From 360a4b971d7a775c0a0a31afe99b68cb70d67355 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Tue, 5 Nov 2024 09:56:13 +0100 Subject: [PATCH 01/72] ci: update retina --- .gitlab/ci/build.yml | 4 ++++ .gitlab/ci/e2e/.env | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 2ec01705ae..537d9bae3d 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -732,6 +732,10 @@ smoke valgrind update cache: start_in: 30 minutes interruptible: false retry: 2 + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts cache: - *cache_build_set diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 5eedba5aff..7bc128c96c 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.54.9 +RETINA_VERSION=0.54.10 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From 9af5f691177fdbe1d20eb78ec6cbd01b2ebacd3b Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 30 Oct 2024 12:10:52 +0100 Subject: [PATCH 02/72] phy: improve srs estimator Minor tweaks as well as EPRE and noise variance estimation. --- .../upper/signal_processors/srs/formatters.h | 7 +- .../srs/srs_estimator_result.h | 8 +- .../srs/srs_estimator_generic_impl.cpp | 102 +++++++++--- .../srs/srs_estimator_test_data.h | 146 +++++++++--------- .../srs/srs_estimator_test_data.tar.gz | 4 +- .../srs/srs_estimator_vectortest.cpp | 3 + 6 files changed, 171 insertions(+), 99 deletions(-) diff --git a/include/srsran/phy/upper/signal_processors/srs/formatters.h b/include/srsran/phy/upper/signal_processors/srs/formatters.h index 4608dc8410..2679aeba63 100644 --- a/include/srsran/phy/upper/signal_processors/srs/formatters.h +++ b/include/srsran/phy/upper/signal_processors/srs/formatters.h @@ -15,6 +15,7 @@ #include "srsran/ran/srs/srs_channel_matrix.h" #include "srsran/ran/srs/srs_channel_matrix_formatters.h" #include "srsran/ran/srs/srs_resource_formatter.h" +#include namespace fmt { @@ -65,7 +66,9 @@ struct formatter { { helper.format_always(ctx, "t_align={:.1}us", config.time_alignment.time_alignment * 1e6); - helper.format_always(ctx, "noise_var={:.3e}", config.noise_variance); + helper.format_always(ctx, "epre={:.3e}dB", config.epre_dB.value_or(std::numeric_limits::quiet_NaN())); + helper.format_always( + ctx, "noise_var={:.3e}", config.noise_variance.value_or(std::numeric_limits::quiet_NaN())); // Get matrix Frobenius norm. float frobenius_norm = config.channel_matrix.frobenius_norm(); @@ -86,4 +89,4 @@ struct formatter { } }; -} // namespace fmt \ No newline at end of file +} // namespace fmt diff --git a/include/srsran/phy/upper/signal_processors/srs/srs_estimator_result.h b/include/srsran/phy/upper/signal_processors/srs/srs_estimator_result.h index 254874a63f..0234b985f5 100644 --- a/include/srsran/phy/upper/signal_processors/srs/srs_estimator_result.h +++ b/include/srsran/phy/upper/signal_processors/srs/srs_estimator_result.h @@ -11,8 +11,8 @@ #pragma once #include "srsran/phy/support/time_alignment_estimator/time_alignment_measurement.h" -#include "srsran/ran/phy_time_unit.h" #include "srsran/ran/srs/srs_channel_matrix.h" +#include namespace srsran { @@ -20,8 +20,10 @@ namespace srsran { struct srs_estimator_result { /// Wideband estimated channel matrix. srs_channel_matrix channel_matrix; - /// Wideband measured noise variance. - float noise_variance; + /// Wideband energy per resource element (EPRE), in decibel. + std::optional epre_dB; + /// Wideband measured noise variance as a linear quantity. + std::optional noise_variance; /// Measured time alignment. time_alignment_measurement time_alignment; }; diff --git a/lib/phy/upper/signal_processors/srs/srs_estimator_generic_impl.cpp b/lib/phy/upper/signal_processors/srs/srs_estimator_generic_impl.cpp index 09a3ccaf84..0a503cff60 100644 --- a/lib/phy/upper/signal_processors/srs/srs_estimator_generic_impl.cpp +++ b/lib/phy/upper/signal_processors/srs/srs_estimator_generic_impl.cpp @@ -19,8 +19,11 @@ #include "srsran/ran/srs/srs_constants.h" #include "srsran/ran/srs/srs_information.h" #include "srsran/srsvec/add.h" +#include "srsran/srsvec/dot_prod.h" #include "srsran/srsvec/mean.h" #include "srsran/srsvec/prod.h" +#include "srsran/srsvec/sc_prod.h" +#include "srsran/srsvec/subtract.h" using namespace srsran; @@ -55,8 +58,8 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re srsran_assert(!config.ports.empty(), "Receive port list is empty."); unsigned nof_rx_ports = config.ports.size(); - unsigned nof_antenna_ports = static_cast(config.resource.nof_antenna_ports); - unsigned nof_symbols = static_cast(config.resource.nof_symbols); + auto nof_antenna_ports = static_cast(config.resource.nof_antenna_ports); + auto nof_symbols = static_cast(config.resource.nof_symbols); unsigned nof_symbols_per_slot = get_nsymb_per_slot(cyclic_prefix::NORMAL); srsran_assert(config.resource.start_symbol.value() + nof_symbols <= nof_symbols_per_slot, "The start symbol index (i.e., {}) plus the number of symbols (i.e., {}) exceeds the number of symbols " @@ -69,7 +72,7 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re subcarrier_spacing scs = to_subcarrier_spacing(config.slot.numerology()); // Extract comb size. - unsigned comb_size = static_cast(config.resource.comb_size); + auto comb_size = static_cast(config.resource.comb_size); srs_information common_info = get_srs_information(config.resource, 0); @@ -91,21 +94,40 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re static_tensor<3, cf_t, max_seq_length * srs_constants::max_nof_rx_ports * srs_constants::max_nof_tx_ports> temp_lse( {sequence_length, nof_rx_ports, nof_antenna_ports}); + // All sequences of pilots. + static_tensor<2, cf_t, max_seq_length * srs_constants::max_nof_tx_ports> all_sequences( + {sequence_length, nof_antenna_ports}); + + // Auxiliary buffer for noise computation. + static_tensor<3, cf_t, 2 * max_seq_length * srs_constants::max_nof_rx_ports> temp_noise( + {sequence_length, 2, nof_rx_ports}); + srsvec::zero(temp_noise.get_data()); + + srs_information info_port0 = get_srs_information(config.resource, /*antenna_port*/ 0); + bool interleaved_pilots = (nof_antenna_ports == 4) && (info_port0.n_cs >= info_port0.n_cs_max / 2); + + float epre = 0; // Iterate transmit ports. for (unsigned i_antenna_port = 0; i_antenna_port != nof_antenna_ports; ++i_antenna_port) { // Obtain SRS information for a given SRS antenna port. srs_information info = get_srs_information(config.resource, i_antenna_port); - // Generate sequence. - static_vector sequence(info.sequence_length); + // Generate sequence and store them in all_sequences. + span sequence = all_sequences.get_view({i_antenna_port}); deps.sequence_generator->generate(sequence, info.sequence_group, info.sequence_number, info.n_cs, info.n_cs_max); + // For the current Tx antenna, keep track of all the LSEs at all Rx ports. + modular_re_buffer_reader port_lse(nof_rx_ports, sequence_length); + // Iterate receive ports. for (unsigned i_rx_port_index = 0; i_rx_port_index != nof_rx_ports; ++i_rx_port_index) { unsigned i_rx_port = config.ports[i_rx_port_index]; // View to the mean LSE for a port combination. span mean_lse = temp_lse.get_view({i_rx_port_index, i_antenna_port}); + // View for noise computation: with interleaved pilots, we need to keep track of two different sets of REs - those + // for odd-indexed ports and those for even-indexed ports. + span noise_help = temp_noise.get_view({(interleaved_pilots) ? i_antenna_port % 2 : 0U, i_rx_port_index}); // Extract sequence for all symbols and average LSE. for (unsigned i_symbol = config.resource.start_symbol.value(), @@ -116,6 +138,13 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re static_vector rx_sequence(info.sequence_length); grid.get(rx_sequence, i_rx_port, i_symbol, info.mapping_initial_subcarrier, info.comb_size); + // Since the same SRS sequence is sent over all symbols, it makes sense to average out the noise. When pilots + // are interleaved, we need to keep track of two different sets of REs. + if ((i_antenna_port == 0) || (interleaved_pilots && (i_antenna_port == 1))) { + srsvec::add(noise_help, rx_sequence, noise_help); + epre += srsvec::average_power(rx_sequence); + } + // Temporary LSE. span lse = rx_sequence; @@ -138,23 +167,25 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re srsvec::sc_prod(mean_lse, 1.0 / static_cast(nof_symbols), mean_lse); } - // Estimate TA. - time_alignment_measurement ta_meas = deps.ta_estimator->estimate(mean_lse, info.comb_size, scs, max_ta); - - // Combine time alignment measurement. - result.time_alignment.time_alignment += ta_meas.time_alignment; - result.time_alignment.min = std::max(result.time_alignment.min, ta_meas.min); - result.time_alignment.max = std::min(result.time_alignment.max, ta_meas.max); - result.time_alignment.resolution = std::max(result.time_alignment.resolution, ta_meas.resolution); + port_lse.set_slice(i_rx_port_index, mean_lse); } + // Estimate TA. + time_alignment_measurement ta_meas = deps.ta_estimator->estimate(port_lse, info.comb_size, scs, max_ta); + + // Combine time alignment measurements. + result.time_alignment.time_alignment += ta_meas.time_alignment; + result.time_alignment.min = std::max(result.time_alignment.min, ta_meas.min); + result.time_alignment.max = std::min(result.time_alignment.max, ta_meas.max); + result.time_alignment.resolution = std::max(result.time_alignment.resolution, ta_meas.resolution); } // Average time alignment across all paths. - result.time_alignment.time_alignment /= nof_antenna_ports * nof_rx_ports; + result.time_alignment.time_alignment /= nof_antenna_ports; + float noise_var = 0; // Compensate time alignment and estimate channel coefficients. - for (unsigned i_antenna_port = 0; i_antenna_port != nof_antenna_ports; ++i_antenna_port) { - for (unsigned i_rx_port = 0; i_rx_port != nof_rx_ports; ++i_rx_port) { + for (unsigned i_rx_port = 0; i_rx_port != nof_rx_ports; ++i_rx_port) { + for (unsigned i_antenna_port = 0; i_antenna_port != nof_antenna_ports; ++i_antenna_port) { // View to the mean LSE for a port combination. span mean_lse = temp_lse.get_view({i_rx_port, i_antenna_port}); @@ -162,7 +193,7 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re srs_information info = get_srs_information(config.resource, i_antenna_port); // Calculate subcarrier phase shift in radians. - float phase_shift_subcarrier = + auto phase_shift_subcarrier = static_cast(TWOPI * result.time_alignment.time_alignment * scs_to_khz(scs) * 1000 * comb_size); // Calculate the initial phase shift in radians. @@ -174,11 +205,44 @@ srs_estimator_result srs_estimator_generic_impl::estimate(const resource_grid_re // Calculate channel wideband coefficient. cf_t coefficient = srsvec::mean(mean_lse); result.channel_matrix.set_coefficient(coefficient, i_rx_port, i_antenna_port); + + // View for noise computation: with interleaved pilots, we need to keep track of two different sets of REs - those + // for odd-indexed ports and those for even-indexed ports. + span noise_help = temp_noise.get_view({(interleaved_pilots) ? i_antenna_port % 2 : 0U, i_rx_port}); + + if ((i_antenna_port == 0) || (interleaved_pilots && (i_antenna_port == 1))) { + compensate_phase_shift(noise_help, phase_shift_subcarrier, phase_shift_offset); + } + + // We recover the signal by multiplying the SRS sequence by the channel coefficient and we remove it from + // noise_help. Recall that the latter contains the contribution of all symbols, so the reconstructed symbol must + // also be counted nof_symbols times. + static_vector recovered_signal(noise_help.size()); + srsvec::sc_prod( + all_sequences.get_view({i_antenna_port}), static_cast(nof_symbols) * coefficient, recovered_signal); + srsvec::subtract(noise_help, recovered_signal, noise_help); + } + span noise_help = temp_noise.get_view({0U, i_rx_port}); + noise_var += srsvec::average_power(noise_help) * noise_help.size(); + + if (interleaved_pilots) { + noise_help = temp_noise.get_view({1U, i_rx_port}); + noise_var += srsvec::average_power(noise_help) * noise_help.size(); } } - // Set noise variance to zero. - result.noise_variance = near_zero; + // At this point, noise_var contains the sum of all the squared errors between the received signal and the + // reconstructed one. For each Rx port, the number of degrees of freedom used to estimate the channel coefficients is + // usually equal nof_antenna_ports, but when pilots are interleaved, in which case it's 2. Also, when interleaving + // pilots, we look at double the samples. + unsigned nof_estimates = (interleaved_pilots ? 2 : nof_antenna_ports); + unsigned correction_factor = (interleaved_pilots ? 2 : 1); + noise_var /= static_cast((nof_symbols * sequence_length - nof_estimates) * correction_factor * nof_rx_ports); + epre /= static_cast(nof_symbols * correction_factor * nof_rx_ports); + + // Set noise variance and EPRE. + result.noise_variance = noise_var; + result.epre_dB = convert_power_to_dB(epre); return result; } diff --git a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h index f2c815ba21..d64bdb3da6 100644 --- a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h +++ b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 12-04-2024 (seed 0): +// This file was generated using the following MATLAB class on 05-11-2024 (seed 0): // + "srsSRSEstimatorUnittest.m" #include "srsran/phy/upper/signal_processors/srs/srs_estimator_configuration.h" @@ -31,78 +31,78 @@ struct test_case_t { static const std::vector srs_estimator_test_data = { // clang-format off - {{{{0, 130, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 12, 17, 647, 2, srs_resource_configuration::comb_size_enum(2), 1, 1, 66, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.964003, -0.265891), cf_t(-0.995781, 0.091758)}}, 1, 2}, 0, {0.000000313}}}, {"test_data/srs_estimator_test_input0.dat"}}, - {{{{0, 937, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 11, 2, 982, 3, srs_resource_configuration::comb_size_enum(4), 3, 9, 50, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.779357, 0.626580), cf_t(-0.559597, -0.828765)}}, 1, 2}, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input1.dat"}}, - {{{{0, 283, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 99, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 25, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.097340, -0.995251), cf_t(0.386322, 0.922364), cf_t(0.280197, -0.959943), cf_t(-0.997933, 0.064268)}}, 2, 2}, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input2.dat"}}, - {{{{0, 772, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 3, 10, 696, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 39, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.163803, 0.986493), cf_t(-0.032008, 0.999488), cf_t(0.007961, -0.999968), cf_t(-0.999300, -0.037421)}}, 2, 2}, 0, {0.000000207}}}, {"test_data/srs_estimator_test_input3.dat"}}, - {{{{0, 560, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 58, 152, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 38, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.888557, 0.458767), cf_t(-0.981336, -0.192301), cf_t(0.915268, -0.402845), cf_t(-0.907949, -0.419080), cf_t(0.943095, 0.332524), cf_t(0.182239, -0.983254), cf_t(0.684977, 0.728565), cf_t(-0.981563, 0.191141)}}, 4, 2}, 0, {-0.000000508}}}, {"test_data/srs_estimator_test_input4.dat"}}, - {{{{0, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 38, 541, 1, srs_resource_configuration::comb_size_enum(4), 2, 8, 30, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.864488, 0.502653), cf_t(0.855377, -0.518005), cf_t(0.458558, -0.888664), cf_t(0.999705, -0.024284), cf_t(0.131708, 0.991289), cf_t(0.575632, 0.817709), cf_t(-0.971121, -0.238589), cf_t(0.881772, 0.471677)}}, 4, 2}, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input5.dat"}}, - {{{{0, 4, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 5, 836, 1, srs_resource_configuration::comb_size_enum(2), 0, 5, 61, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.415250, 0.909707), cf_t(-0.086618, 0.996242)}}, 1, 2}, 0, {-0.000000369}}}, {"test_data/srs_estimator_test_input6.dat"}}, - {{{{0, 593, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 39, 148, 1, srs_resource_configuration::comb_size_enum(4), 2, 0, 16, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.714536, 0.699599), cf_t(0.403437, 0.915008)}}, 1, 2}, 0, {-0.000000271}}}, {"test_data/srs_estimator_test_input7.dat"}}, - {{{{0, 924, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 12, 15, 502, 1, srs_resource_configuration::comb_size_enum(2), 1, 0, 11, 0, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.592272, -0.805738), cf_t(-0.599184, -0.800612), cf_t(-0.114589, -0.993413), cf_t(-0.952834, 0.303492)}}, 2, 2}, 0, {0.000000049}}}, {"test_data/srs_estimator_test_input8.dat"}}, - {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 8, 40, 187, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.919884, 0.392191), cf_t(-0.346703, 0.937975), cf_t(-0.944618, 0.328172), cf_t(-0.998571, -0.053436)}}, 2, 2}, 0, {0.000000011}}}, {"test_data/srs_estimator_test_input9.dat"}}, - {{{{0, 659, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 22, 831, 3, srs_resource_configuration::comb_size_enum(2), 1, 7, 39, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.262404, 0.964958), cf_t(-0.983358, 0.181679), cf_t(0.558486, -0.829514), cf_t(0.150711, 0.988578), cf_t(-0.316455, 0.948607), cf_t(0.122290, 0.992494), cf_t(0.340131, 0.940378), cf_t(0.477850, 0.878441)}}, 4, 2}, 0, {-0.000000284}}}, {"test_data/srs_estimator_test_input10.dat"}}, - {{{{0, 945, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 62, 189, 1, srs_resource_configuration::comb_size_enum(4), 0, 4, 40, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.076653, 0.997058), cf_t(-0.241284, -0.970455), cf_t(0.739979, 0.672630), cf_t(-0.418821, 0.908069), cf_t(-0.798388, -0.602143), cf_t(0.176590, 0.984285), cf_t(-0.289087, 0.957303), cf_t(-0.888618, 0.458649)}}, 4, 2}, 0, {0.000000008}}}, {"test_data/srs_estimator_test_input11.dat"}}, - {{{{0, 820, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 14, 951, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 24, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.997150, -0.075440), cf_t(0.972018, 0.234904)}}, 1, 2}, 0, {0.000000401}}}, {"test_data/srs_estimator_test_input12.dat"}}, - {{{{0, 101, 9, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 2, 8, 343, 2, srs_resource_configuration::comb_size_enum(4), 0, 5, 52, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.217916, -0.975968), cf_t(0.822535, -0.568714)}}, 1, 2}, 0, {0.000000407}}}, {"test_data/srs_estimator_test_input13.dat"}}, - {{{{0, 202, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 11, 761, 0, srs_resource_configuration::comb_size_enum(2), 1, 5, 11, 6, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.991042, -0.133553), cf_t(-0.999996, -0.002963), cf_t(-0.232257, -0.972654), cf_t(-0.983546, 0.180660)}}, 2, 2}, 0, {-0.000000459}}}, {"test_data/srs_estimator_test_input14.dat"}}, - {{{{0, 73, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 5, 52, 99, 2, srs_resource_configuration::comb_size_enum(4), 0, 6, 66, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.592900, -0.805276), cf_t(-0.958159, 0.286237), cf_t(0.310992, -0.950413), cf_t(-0.911123, 0.412136)}}, 2, 2}, 0, {0.000000339}}}, {"test_data/srs_estimator_test_input15.dat"}}, - {{{{0, 177, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 4, 3, 851, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 42, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.260745, 0.965408), cf_t(0.995269, 0.097155), cf_t(0.497267, 0.867597), cf_t(-0.695505, 0.718521), cf_t(-0.909196, 0.416369), cf_t(0.994991, -0.099963), cf_t(0.785448, 0.618928), cf_t(0.320239, 0.947337)}}, 4, 2}, 0, {-0.000000011}}}, {"test_data/srs_estimator_test_input16.dat"}}, - {{{{0, 942, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 27, 755, 2, srs_resource_configuration::comb_size_enum(4), 3, 11, 20, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.302444, -0.953167), cf_t(-0.969934, -0.243370), cf_t(-0.500755, -0.865589), cf_t(0.693588, 0.720372), cf_t(-0.501783, -0.864994), cf_t(-0.320316, -0.947311), cf_t(0.436367, 0.899769), cf_t(0.999983, -0.005778)}}, 4, 2}, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input17.dat"}}, - {{{{0, 903, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 29, 195, 3, srs_resource_configuration::comb_size_enum(2), 0, 7, 25, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.362722, 0.931897), cf_t(-0.900099, 0.435686), cf_t(-0.993627, 0.112719), cf_t(0.726333, 0.687343)}}, 1, 4}, 0, {0.000000093}}}, {"test_data/srs_estimator_test_input18.dat"}}, - {{{{0, 596, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 16, 297, 3, srs_resource_configuration::comb_size_enum(4), 3, 4, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.779372, 0.626561), cf_t(0.831673, -0.555266), cf_t(0.727478, -0.686132), cf_t(0.413006, -0.910728)}}, 1, 4}, 0, {-0.000000249}}}, {"test_data/srs_estimator_test_input19.dat"}}, - {{{{0, 435, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 2, 165, 0, srs_resource_configuration::comb_size_enum(2), 0, 7, 27, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.425673, -0.904877), cf_t(-0.454806, 0.890591), cf_t(-0.197500, -0.980303), cf_t(0.787726, 0.616026), cf_t(0.980662, -0.195711), cf_t(-0.766660, -0.642054), cf_t(-0.980682, -0.195607), cf_t(0.179984, -0.983670)}}, 2, 4}, 0, {-0.000000080}}}, {"test_data/srs_estimator_test_input20.dat"}}, - {{{{0, 157, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 29, 450, 3, srs_resource_configuration::comb_size_enum(4), 2, 7, 65, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.058356, 0.998296), cf_t(-0.337907, -0.941179), cf_t(-0.447696, -0.894186), cf_t(0.910125, 0.414334), cf_t(-0.242993, 0.970028), cf_t(-0.030093, 0.999547), cf_t(-0.471767, -0.881723), cf_t(0.162389, 0.986727)}}, 2, 4}, 0, {0.000000175}}}, {"test_data/srs_estimator_test_input21.dat"}}, - {{{{0, 799, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 24, 6, 3, srs_resource_configuration::comb_size_enum(2), 0, 5, 31, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.126329, -0.991988), cf_t(0.974860, 0.222818), cf_t(0.573868, 0.818948), cf_t(-0.072652, -0.997357), cf_t(-0.439780, 0.898105), cf_t(0.449088, 0.893487), cf_t(-0.541779, 0.840521), cf_t(0.044912, 0.998991), cf_t(0.216544, -0.976273), cf_t(-0.176520, -0.984297), cf_t(-0.780865, -0.624699), cf_t(0.868396, -0.495872), cf_t(-0.983849, 0.178998), cf_t(-0.986156, 0.165823), cf_t(0.357907, 0.933757), cf_t(-0.119481, 0.992836)}}, 4, 4}, 0, {0.000000277}}}, {"test_data/srs_estimator_test_input22.dat"}}, - {{{{0, 93, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 8, 27, 699, 2, srs_resource_configuration::comb_size_enum(4), 2, 7, 64, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.255166, 0.966897), cf_t(-0.781200, -0.624281), cf_t(0.127113, -0.991888), cf_t(0.546021, -0.837771), cf_t(-0.253059, -0.967451), cf_t(-0.951324, 0.308194), cf_t(-0.588893, 0.808211), cf_t(0.497732, -0.867331), cf_t(0.086408, 0.996260), cf_t(-0.966561, 0.256438), cf_t(-0.525123, -0.851026), cf_t(-0.040459, 0.999181), cf_t(0.731560, 0.681777), cf_t(-0.525470, -0.850812), cf_t(-0.864425, 0.502762), cf_t(-0.756472, -0.654026)}}, 4, 4}, 0, {0.000000086}}}, {"test_data/srs_estimator_test_input23.dat"}}, - {{{{0, 271, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 4, 41, 122, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 36, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.180918, -0.983498), cf_t(-0.990028, -0.140872), cf_t(0.999218, -0.039545), cf_t(0.195542, 0.980695)}}, 1, 4}, 0, {-0.000000411}}}, {"test_data/srs_estimator_test_input24.dat"}}, - {{{{0, 414, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 40, 374, 3, srs_resource_configuration::comb_size_enum(4), 3, 2, 9, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.331241, -0.943546), cf_t(0.831225, 0.555936), cf_t(-0.987288, -0.158944), cf_t(-0.981880, -0.189505)}}, 1, 4}, 0, {0.000000376}}}, {"test_data/srs_estimator_test_input25.dat"}}, - {{{{0, 687, 4, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 9, 1, 532, 1, srs_resource_configuration::comb_size_enum(2), 0, 2, 55, 4, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.904617, 0.426226), cf_t(-0.797004, 0.603974), cf_t(0.761511, -0.648153), cf_t(0.359428, -0.933173), cf_t(-0.775230, 0.631679), cf_t(0.031895, -0.999491), cf_t(0.119811, -0.992797), cf_t(-0.717669, 0.696384)}}, 2, 4}, 0, {-0.000000296}}}, {"test_data/srs_estimator_test_input26.dat"}}, - {{{{0, 335, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 49, 449, 0, srs_resource_configuration::comb_size_enum(4), 3, 6, 60, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.850908, -0.525314), cf_t(-0.008132, -0.999967), cf_t(0.563370, 0.826205), cf_t(0.457256, -0.889335), cf_t(0.309837, 0.950790), cf_t(0.248465, -0.968641), cf_t(-0.833922, 0.551883), cf_t(-0.417371, 0.908736)}}, 2, 4}, 0, {0.000000035}}}, {"test_data/srs_estimator_test_input27.dat"}}, - {{{{0, 139, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 31, 507, 0, srs_resource_configuration::comb_size_enum(2), 0, 6, 63, 2, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.328863, -0.944377), cf_t(0.997574, -0.069614), cf_t(0.998007, -0.063103), cf_t(0.138768, 0.990325), cf_t(-0.867724, -0.497046), cf_t(0.999995, 0.003282), cf_t(-0.984914, -0.173044), cf_t(-0.999928, 0.011974), cf_t(0.399437, -0.916761), cf_t(0.663376, -0.748286), cf_t(-0.991735, 0.128304), cf_t(0.812154, -0.583443), cf_t(0.724713, -0.689050), cf_t(-0.760135, -0.649766), cf_t(0.317059, -0.948406), cf_t(-0.891971, -0.452093)}}, 4, 4}, 0, {0.000000360}}}, {"test_data/srs_estimator_test_input28.dat"}}, - {{{{0, 252, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 42, 85, 2, srs_resource_configuration::comb_size_enum(4), 3, 9, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.900263, -0.435346), cf_t(0.650454, -0.759545), cf_t(-0.946509, -0.322677), cf_t(-0.649025, 0.760767), cf_t(-0.876033, -0.482251), cf_t(-0.995136, 0.098508), cf_t(-0.685081, -0.728467), cf_t(0.951960, 0.306223), cf_t(0.994312, 0.106505), cf_t(0.561333, -0.827590), cf_t(0.979866, 0.199655), cf_t(-0.997853, 0.065487), cf_t(0.725261, 0.688474), cf_t(0.252309, 0.967647), cf_t(-0.751301, -0.659960), cf_t(0.353414, 0.935467)}}, 4, 4}, 0, {-0.000000393}}}, {"test_data/srs_estimator_test_input29.dat"}}, - {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 34, 650, 2, srs_resource_configuration::comb_size_enum(2), 0, 5, 8, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.998165, 0.060550), cf_t(0.602920, -0.797801), cf_t(0.702325, -0.711856), cf_t(-0.127168, 0.991881)}}, 1, 4}, 0, {-0.000000304}}}, {"test_data/srs_estimator_test_input30.dat"}}, - {{{{0, 427, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 2, 6, 970, 0, srs_resource_configuration::comb_size_enum(4), 0, 6, 3, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.908015, -0.418937), cf_t(-0.133671, -0.991026), cf_t(-0.076319, -0.997083), cf_t(0.921690, 0.387928)}}, 1, 4}, 0, {0.000000375}}}, {"test_data/srs_estimator_test_input31.dat"}}, - {{{{0, 879, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 25, 525, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.497838, 0.867270), cf_t(0.547481, -0.836818), cf_t(-0.978669, 0.205443), cf_t(-0.931997, -0.362466), cf_t(-0.596905, -0.802312), cf_t(0.608429, -0.793608), cf_t(0.987463, 0.157850), cf_t(-0.576953, 0.816777)}}, 2, 4}, 0, {-0.000000056}}}, {"test_data/srs_estimator_test_input32.dat"}}, - {{{{0, 678, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 3, 63, 920, 2, srs_resource_configuration::comb_size_enum(4), 2, 3, 28, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.975697, 0.219125), cf_t(0.436455, 0.899726), cf_t(0.087583, -0.996157), cf_t(-0.635655, 0.771973), cf_t(0.415542, -0.909574), cf_t(0.937199, 0.348796), cf_t(0.808198, 0.588911), cf_t(-0.990560, -0.137079)}}, 2, 4}, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input33.dat"}}, - {{{{0, 926, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 6, 479, 2, srs_resource_configuration::comb_size_enum(2), 1, 2, 40, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.308640, 0.951179), cf_t(0.900903, 0.434021), cf_t(0.996519, 0.083364), cf_t(-0.352692, 0.935739), cf_t(0.665435, 0.746455), cf_t(0.047191, 0.998886), cf_t(0.798519, -0.601970), cf_t(-0.962127, 0.272603), cf_t(0.232825, 0.972519), cf_t(0.943503, 0.331364), cf_t(0.328917, 0.944359), cf_t(0.802807, 0.596239), cf_t(0.789930, -0.613197), cf_t(-0.933705, 0.358043), cf_t(0.832792, 0.553586), cf_t(0.999580, -0.028963)}}, 4, 4}, 0, {-0.000000175}}}, {"test_data/srs_estimator_test_input34.dat"}}, - {{{{0, 305, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 40, 517, 0, srs_resource_configuration::comb_size_enum(4), 0, 10, 36, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.773890, 0.633320), cf_t(-0.023161, -0.999732), cf_t(-0.796018, -0.605273), cf_t(0.195873, -0.980629), cf_t(0.458513, -0.888688), cf_t(0.997892, 0.064901), cf_t(-0.986581, -0.163272), cf_t(-0.236358, 0.971666), cf_t(-0.525697, 0.850672), cf_t(0.954026, 0.299724), cf_t(-0.127144, -0.991884), cf_t(-0.353287, -0.935515), cf_t(-0.272789, 0.962074), cf_t(-0.493186, -0.869924), cf_t(-0.265367, -0.964148), cf_t(-0.937275, -0.348591)}}, 4, 4}, 0, {-0.000000108}}}, {"test_data/srs_estimator_test_input35.dat"}}, - {{{{1, 345, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 8, 7, 759, 0, srs_resource_configuration::comb_size_enum(2), 1, 7, 50, 7, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.866489, -0.499197), cf_t(-0.062588, -0.998039)}}, 1, 2}, 0, {-0.000000138}}}, {"test_data/srs_estimator_test_input36.dat"}}, - {{{{1, 887, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 43, 375, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 5, 4, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.137379, -0.990519), cf_t(0.274919, 0.961467)}}, 1, 2}, 0, {-0.000000058}}}, {"test_data/srs_estimator_test_input37.dat"}}, - {{{{1, 657, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 6, 6, 155, 1, srs_resource_configuration::comb_size_enum(2), 0, 1, 27, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.790747, 0.612143), cf_t(0.214634, -0.976695), cf_t(0.761287, 0.648415), cf_t(-0.258234, 0.966082)}}, 2, 2}, 0, {0.000000054}}}, {"test_data/srs_estimator_test_input38.dat"}}, - {{{{1, 711, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 10, 7, 443, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.118837, -0.992914), cf_t(-0.143630, 0.989631), cf_t(-0.794016, 0.607897), cf_t(0.972758, 0.231824)}}, 2, 2}, 0, {0.000000090}}}, {"test_data/srs_estimator_test_input39.dat"}}, - {{{{1, 624, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 323, 0, srs_resource_configuration::comb_size_enum(2), 0, 0, 28, 8, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.559101, -0.829099), cf_t(-0.980835, -0.194839), cf_t(-0.676415, -0.736521), cf_t(0.664589, 0.747209), cf_t(-0.169313, -0.985562), cf_t(0.775226, 0.631684), cf_t(0.700412, 0.713739), cf_t(0.814178, 0.580616)}}, 4, 2}, 0, {-0.000000186}}}, {"test_data/srs_estimator_test_input40.dat"}}, - {{{{1, 325, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 57, 222, 2, srs_resource_configuration::comb_size_enum(4), 2, 2, 5, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.856881, -0.515515), cf_t(-0.934801, -0.355173), cf_t(0.502518, 0.864567), cf_t(0.997128, -0.075736), cf_t(-0.268626, -0.963245), cf_t(-0.388070, 0.921630), cf_t(-0.718138, -0.695900), cf_t(0.479373, 0.877611)}}, 4, 2}, 0, {-0.000000126}}}, {"test_data/srs_estimator_test_input41.dat"}}, - {{{{1, 700, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 43, 1006, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 22, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.304382, 0.952550), cf_t(-0.955964, 0.293485)}}, 1, 2}, 0, {-0.000000040}}}, {"test_data/srs_estimator_test_input42.dat"}}, - {{{{1, 760, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 1, 439, 1, srs_resource_configuration::comb_size_enum(4), 1, 11, 63, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.965195, 0.261531), cf_t(0.059790, 0.998211)}}, 1, 2}, 0, {0.000000137}}}, {"test_data/srs_estimator_test_input43.dat"}}, - {{{{1, 761, 7, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 1, 13, 697, 0, srs_resource_configuration::comb_size_enum(2), 1, 1, 45, 5, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.787798, -0.615934), cf_t(-0.292825, -0.956166), cf_t(-0.994593, -0.103851), cf_t(0.569387, 0.822070)}}, 2, 2}, 0, {0.000000236}}}, {"test_data/srs_estimator_test_input44.dat"}}, - {{{{1, 37, 5, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 33, 766, 1, srs_resource_configuration::comb_size_enum(4), 2, 4, 12, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.033839, 0.999427), cf_t(0.887198, -0.461389), cf_t(0.991687, 0.128672), cf_t(-0.568821, -0.822461)}}, 2, 2}, 0, {0.000000225}}}, {"test_data/srs_estimator_test_input45.dat"}}, - {{{{1, 813, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 32, 450, 2, srs_resource_configuration::comb_size_enum(2), 1, 0, 58, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.679083, -0.734061), cf_t(0.999823, -0.018828), cf_t(-0.575257, -0.817973), cf_t(-0.759366, 0.650663), cf_t(-0.613273, 0.789871), cf_t(0.161574, 0.986861), cf_t(-0.790191, -0.612861), cf_t(0.626775, 0.779200)}}, 4, 2}, 0, {-0.000000247}}}, {"test_data/srs_estimator_test_input46.dat"}}, - {{{{1, 743, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 36, 861, 0, srs_resource_configuration::comb_size_enum(4), 3, 11, 15, 8, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.700697, 0.713459), cf_t(-0.636860, -0.770980), cf_t(0.960204, 0.279299), cf_t(-0.574685, 0.818375), cf_t(0.852639, 0.522500), cf_t(0.422269, 0.906471), cf_t(-0.167759, -0.985828), cf_t(-0.532550, -0.846398)}}, 4, 2}, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input47.dat"}}, - {{{{1, 932, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 8, 24, 763, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 16, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.954188, 0.299208), cf_t(0.139577, 0.990211)}}, 1, 2}, 0, {0.000000159}}}, {"test_data/srs_estimator_test_input48.dat"}}, - {{{{1, 548, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 4, 821, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 36, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.751603, -0.659616), cf_t(0.805326, -0.592832)}}, 1, 2}, 0, {0.000000066}}}, {"test_data/srs_estimator_test_input49.dat"}}, - {{{{1, 186, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 49, 109, 1, srs_resource_configuration::comb_size_enum(2), 1, 3, 46, 10, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.984732, -0.174075), cf_t(-0.799163, -0.601114), cf_t(-0.849650, 0.527346), cf_t(0.003268, -0.999995)}}, 2, 2}, 0, {0.000000044}}}, {"test_data/srs_estimator_test_input50.dat"}}, - {{{{1, 524, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 22, 736, 3, srs_resource_configuration::comb_size_enum(4), 1, 5, 28, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.201359, 0.979517), cf_t(-0.361775, 0.932265), cf_t(0.704193, 0.710009), cf_t(-0.149577, -0.988750)}}, 2, 2}, 0, {0.000000147}}}, {"test_data/srs_estimator_test_input51.dat"}}, - {{{{1, 863, 6, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 10, 24, 789, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 45, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.990017, 0.140950), cf_t(0.085066, 0.996375), cf_t(0.479789, -0.877384), cf_t(0.916448, -0.400154), cf_t(-0.712787, -0.701381), cf_t(0.442061, 0.896985), cf_t(0.106122, -0.994353), cf_t(0.778900, 0.627148)}}, 4, 2}, 0, {-0.000000166}}}, {"test_data/srs_estimator_test_input52.dat"}}, - {{{{1, 197, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 9, 35, 101, 3, srs_resource_configuration::comb_size_enum(4), 1, 4, 14, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.997966, -0.063747), cf_t(-0.689460, -0.724324), cf_t(-0.773925, 0.633277), cf_t(-0.999968, -0.008061), cf_t(0.831868, -0.554973), cf_t(0.803315, 0.595555), cf_t(0.941694, 0.336470), cf_t(-0.909379, 0.415969)}}, 4, 2}, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input53.dat"}}, - {{{{1, 915, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 62, 399, 2, srs_resource_configuration::comb_size_enum(2), 0, 4, 51, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.857206, 0.514974), cf_t(-0.998844, 0.048079), cf_t(-0.340255, -0.940333), cf_t(0.985361, -0.170481)}}, 1, 4}, 0, {-0.000000090}}}, {"test_data/srs_estimator_test_input54.dat"}}, - {{{{1, 977, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 18, 365, 0, srs_resource_configuration::comb_size_enum(4), 2, 7, 44, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.955692, 0.294369), cf_t(-0.581591, 0.813481), cf_t(-0.953626, 0.300995), cf_t(0.057114, 0.998368)}}, 1, 4}, 0, {0.000000112}}}, {"test_data/srs_estimator_test_input55.dat"}}, - {{{{1, 748, 8, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 37, 856, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 59, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.603640, 0.797257), cf_t(0.985600, -0.169091), cf_t(-0.949970, 0.312340), cf_t(0.372754, 0.927930), cf_t(0.973861, -0.227146), cf_t(-0.497530, -0.867447), cf_t(0.964892, 0.262647), cf_t(-0.856102, -0.516806)}}, 2, 4}, 0, {0.000000091}}}, {"test_data/srs_estimator_test_input56.dat"}}, - {{{{1, 830, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 41, 85, 0, srs_resource_configuration::comb_size_enum(4), 1, 3, 17, 10, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.490896, 0.871218), cf_t(0.746581, -0.665294), cf_t(0.576372, 0.817188), cf_t(0.829621, 0.558328), cf_t(-0.577612, 0.816311), cf_t(0.904936, -0.425548), cf_t(0.721796, 0.692106), cf_t(-0.805382, 0.592756)}}, 2, 4}, 0, {-0.000000236}}}, {"test_data/srs_estimator_test_input57.dat"}}, - {{{{1, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 7, 37, 702, 0, srs_resource_configuration::comb_size_enum(2), 1, 3, 36, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.995429, -0.095508), cf_t(-0.983015, 0.183524), cf_t(-0.999702, -0.024425), cf_t(-0.988245, 0.152878), cf_t(-0.213983, -0.976837), cf_t(-0.928117, -0.372289), cf_t(-0.603883, -0.797073), cf_t(-0.649253, 0.760572), cf_t(0.530349, -0.847779), cf_t(-0.119668, 0.992814), cf_t(-0.354918, 0.934897), cf_t(0.237191, -0.971463), cf_t(-0.913359, 0.407154), cf_t(-0.006167, -0.999981), cf_t(0.643578, 0.765381), cf_t(0.189207, -0.981937)}}, 4, 4}, 0, {0.000000088}}}, {"test_data/srs_estimator_test_input58.dat"}}, - {{{{1, 573, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 18, 961, 3, srs_resource_configuration::comb_size_enum(4), 3, 10, 64, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.952678, -0.303982), cf_t(-0.944096, 0.329672), cf_t(0.922999, -0.384803), cf_t(-0.833438, -0.552613), cf_t(-0.135383, -0.990793), cf_t(-0.606423, -0.795142), cf_t(0.479179, -0.877717), cf_t(0.696150, -0.717896), cf_t(-0.885937, -0.463806), cf_t(-0.991139, -0.132828), cf_t(0.583127, -0.812381), cf_t(0.913975, -0.405771), cf_t(0.986831, 0.161753), cf_t(-0.695067, 0.718945), cf_t(-0.696067, 0.717977), cf_t(-0.490187, -0.871617)}}, 4, 4}, 0, {-0.000000153}}}, {"test_data/srs_estimator_test_input59.dat"}}, - {{{{1, 416, 6, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 18, 956, 2, srs_resource_configuration::comb_size_enum(2), 1, 4, 18, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.207893, -0.978152), cf_t(-0.208225, 0.978081), cf_t(0.794749, -0.606938), cf_t(0.462807, -0.886459)}}, 1, 4}, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input60.dat"}}, - {{{{1, 854, 4, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 29, 588, 2, srs_resource_configuration::comb_size_enum(4), 3, 0, 45, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.926287, 0.376820), cf_t(-0.924648, 0.380824), cf_t(0.741587, 0.670857), cf_t(0.395312, -0.918547)}}, 1, 4}, 0, {-0.000000091}}}, {"test_data/srs_estimator_test_input61.dat"}}, - {{{{1, 384, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 8, 575, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 9, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.997308, 0.073328), cf_t(-0.679303, -0.733858), cf_t(-0.968731, -0.248112), cf_t(0.634128, -0.773228), cf_t(0.825762, 0.564019), cf_t(0.986911, -0.161263), cf_t(0.605359, 0.795953), cf_t(-0.902572, -0.430540)}}, 2, 4}, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input62.dat"}}, - {{{{1, 338, 5, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 56, 503, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 41, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.418036, -0.908430), cf_t(-0.053898, 0.998546), cf_t(0.755220, -0.655471), cf_t(0.801062, -0.598581), cf_t(0.907779, -0.419449), cf_t(-0.832822, -0.553541), cf_t(0.363536, 0.931580), cf_t(-0.999709, -0.024126)}}, 2, 4}, 0, {0.000000059}}}, {"test_data/srs_estimator_test_input63.dat"}}, - {{{{1, 206, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 39, 438, 2, srs_resource_configuration::comb_size_enum(2), 1, 6, 37, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.554288, 0.832325), cf_t(0.515896, -0.856651), cf_t(-0.755858, 0.654736), cf_t(-0.346102, -0.938197), cf_t(-0.924943, -0.380105), cf_t(-0.116682, -0.993169), cf_t(0.159876, -0.987137), cf_t(0.941334, -0.337476), cf_t(-0.339901, -0.940461), cf_t(-0.637574, 0.770389), cf_t(-0.098667, -0.995121), cf_t(0.213435, -0.976957), cf_t(-0.895121, 0.445823), cf_t(-0.958901, 0.283740), cf_t(-0.905569, 0.424199), cf_t(-0.275539, -0.961290)}}, 4, 4}, 0, {-0.000000203}}}, {"test_data/srs_estimator_test_input64.dat"}}, - {{{{1, 470, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 0, 1, 234, 3, srs_resource_configuration::comb_size_enum(4), 0, 6, 14, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.900458, -0.434943), cf_t(0.938785, 0.344502), cf_t(-0.918192, 0.396135), cf_t(0.655961, -0.754795), cf_t(0.719484, 0.694509), cf_t(0.937989, 0.346665), cf_t(0.493938, -0.869497), cf_t(0.817434, 0.576022), cf_t(-0.475320, -0.879813), cf_t(0.575002, 0.818152), cf_t(-0.740095, -0.672502), cf_t(0.837707, -0.546120), cf_t(-0.810545, -0.585677), cf_t(0.992410, 0.122971), cf_t(-0.992012, -0.126140), cf_t(0.778396, 0.627773)}}, 4, 4}, 0, {0.000000009}}}, {"test_data/srs_estimator_test_input65.dat"}}, - {{{{1, 4, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 63, 869, 2, srs_resource_configuration::comb_size_enum(2), 0, 6, 39, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.080884, -0.996724), cf_t(0.867188, 0.497982), cf_t(-0.527332, -0.849659), cf_t(-0.994315, -0.106480)}}, 1, 4}, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input66.dat"}}, - {{{{1, 451, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 10, 53, 671, 2, srs_resource_configuration::comb_size_enum(4), 2, 4, 16, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.879545, -0.475815), cf_t(0.670159, -0.742218), cf_t(-0.833304, 0.552815), cf_t(0.759936, 0.649998)}}, 1, 4}, 0, {-0.000000029}}}, {"test_data/srs_estimator_test_input67.dat"}}, - {{{{1, 853, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 4, 8, 399, 1, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 3, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.890602, 0.454783), cf_t(0.040369, 0.999185), cf_t(0.732369, 0.680908), cf_t(0.218573, -0.975821), cf_t(-0.999520, 0.030990), cf_t(0.893589, 0.448886), cf_t(-0.270490, -0.962723), cf_t(-0.785836, 0.618435)}}, 2, 4}, 0, {-0.000000259}}}, {"test_data/srs_estimator_test_input68.dat"}}, - {{{{1, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 1, 8, 274, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 32, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.711585, 0.702600), cf_t(-0.921034, 0.389482), cf_t(-0.988858, -0.148859), cf_t(0.460400, 0.887712), cf_t(-0.093311, 0.995637), cf_t(0.986576, 0.163301), cf_t(0.909174, 0.416417), cf_t(0.959728, -0.280932)}}, 2, 4}, 0, {-0.000000036}}}, {"test_data/srs_estimator_test_input69.dat"}}, - {{{{1, 7, 9, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 35, 722, 0, srs_resource_configuration::comb_size_enum(2), 1, 4, 60, 7, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.619720, -0.784823), cf_t(0.844985, -0.534791), cf_t(0.603248, -0.797553), cf_t(-0.979316, -0.202335), cf_t(-0.817910, 0.575347), cf_t(0.841278, -0.540602), cf_t(-0.935217, 0.354075), cf_t(-0.208952, -0.977926), cf_t(-0.414485, 0.910056), cf_t(-0.838918, -0.544258), cf_t(0.824798, -0.565428), cf_t(0.429744, 0.902951), cf_t(-0.775950, -0.630794), cf_t(-0.495848, 0.868409), cf_t(0.978348, 0.206966), cf_t(-0.517308, 0.855799)}}, 4, 4}, 0, {-0.000000163}}}, {"test_data/srs_estimator_test_input70.dat"}}, - {{{{1, 561, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 15, 565, 0, srs_resource_configuration::comb_size_enum(4), 0, 11, 55, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.136161, -0.990687), cf_t(0.999972, 0.007530), cf_t(-0.963619, -0.267278), cf_t(0.072483, -0.997370), cf_t(0.449440, 0.893310), cf_t(-0.405318, 0.914176), cf_t(-0.927533, 0.373742), cf_t(0.077883, -0.996962), cf_t(-0.639218, 0.769025), cf_t(-0.311305, -0.950310), cf_t(-0.233001, 0.972477), cf_t(-0.887975, -0.459892), cf_t(0.375183, 0.926951), cf_t(-0.705972, -0.708240), cf_t(-0.999946, -0.010424), cf_t(-0.014684, -0.999892)}}, 4, 4}, 0, {0.000000076}}}, {"test_data/srs_estimator_test_input71.dat"}}, + {{{{0, 130, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 12, 17, 647, 2, srs_resource_configuration::comb_size_enum(2), 1, 1, 66, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.681653, -0.188013), cf_t(-0.704124, 0.064883)}}, 1, 2}, -1.4465e-15, 0, {0.000000313}}}, {"test_data/srs_estimator_test_input0.dat"}}, + {{{{0, 937, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 11, 2, 982, 3, srs_resource_configuration::comb_size_enum(4), 3, 9, 50, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.551089, 0.443059), cf_t(-0.395695, -0.586025)}}, 1, 2}, -3.3751e-15, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input1.dat"}}, + {{{{0, 283, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 99, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 25, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.068830, -0.703749), cf_t(0.273171, 0.652210), cf_t(0.198129, -0.678782), cf_t(-0.705645, 0.045444)}}, 2, 2}, -3.8573e-15, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input2.dat"}}, + {{{{0, 772, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 3, 10, 696, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 39, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.115826, 0.697556), cf_t(-0.022633, 0.706744), cf_t(0.005629, -0.707084), cf_t(-0.706612, -0.026460)}}, 2, 2}, 2.893e-15, 0, {0.000000207}}}, {"test_data/srs_estimator_test_input3.dat"}}, + {{{{0, 560, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 58, 152, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 38, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.628305, 0.324397), cf_t(-0.693909, -0.135978), cf_t(0.647192, -0.284854), cf_t(-0.642017, -0.296334), cf_t(0.666869, 0.235130), cf_t(0.128862, -0.695266), cf_t(0.484352, 0.515173), cf_t(-0.694070, 0.135157)}}, 4, 2}, 5.786e-15, 0, {-0.000000508}}}, {"test_data/srs_estimator_test_input4.dat"}}, + {{{{0, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 38, 541, 1, srs_resource_configuration::comb_size_enum(4), 2, 8, 30, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.611285, 0.355430), cf_t(0.604843, -0.366285), cf_t(0.324250, -0.628381), cf_t(0.706898, -0.017171), cf_t(0.093131, 0.700947), cf_t(0.407033, 0.578207), cf_t(-0.686686, -0.168708), cf_t(0.623507, 0.333526)}}, 4, 2}, 9.6433e-16, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input5.dat"}}, + {{{{0, 4, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 5, 836, 1, srs_resource_configuration::comb_size_enum(2), 0, 5, 61, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.293626, 0.643260), cf_t(-0.061248, 0.704449)}}, 1, 2}, 0, 0, {-0.000000369}}}, {"test_data/srs_estimator_test_input6.dat"}}, + {{{{0, 593, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 39, 148, 1, srs_resource_configuration::comb_size_enum(4), 2, 0, 16, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.505253, 0.494691), cf_t(0.285273, 0.647008)}}, 1, 2}, -4.8216e-16, 0, {-0.000000271}}}, {"test_data/srs_estimator_test_input7.dat"}}, + {{{{0, 924, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 12, 15, 502, 1, srs_resource_configuration::comb_size_enum(2), 1, 0, 11, 0, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.418800, -0.569743), cf_t(-0.423687, -0.566118), cf_t(-0.081027, -0.702449), cf_t(-0.673755, 0.214601)}}, 2, 2}, 1.9287e-15, 0, {0.000000049}}}, {"test_data/srs_estimator_test_input8.dat"}}, + {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 8, 40, 187, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.650456, 0.277321), cf_t(-0.245156, 0.663248), cf_t(-0.667946, 0.232053), cf_t(-0.706097, -0.037785)}}, 2, 2}, -4.8216e-16, 0, {0.000000011}}}, {"test_data/srs_estimator_test_input9.dat"}}, + {{{{0, 659, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 22, 831, 3, srs_resource_configuration::comb_size_enum(2), 1, 7, 39, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.185548, 0.682328), cf_t(-0.695339, 0.128467), cf_t(0.394909, -0.586555), cf_t(0.106569, 0.699030), cf_t(-0.223768, 0.670767), cf_t(0.086472, 0.701800), cf_t(0.240509, 0.664948), cf_t(0.337891, 0.621152)}}, 4, 2}, -4.8216e-16, 0, {-0.000000284}}}, {"test_data/srs_estimator_test_input10.dat"}}, + {{{{0, 945, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 62, 189, 1, srs_resource_configuration::comb_size_enum(4), 0, 4, 40, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.054202, 0.705026), cf_t(-0.170613, -0.686215), cf_t(0.523244, 0.475621), cf_t(-0.296151, 0.642102), cf_t(-0.564546, -0.425779), cf_t(0.124868, 0.695994), cf_t(-0.204416, 0.676915), cf_t(-0.628347, 0.324314)}}, 4, 2}, 1.2536e-14, 0, {0.000000008}}}, {"test_data/srs_estimator_test_input11.dat"}}, + {{{{0, 820, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 14, 951, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 24, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.705092, -0.053344), cf_t(0.687321, 0.166103)}}, 1, 2}, 9.6433e-16, 0, {0.000000401}}}, {"test_data/srs_estimator_test_input12.dat"}}, + {{{{0, 101, 9, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 2, 8, 343, 2, srs_resource_configuration::comb_size_enum(4), 0, 5, 52, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.154090, -0.690113), cf_t(0.581620, -0.402142)}}, 1, 2}, -1.4465e-15, 0, {0.000000407}}}, {"test_data/srs_estimator_test_input13.dat"}}, + {{{{0, 202, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 11, 761, 0, srs_resource_configuration::comb_size_enum(2), 1, 5, 11, 6, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.700772, -0.094436), cf_t(-0.707104, -0.002095), cf_t(-0.164231, -0.687771), cf_t(-0.695472, 0.127746)}}, 2, 2}, 9.6433e-16, 0, {-0.000000459}}}, {"test_data/srs_estimator_test_input14.dat"}}, + {{{{0, 73, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 5, 52, 99, 2, srs_resource_configuration::comb_size_enum(4), 0, 6, 66, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.419244, -0.569416), cf_t(-0.677521, 0.202400), cf_t(0.219904, -0.672043), cf_t(-0.644261, 0.291424)}}, 2, 2}, 0, 0, {0.000000339}}}, {"test_data/srs_estimator_test_input15.dat"}}, + {{{{0, 177, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 4, 3, 851, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 42, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.184375, 0.682646), cf_t(0.703762, 0.068699), cf_t(0.351621, 0.613484), cf_t(-0.491797, 0.508071), cf_t(-0.642898, 0.294418), cf_t(0.703565, -0.070685), cf_t(0.555395, 0.437648), cf_t(0.226443, 0.669868)}}, 4, 2}, -4.8216e-16, 0, {-0.000000011}}}, {"test_data/srs_estimator_test_input16.dat"}}, + {{{{0, 942, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 27, 755, 2, srs_resource_configuration::comb_size_enum(4), 3, 11, 20, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.213860, -0.673991), cf_t(-0.685847, -0.172089), cf_t(-0.354087, -0.612064), cf_t(0.490441, 0.509380), cf_t(-0.354814, -0.611643), cf_t(-0.226497, -0.669850), cf_t(0.308558, 0.636233), cf_t(0.707095, -0.004086)}}, 4, 2}, -1.9287e-15, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input17.dat"}}, + {{{{0, 903, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 29, 195, 3, srs_resource_configuration::comb_size_enum(2), 0, 7, 25, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.256483, 0.658951), cf_t(-0.636466, 0.308076), cf_t(-0.702600, 0.079704), cf_t(0.513595, 0.486025)}}, 1, 4}, -1.4465e-15, 0, {0.000000093}}}, {"test_data/srs_estimator_test_input18.dat"}}, + {{{{0, 596, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 16, 297, 3, srs_resource_configuration::comb_size_enum(4), 3, 4, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.389686, 0.313280), cf_t(0.415836, -0.277633), cf_t(0.363739, -0.343066), cf_t(0.206503, -0.455364)}}, 1, 4}, 9.6433e-16, 0, {-0.000000249}}}, {"test_data/srs_estimator_test_input19.dat"}}, + {{{{0, 435, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 2, 165, 0, srs_resource_configuration::comb_size_enum(2), 0, 7, 27, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.300996, -0.639845), cf_t(-0.321596, 0.629743), cf_t(-0.139653, -0.693179), cf_t(0.557006, 0.435596), cf_t(0.693433, -0.138388), cf_t(-0.542110, -0.454000), cf_t(-0.693447, -0.138315), cf_t(0.127268, -0.695559)}}, 2, 4}, -3.3751e-15, 0, {-0.000000080}}}, {"test_data/srs_estimator_test_input20.dat"}}, + {{{{0, 157, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 29, 450, 3, srs_resource_configuration::comb_size_enum(4), 2, 7, 65, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.041264, 0.705902), cf_t(-0.238936, -0.665514), cf_t(-0.316569, -0.632285), cf_t(0.643555, 0.292979), cf_t(-0.171822, 0.685913), cf_t(-0.021279, 0.706787), cf_t(-0.333590, -0.623472), cf_t(0.114826, 0.697721)}}, 2, 4}, 9.6433e-16, 0, {0.000000175}}}, {"test_data/srs_estimator_test_input21.dat"}}, + {{{{0, 799, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 24, 6, 3, srs_resource_configuration::comb_size_enum(2), 0, 5, 31, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.089328, -0.701442), cf_t(0.689330, 0.157556), cf_t(0.405786, 0.579084), cf_t(-0.051373, -0.705238), cf_t(-0.310971, 0.635056), cf_t(0.317553, 0.631791), cf_t(-0.383096, 0.594338), cf_t(0.031758, 0.706393), cf_t(0.153120, -0.690329), cf_t(-0.124818, -0.696003), cf_t(-0.552155, -0.441729), cf_t(0.614049, -0.350634), cf_t(-0.695687, 0.126571), cf_t(-0.697317, 0.117255), cf_t(0.253078, 0.660266), cf_t(-0.084486, 0.702041)}}, 4, 4}, -4.8216e-16, 0, {0.000000277}}}, {"test_data/srs_estimator_test_input22.dat"}}, + {{{{0, 93, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 8, 27, 699, 2, srs_resource_configuration::comb_size_enum(4), 2, 7, 64, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.180430, 0.683700), cf_t(-0.552392, -0.441433), cf_t(0.089882, -0.701371), cf_t(0.386095, -0.592394), cf_t(-0.178940, -0.684091), cf_t(-0.672687, 0.217926), cf_t(-0.416410, 0.571492), cf_t(0.351950, -0.613296), cf_t(0.061100, 0.704462), cf_t(-0.683462, 0.181329), cf_t(-0.371318, -0.601766), cf_t(-0.028609, 0.706528), cf_t(0.517291, 0.482089), cf_t(-0.371563, -0.601615), cf_t(-0.611241, 0.355506), cf_t(-0.534906, -0.462466)}}, 4, 4}, 1.9287e-15, 0, {0.000000086}}}, {"test_data/srs_estimator_test_input23.dat"}}, + {{{{0, 271, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 4, 41, 122, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 36, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.127928, -0.695438), cf_t(-0.700055, -0.099612), cf_t(0.706554, -0.027962), cf_t(0.138269, 0.693456)}}, 1, 4}, -3.3751e-15, 0, {-0.000000411}}}, {"test_data/srs_estimator_test_input24.dat"}}, + {{{{0, 414, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 40, 374, 3, srs_resource_configuration::comb_size_enum(4), 3, 2, 9, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.165621, -0.471773), cf_t(0.415613, 0.277968), cf_t(-0.493644, -0.079472), cf_t(-0.490940, -0.094753)}}, 1, 4}, 0, 0, {0.000000376}}}, {"test_data/srs_estimator_test_input25.dat"}}, + {{{{0, 687, 4, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 9, 1, 532, 1, srs_resource_configuration::comb_size_enum(2), 0, 2, 55, 4, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.452308, 0.213113), cf_t(-0.398502, 0.301987), cf_t(0.380755, -0.324076), cf_t(0.179714, -0.466586), cf_t(-0.387615, 0.315840), cf_t(0.015947, -0.499746), cf_t(0.059905, -0.496398), cf_t(-0.358835, 0.348192)}}, 2, 4}, 9.6433e-16, 0, {-0.000000296}}}, {"test_data/srs_estimator_test_input26.dat"}}, + {{{{0, 335, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 49, 449, 0, srs_resource_configuration::comb_size_enum(4), 3, 6, 60, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.601683, -0.371453), cf_t(-0.005750, -0.707083), cf_t(0.398363, 0.584215), cf_t(0.323329, -0.628855), cf_t(0.219088, 0.672310), cf_t(0.175691, -0.684933), cf_t(-0.589672, 0.390240), cf_t(-0.295126, 0.642573)}}, 2, 4}, -2.4108e-15, 0, {0.000000035}}}, {"test_data/srs_estimator_test_input27.dat"}}, + {{{{0, 139, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 31, 507, 0, srs_resource_configuration::comb_size_enum(2), 0, 6, 63, 2, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.232542, -0.667776), cf_t(0.705391, -0.049225), cf_t(0.705698, -0.044620), cf_t(0.098124, 0.700265), cf_t(-0.613574, -0.351464), cf_t(0.707103, 0.002321), cf_t(-0.696439, -0.122360), cf_t(-0.707056, 0.008467), cf_t(0.282445, -0.648248), cf_t(0.469078, -0.529118), cf_t(-0.701262, 0.090724), cf_t(0.574279, -0.412557), cf_t(0.512450, -0.487232), cf_t(-0.537496, -0.459454), cf_t(0.224194, -0.670624), cf_t(-0.630719, -0.319678)}}, 4, 4}, 9.6433e-16, 0, {0.000000360}}}, {"test_data/srs_estimator_test_input28.dat"}}, + {{{{0, 252, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 42, 85, 2, srs_resource_configuration::comb_size_enum(4), 3, 9, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.636582, -0.307836), cf_t(0.459941, -0.537080), cf_t(-0.669283, -0.228167), cf_t(-0.458930, 0.537944), cf_t(-0.619449, -0.341003), cf_t(-0.703668, 0.069656), cf_t(-0.484425, -0.515104), cf_t(0.673137, 0.216532), cf_t(0.703085, 0.075310), cf_t(0.396922, -0.585194), cf_t(0.692870, 0.141177), cf_t(-0.705589, 0.046306), cf_t(0.512837, 0.486825), cf_t(0.178409, 0.684230), cf_t(-0.531250, -0.466662), cf_t(0.249901, 0.661475)}}, 4, 4}, 0, 0, {-0.000000393}}}, {"test_data/srs_estimator_test_input29.dat"}}, + {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 34, 650, 2, srs_resource_configuration::comb_size_enum(2), 0, 5, 8, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.705809, 0.042815), cf_t(0.426329, -0.564131), cf_t(0.496619, -0.503358), cf_t(-0.089921, 0.701366)}}, 1, 4}, 0, 0, {-0.000000304}}}, {"test_data/srs_estimator_test_input30.dat"}}, + {{{{0, 427, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 2, 6, 970, 0, srs_resource_configuration::comb_size_enum(4), 0, 6, 3, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.642064, -0.296233), cf_t(-0.094520, -0.700761), cf_t(-0.053966, -0.705044), cf_t(0.651733, 0.274306)}}, 1, 4}, 1.9287e-15, 0, {0.000000375}}}, {"test_data/srs_estimator_test_input31.dat"}}, + {{{{0, 879, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 25, 525, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.248919, 0.433635), cf_t(0.273741, -0.418409), cf_t(-0.489335, 0.102722), cf_t(-0.465999, -0.181233), cf_t(-0.298453, -0.401156), cf_t(0.304214, -0.396804), cf_t(0.493732, 0.078925), cf_t(-0.288476, 0.408389)}}, 2, 4}, -9.6433e-16, 0, {-0.000000056}}}, {"test_data/srs_estimator_test_input32.dat"}}, + {{{{0, 678, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 3, 63, 920, 2, srs_resource_configuration::comb_size_enum(4), 2, 3, 28, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.487848, 0.109562), cf_t(0.218227, 0.449863), cf_t(0.043791, -0.498079), cf_t(-0.317827, 0.385987), cf_t(0.207771, -0.454787), cf_t(0.468599, 0.174398), cf_t(0.404099, 0.294455), cf_t(-0.495280, -0.068539)}}, 2, 4}, -4.8216e-16, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input33.dat"}}, + {{{{0, 926, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 6, 479, 2, srs_resource_configuration::comb_size_enum(2), 1, 2, 40, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.154320, 0.475589), cf_t(0.450451, 0.217010), cf_t(0.498260, 0.041682), cf_t(-0.176346, 0.467870), cf_t(0.332718, 0.373228), cf_t(0.023595, 0.499443), cf_t(0.399259, -0.300985), cf_t(-0.481063, 0.136302), cf_t(0.116412, 0.486259), cf_t(0.471752, 0.165682), cf_t(0.164458, 0.472179), cf_t(0.401404, 0.298119), cf_t(0.394965, -0.306598), cf_t(-0.466853, 0.179022), cf_t(0.416396, 0.276793), cf_t(0.499790, -0.014482)}}, 4, 4}, 9.6433e-16, 0, {-0.000000175}}}, {"test_data/srs_estimator_test_input34.dat"}}, + {{{{0, 305, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 40, 517, 0, srs_resource_configuration::comb_size_enum(4), 0, 10, 36, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.547223, 0.447825), cf_t(-0.016378, -0.706917), cf_t(-0.562870, -0.427992), cf_t(0.138503, -0.693410), cf_t(0.324218, -0.628397), cf_t(0.705616, 0.045892), cf_t(-0.697618, -0.115451), cf_t(-0.167131, 0.687072), cf_t(-0.371724, 0.601516), cf_t(0.674598, 0.211937), cf_t(-0.089905, -0.701368), cf_t(-0.249812, -0.661509), cf_t(-0.192891, 0.680289), cf_t(-0.348735, -0.615129), cf_t(-0.187643, -0.681755), cf_t(-0.662754, -0.246491)}}, 4, 4}, -4.3395e-15, 0, {-0.000000108}}}, {"test_data/srs_estimator_test_input35.dat"}}, + {{{{1, 345, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 8, 7, 759, 0, srs_resource_configuration::comb_size_enum(2), 1, 7, 50, 7, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.612700, -0.352985), cf_t(-0.044256, -0.705720)}}, 1, 2}, 4.8216e-15, 0, {-0.000000138}}}, {"test_data/srs_estimator_test_input36.dat"}}, + {{{{1, 887, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 43, 375, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 5, 4, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.097142, -0.700402), cf_t(0.194397, 0.679860)}}, 1, 2}, 0, 0, {-0.000000058}}}, {"test_data/srs_estimator_test_input37.dat"}}, + {{{{1, 657, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 6, 6, 155, 1, srs_resource_configuration::comb_size_enum(2), 0, 1, 27, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.559142, 0.432851), cf_t(0.151769, -0.690627), cf_t(0.538311, 0.458499), cf_t(-0.182599, 0.683123)}}, 2, 2}, 9.6433e-16, 0, {0.000000054}}}, {"test_data/srs_estimator_test_input38.dat"}}, + {{{{1, 711, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 10, 7, 443, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.084030, -0.702096), cf_t(-0.101562, 0.699775), cf_t(-0.561454, 0.429848), cf_t(0.687844, 0.163924)}}, 2, 2}, 0, 0, {0.000000090}}}, {"test_data/srs_estimator_test_input39.dat"}}, + {{{{1, 624, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 323, 0, srs_resource_configuration::comb_size_enum(2), 0, 0, 28, 8, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.395344, -0.586262), cf_t(-0.693555, -0.137772), cf_t(-0.478297, -0.520799), cf_t(0.469935, 0.528357), cf_t(-0.119723, -0.696898), cf_t(0.548168, 0.446668), cf_t(0.495266, 0.504690), cf_t(0.575711, 0.410557)}}, 4, 2}, -2.2662e-14, 0, {-0.000000186}}}, {"test_data/srs_estimator_test_input40.dat"}}, + {{{{1, 325, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 57, 222, 2, srs_resource_configuration::comb_size_enum(4), 2, 2, 5, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.605906, -0.364524), cf_t(-0.661004, -0.251145), cf_t(0.355334, 0.611341), cf_t(0.705076, -0.053553), cf_t(-0.189947, -0.681117), cf_t(-0.274407, 0.651691), cf_t(-0.507800, -0.492076), cf_t(0.338968, 0.620565)}}, 4, 2}, -4.8216e-16, 0, {-0.000000126}}}, {"test_data/srs_estimator_test_input41.dat"}}, + {{{{1, 700, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 43, 1006, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 22, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.215231, 0.673555), cf_t(-0.675969, 0.207525)}}, 1, 2}, -3.8573e-15, 0, {-0.000000040}}}, {"test_data/srs_estimator_test_input42.dat"}}, + {{{{1, 760, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 1, 439, 1, srs_resource_configuration::comb_size_enum(4), 1, 11, 63, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.682496, 0.184930), cf_t(0.042278, 0.705842)}}, 1, 2}, -1.4465e-15, 0, {0.000000137}}}, {"test_data/srs_estimator_test_input43.dat"}}, + {{{{1, 761, 7, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 1, 13, 697, 0, srs_resource_configuration::comb_size_enum(2), 1, 1, 45, 5, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.557057, -0.435531), cf_t(-0.207059, -0.676111), cf_t(-0.703283, -0.073434), cf_t(0.402617, 0.581291)}}, 2, 2}, -1.3501e-14, 0, {0.000000236}}}, {"test_data/srs_estimator_test_input44.dat"}}, + {{{{1, 37, 5, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 33, 766, 1, srs_resource_configuration::comb_size_enum(4), 2, 4, 12, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.023928, 0.706702), cf_t(0.627344, -0.326251), cf_t(0.701229, 0.090985), cf_t(-0.402217, -0.581568)}}, 2, 2}, -2.0733e-14, 0, {0.000000225}}}, {"test_data/srs_estimator_test_input45.dat"}}, + {{{{1, 813, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 32, 450, 2, srs_resource_configuration::comb_size_enum(2), 1, 0, 58, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.480184, -0.519060), cf_t(0.706981, -0.013313), cf_t(-0.406768, -0.578394), cf_t(-0.536953, 0.460089), cf_t(-0.433649, 0.558523), cf_t(0.114250, 0.697816), cf_t(-0.558749, -0.433358), cf_t(0.443197, 0.550978)}}, 4, 2}, 9.6433e-16, 0, {-0.000000247}}}, {"test_data/srs_estimator_test_input46.dat"}}, + {{{{1, 743, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 36, 861, 0, srs_resource_configuration::comb_size_enum(4), 3, 11, 15, 8, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.495468, 0.504492), cf_t(-0.450328, -0.545165), cf_t(0.678967, 0.197495), cf_t(-0.406363, 0.578678), cf_t(0.602907, 0.369464), cf_t(0.298589, 0.640971), cf_t(-0.118624, -0.697086), cf_t(-0.376570, -0.598494)}}, 4, 2}, -8.6789e-15, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input47.dat"}}, + {{{{1, 932, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 8, 24, 763, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 16, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.674713, 0.211572), cf_t(0.098696, 0.700185)}}, 1, 2}, 7.7146e-15, 0, {0.000000159}}}, {"test_data/srs_estimator_test_input48.dat"}}, + {{{{1, 548, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 4, 821, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 36, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.531463, -0.466419), cf_t(0.569452, -0.419196)}}, 1, 2}, -4.8216e-16, 0, {0.000000066}}}, {"test_data/srs_estimator_test_input49.dat"}}, + {{{{1, 186, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 49, 109, 1, srs_resource_configuration::comb_size_enum(2), 1, 3, 46, 10, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.696311, -0.123090), cf_t(-0.565094, -0.425052), cf_t(-0.600794, 0.372890), cf_t(0.002311, -0.707103)}}, 2, 2}, 0, 0, {0.000000044}}}, {"test_data/srs_estimator_test_input50.dat"}}, + {{{{1, 524, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 22, 736, 3, srs_resource_configuration::comb_size_enum(4), 1, 5, 28, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.142382, 0.692623), cf_t(-0.255814, 0.659211), cf_t(0.497939, 0.502052), cf_t(-0.105767, -0.699152)}}, 2, 2}, 9.6433e-16, 0, {0.000000147}}}, {"test_data/srs_estimator_test_input51.dat"}}, + {{{{1, 863, 6, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 10, 24, 789, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 45, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.700048, 0.099667), cf_t(0.060151, 0.704544), cf_t(0.339262, -0.620404), cf_t(0.648026, -0.282952), cf_t(-0.504016, -0.495951), cf_t(0.312584, 0.634264), cf_t(0.075039, -0.703114), cf_t(0.550766, 0.443460)}}, 4, 2}, 0, 0, {-0.000000166}}}, {"test_data/srs_estimator_test_input52.dat"}}, + {{{{1, 197, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 9, 35, 101, 3, srs_resource_configuration::comb_size_enum(4), 1, 4, 14, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.705669, -0.045076), cf_t(-0.487522, -0.512174), cf_t(-0.547248, 0.447794), cf_t(-0.707084, -0.005700), cf_t(0.588220, -0.392425), cf_t(0.568029, 0.421121), cf_t(0.665878, 0.237921), cf_t(-0.643028, 0.294135)}}, 4, 2}, 0, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input53.dat"}}, + {{{{1, 915, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 62, 399, 2, srs_resource_configuration::comb_size_enum(2), 0, 4, 51, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.606136, 0.364142), cf_t(-0.706289, 0.033997), cf_t(-0.240597, -0.664916), cf_t(0.696755, -0.120548)}}, 1, 4}, -4.8216e-16, 0, {-0.000000090}}}, {"test_data/srs_estimator_test_input54.dat"}}, + {{{{1, 977, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 18, 365, 0, srs_resource_configuration::comb_size_enum(4), 2, 7, 44, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.675776, 0.208150), cf_t(-0.411247, 0.575218), cf_t(-0.674315, 0.212836), cf_t(0.040386, 0.705953)}}, 1, 4}, 6.7503e-15, 0, {0.000000112}}}, {"test_data/srs_estimator_test_input55.dat"}}, + {{{{1, 748, 8, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 37, 856, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 59, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.426838, 0.563746), cf_t(0.696925, -0.119566), cf_t(-0.671730, 0.220858), cf_t(0.263577, 0.656146), cf_t(0.688624, -0.160616), cf_t(-0.351807, -0.613378), cf_t(0.682282, 0.185720), cf_t(-0.605356, -0.365437)}}, 2, 4}, -3.3751e-15, 0, {0.000000091}}}, {"test_data/srs_estimator_test_input56.dat"}}, + {{{{1, 830, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 41, 85, 0, srs_resource_configuration::comb_size_enum(4), 1, 3, 17, 10, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.245448, 0.435609), cf_t(0.373291, -0.332647), cf_t(0.288186, 0.408594), cf_t(0.414810, 0.279164), cf_t(-0.288806, 0.408156), cf_t(0.452468, -0.212774), cf_t(0.360898, 0.346053), cf_t(-0.402691, 0.296378)}}, 2, 4}, -2.893e-15, 0, {-0.000000236}}}, {"test_data/srs_estimator_test_input57.dat"}}, + {{{{1, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 7, 37, 702, 0, srs_resource_configuration::comb_size_enum(2), 1, 3, 36, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.497714, -0.047754), cf_t(-0.491508, 0.091762), cf_t(-0.499851, -0.012213), cf_t(-0.494123, 0.076439), cf_t(-0.106992, -0.488419), cf_t(-0.464059, -0.186144), cf_t(-0.301942, -0.398536), cf_t(-0.324627, 0.380286), cf_t(0.265175, -0.423890), cf_t(-0.059834, 0.496407), cf_t(-0.177459, 0.467449), cf_t(0.118596, -0.485731), cf_t(-0.456680, 0.203577), cf_t(-0.003084, -0.499990), cf_t(0.321789, 0.382690), cf_t(0.094603, -0.490969)}}, 4, 4}, -1.9287e-15, 0, {0.000000088}}}, {"test_data/srs_estimator_test_input58.dat"}}, + {{{{1, 573, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 18, 961, 3, srs_resource_configuration::comb_size_enum(4), 3, 10, 64, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.673645, -0.214948), cf_t(-0.667576, 0.233113), cf_t(0.652659, -0.272097), cf_t(-0.589330, -0.390756), cf_t(-0.095730, -0.700597), cf_t(-0.428806, -0.562251), cf_t(0.338831, -0.620640), cf_t(0.492252, -0.507629), cf_t(-0.626452, -0.327960), cf_t(-0.700841, -0.093924), cf_t(0.412333, -0.574440), cf_t(0.646278, -0.286923), cf_t(0.697795, 0.114377), cf_t(-0.491487, 0.508371), cf_t(-0.492194, 0.507686), cf_t(-0.346614, -0.616327)}}, 4, 4}, 0, 0, {-0.000000153}}}, {"test_data/srs_estimator_test_input59.dat"}}, + {{{{1, 416, 6, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 18, 956, 2, srs_resource_configuration::comb_size_enum(2), 1, 4, 18, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.147002, -0.691658), cf_t(-0.147238, 0.691608), cf_t(0.561973, -0.429170), cf_t(0.327254, -0.626821)}}, 1, 4}, 0, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input60.dat"}}, + {{{{1, 854, 4, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 29, 588, 2, srs_resource_configuration::comb_size_enum(4), 3, 0, 45, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.463143, 0.188410), cf_t(-0.462324, 0.190412), cf_t(0.370793, 0.335429), cf_t(0.197656, -0.459274)}}, 1, 4}, -3.3751e-15, 0, {-0.000000091}}}, {"test_data/srs_estimator_test_input61.dat"}}, + {{{{1, 384, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 8, 575, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 9, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.498654, 0.036664), cf_t(-0.339651, -0.366929), cf_t(-0.484366, -0.124056), cf_t(0.317064, -0.386614), cf_t(0.412881, 0.282009), cf_t(0.493456, -0.080631), cf_t(0.302679, 0.397976), cf_t(-0.451286, -0.215270)}}, 2, 4}, 9.6433e-16, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input62.dat"}}, + {{{{1, 338, 5, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 56, 503, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 41, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.209018, -0.454215), cf_t(-0.026949, 0.499273), cf_t(0.377610, -0.327736), cf_t(0.400531, -0.299291), cf_t(0.453889, -0.209725), cf_t(-0.416411, -0.276770), cf_t(0.181768, 0.465790), cf_t(-0.499854, -0.012063)}}, 2, 4}, -1.9287e-15, 0, {0.000000059}}}, {"test_data/srs_estimator_test_input63.dat"}}, + {{{{1, 206, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 39, 438, 2, srs_resource_configuration::comb_size_enum(2), 1, 6, 37, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.391941, 0.588542), cf_t(0.364793, -0.605744), cf_t(-0.534472, 0.462968), cf_t(-0.244731, -0.663405), cf_t(-0.654034, -0.268775), cf_t(-0.082507, -0.702277), cf_t(0.113049, -0.698011), cf_t(0.665624, -0.238631), cf_t(-0.240346, -0.665007), cf_t(-0.450833, 0.544747), cf_t(-0.069768, -0.703656), cf_t(0.150921, -0.690813), cf_t(-0.632946, 0.315244), cf_t(-0.678046, 0.200634), cf_t(-0.640334, 0.299954), cf_t(-0.194835, -0.679735)}}, 4, 4}, 0, 0, {-0.000000203}}}, {"test_data/srs_estimator_test_input64.dat"}}, + {{{{1, 470, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 0, 1, 234, 3, srs_resource_configuration::comb_size_enum(4), 0, 6, 14, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.636720, -0.307551), cf_t(0.663822, 0.243600), cf_t(-0.649260, 0.280110), cf_t(0.463834, -0.533720), cf_t(0.508752, 0.491092), cf_t(0.663258, 0.245129), cf_t(0.349267, -0.614827), cf_t(0.578013, 0.407309), cf_t(-0.336102, -0.622122), cf_t(0.406588, 0.578521), cf_t(-0.523326, -0.475531), cf_t(0.592348, -0.386165), cf_t(-0.573142, -0.414136), cf_t(0.701740, 0.086953), cf_t(-0.701459, -0.089194), cf_t(0.550409, 0.443903)}}, 4, 4}, 0, 0, {0.000000009}}}, {"test_data/srs_estimator_test_input65.dat"}}, + {{{{1, 4, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 63, 869, 2, srs_resource_configuration::comb_size_enum(2), 0, 6, 39, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.057193, -0.704790), cf_t(0.613194, 0.352126), cf_t(-0.372880, -0.600800), cf_t(-0.703087, -0.075293)}}, 1, 4}, 0, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input66.dat"}}, + {{{{1, 451, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 10, 53, 671, 2, srs_resource_configuration::comb_size_enum(4), 2, 4, 16, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.439773, -0.237908), cf_t(0.335080, -0.371109), cf_t(-0.416652, 0.276408), cf_t(0.379968, 0.324999)}}, 1, 4}, -5.3038e-15, 0, {-0.000000029}}}, {"test_data/srs_estimator_test_input67.dat"}}, + {{{{1, 853, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 4, 8, 399, 1, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 3, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.445301, 0.227391), cf_t(0.020184, 0.499592), cf_t(0.366185, 0.340454), cf_t(0.109286, -0.487910), cf_t(-0.499760, 0.015495), cf_t(0.446794, 0.224443), cf_t(-0.135245, -0.481361), cf_t(-0.392918, 0.309218)}}, 2, 4}, -4.8216e-16, 0, {-0.000000259}}}, {"test_data/srs_estimator_test_input68.dat"}}, + {{{{1, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 1, 8, 274, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 32, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.355792, 0.351300), cf_t(-0.460517, 0.194741), cf_t(-0.494429, -0.074430), cf_t(0.230200, 0.443856), cf_t(-0.046656, 0.497818), cf_t(0.493288, 0.081651), cf_t(0.454587, 0.208209), cf_t(0.479864, -0.140466)}}, 2, 4}, 9.6433e-16, 0, {-0.000000036}}}, {"test_data/srs_estimator_test_input69.dat"}}, + {{{{1, 7, 9, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 35, 722, 0, srs_resource_configuration::comb_size_enum(2), 1, 4, 60, 7, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.438208, -0.554954), cf_t(0.597494, -0.378154), cf_t(0.426561, -0.563955), cf_t(-0.692481, -0.143072), cf_t(-0.578349, 0.406832), cf_t(0.594874, -0.382264), cf_t(-0.661298, 0.250369), cf_t(-0.147752, -0.691498), cf_t(-0.293085, 0.643507), cf_t(-0.593204, -0.384849), cf_t(0.583220, -0.399818), cf_t(0.303875, 0.638482), cf_t(-0.548680, -0.446039), cf_t(-0.350618, 0.614058), cf_t(0.691797, 0.146347), cf_t(-0.365792, 0.605141)}}, 4, 4}, -4.8216e-16, 0, {-0.000000163}}}, {"test_data/srs_estimator_test_input70.dat"}}, + {{{{1, 561, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 15, 565, 0, srs_resource_configuration::comb_size_enum(4), 0, 11, 55, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.096280, -0.700521), cf_t(0.707087, 0.005324), cf_t(-0.681382, -0.188994), cf_t(0.051253, -0.705247), cf_t(0.317802, 0.631666), cf_t(-0.286603, 0.646420), cf_t(-0.655865, 0.264276), cf_t(0.055072, -0.704959), cf_t(-0.451996, 0.543783), cf_t(-0.220126, -0.671971), cf_t(-0.164757, 0.687645), cf_t(-0.627893, -0.325193), cf_t(0.265294, 0.655453), cf_t(-0.499198, -0.500801), cf_t(-0.707068, -0.007371), cf_t(-0.010383, -0.707031)}}, 4, 4}, 9.6433e-16, 0, {0.000000076}}}, {"test_data/srs_estimator_test_input71.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz index a42b9bff20..476fbe56a7 100644 --- a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz +++ b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03cf300426210d5da88c4d7745d381e78ada21e19e2be97366deaa715976d76f -size 643191 +oid sha256:8f2f48e56d05ff2ade31310b4fb58d1c1be7b04eb576802be265b45ae24f1cd7 +size 643092 diff --git a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_vectortest.cpp b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_vectortest.cpp index ccef3b7a55..f4b77f89ae 100644 --- a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_vectortest.cpp +++ b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_vectortest.cpp @@ -88,6 +88,9 @@ TEST_P(srsEstimatorFixture, FromVector) srs_estimator_result result = estimator->estimate(grid, config); ASSERT_EQ(test_case.context.result.channel_matrix.normalize(), result.channel_matrix.normalize()); + ASSERT_TRUE(result.epre_dB.has_value()); + ASSERT_NEAR( + convert_dB_to_power(test_case.context.result.epre_dB.value()), convert_dB_to_power(result.epre_dB.value()), 5e-3); ASSERT_NEAR(test_case.context.result.time_alignment.time_alignment, result.time_alignment.time_alignment, 1e-7); } From 65a3a82fd00d167019d7c4bb53e7bac89296bbb4 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 30 Oct 2024 14:44:34 +0100 Subject: [PATCH 03/72] phy: refactor srs validator The sounding reference signal validator now returns an error message instead of a simple pass/fail flag. --- .../srs/srs_estimator_configuration_validator.h | 7 +++++-- include/srsran/phy/upper/uplink_processor.h | 6 +++--- lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp | 7 ++++--- .../srs/srs_validator_generic_impl.cpp | 12 ++++++------ .../srs/srs_validator_generic_impl.h | 2 +- lib/phy/upper/upper_phy_pdu_validators.h | 5 ++++- .../fapi_adaptor/phy/fapi_to_phy_translator_test.cpp | 5 ++++- 7 files changed, 27 insertions(+), 17 deletions(-) diff --git a/include/srsran/phy/upper/signal_processors/srs/srs_estimator_configuration_validator.h b/include/srsran/phy/upper/signal_processors/srs/srs_estimator_configuration_validator.h index f587d44b31..16b71983a0 100644 --- a/include/srsran/phy/upper/signal_processors/srs/srs_estimator_configuration_validator.h +++ b/include/srsran/phy/upper/signal_processors/srs/srs_estimator_configuration_validator.h @@ -10,6 +10,9 @@ #pragma once +#include "srsran/adt/expected.h" +#include + namespace srsran { struct srs_estimator_configuration; @@ -22,8 +25,8 @@ class srs_estimator_configuration_validator virtual ~srs_estimator_configuration_validator() = default; /// \brief Validates SRS channel estimator configuration parameters. - /// \return True if the parameters contained in \c config are supported, false otherwise. - virtual bool is_valid(const srs_estimator_configuration& config) const = 0; + /// \return A success if the parameters contained in \c config are supported, an error message otherwise. + virtual error_type is_valid(const srs_estimator_configuration& config) const = 0; }; } // namespace srsran diff --git a/include/srsran/phy/upper/uplink_processor.h b/include/srsran/phy/upper/uplink_processor.h index 6614a3208d..4f1a8de710 100644 --- a/include/srsran/phy/upper/uplink_processor.h +++ b/include/srsran/phy/upper/uplink_processor.h @@ -161,12 +161,12 @@ class uplink_pdu_validator virtual error_type is_valid(const pucch_processor::format4_configuration& config) const = 0; /// \brief Validates PUSCH configuration parameters. - /// \return A success if the parameters contained in \c pdu are supported, an error message otherwise. + /// \return A success if the parameters contained in \c config are supported, an error message otherwise. virtual error_type is_valid(const pusch_processor::pdu_t& config) const = 0; /// \brief Validates Sounding Reference Signals channel estimator configuration. - /// \return True if the parameters contained in \c config are supported, false otherwise. - virtual bool is_valid(const srs_estimator_configuration& config) const = 0; + /// \return A success if the parameters contained in \c config are supported, an error message otherwise. + virtual error_type is_valid(const srs_estimator_configuration& config) const = 0; }; /// \brief Pool of uplink processors. diff --git a/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp b/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp index b894ae368c..1deeb3c5d2 100644 --- a/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp +++ b/lib/fapi_adaptor/phy/fapi_to_phy_translator.cpp @@ -457,9 +457,10 @@ static expected translate_ul_tti_pdus_to_phy_pdus(const fapi::ul_tt case fapi::ul_pdu_type::SRS: { uplink_processor::srs_pdu& ul_pdu = pdus.srs.emplace_back(); convert_srs_fapi_to_phy(ul_pdu, pdu.srs_pdu, msg.sfn, msg.slot); - if (!ul_pdu_validator.is_valid(ul_pdu.config)) { - logger.warning("Upper PHY flagged a SRS PDU as having an invalid configuration. Skipping UL_TTI.request"); - + error_type srs_validation = ul_pdu_validator.is_valid(ul_pdu.config); + if (!srs_validation.has_value()) { + logger.warning("Skipping UL_TTI.request: SRS PDU flagged as invalid with the following error\n {}", + srs_validation.error()); return make_unexpected(default_error_t{}); } break; diff --git a/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.cpp b/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.cpp index 3b2d671a65..cc5e04de46 100644 --- a/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.cpp +++ b/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.cpp @@ -13,27 +13,27 @@ using namespace srsran; -bool srs_validator_generic_impl::is_valid(const srs_estimator_configuration& config) const +error_type srs_validator_generic_impl::is_valid(const srs_estimator_configuration& config) const { // Check the SRS resource is valid. if (!config.resource.is_valid()) { - return false; + return make_unexpected("Invalid SRS resource configuration."); } // Frequency hopping is not supported. if (config.resource.has_frequency_hopping()) { - return false; + return make_unexpected("The SRS estimator does not support frequency hopping."); } // Sequence and group hopping is not supported. if (config.resource.hopping != srs_resource_configuration::group_or_sequence_hopping_enum::neither) { - return false; + return make_unexpected("The SRS estimator does not support group or sequence hopping."); } // Invalid receive port list. if (config.ports.empty()) { - return false; + return make_unexpected("Empty list of Rx ports for the SRS estimator."); } - return true; + return default_success_t(); } diff --git a/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.h b/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.h index 7381175574..c4e9723260 100644 --- a/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.h +++ b/lib/phy/upper/signal_processors/srs/srs_validator_generic_impl.h @@ -21,7 +21,7 @@ class srs_validator_generic_impl : public srs_estimator_configuration_validator { public: // See interface for documentation. - bool is_valid(const srs_estimator_configuration& config) const override; + error_type is_valid(const srs_estimator_configuration& config) const override; }; } // namespace srsran diff --git a/lib/phy/upper/upper_phy_pdu_validators.h b/lib/phy/upper/upper_phy_pdu_validators.h index 2d241009e1..410d5c077f 100644 --- a/lib/phy/upper/upper_phy_pdu_validators.h +++ b/lib/phy/upper/upper_phy_pdu_validators.h @@ -62,7 +62,10 @@ class uplink_processor_validator_impl : public uplink_pdu_validator { return pusch->is_valid(config); } - bool is_valid(const srs_estimator_configuration& config) const override { return srs->is_valid(config); } + error_type is_valid(const srs_estimator_configuration& config) const override + { + return srs->is_valid(config); + } private: std::unique_ptr prach; diff --git a/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp b/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp index 026f94ab81..e391d881db 100644 --- a/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp +++ b/tests/unittests/fapi_adaptor/phy/fapi_to_phy_translator_test.cpp @@ -83,7 +83,10 @@ class uplink_pdu_validator_dummy : public uplink_pdu_validator return default_success_t(); } error_type is_valid(const pusch_processor::pdu_t& pdu) const override { return default_success_t(); } - bool is_valid(const srs_estimator_configuration& config) const override { return true; } + error_type is_valid(const srs_estimator_configuration& config) const override + { + return default_success_t(); + } }; class resource_grid_pool_dummy : public resource_grid_pool, private shared_resource_grid::pool_interface From 91d4a95987e28d57d969f22e527e9894a6fc95e8 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 30 Oct 2024 11:16:47 +0100 Subject: [PATCH 04/72] e2sm_rc: fix PLMN decoding --- .../e2sm_rc_control_action_du_executor.cpp | 16 ++++++++++++---- .../e2/e2_ric_control_procedure_test.cpp | 13 +++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp index a43685e824..aed12551da 100644 --- a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp +++ b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp @@ -108,8 +108,16 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( if (action_params[ran_param_id] == "PLMN Identity") { srs_du::control_config_params cur_control_params = {}; cur_control_params.rrm_policy_group.emplace(); - cur_control_params.rrm_policy_group.value().pol_member.plmn_id = - plmn_identity::parse(ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_string()).value(); + if (ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().size() != 3) { + logger.error("E2SM-RC Slice-level PRB quota Control Request: PLMN (param_id={}) encoded not correctly.", + ran_param_id); + return; + } + std::array plmn_bytes; + std::copy(ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().begin(), + ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().end(), + plmn_bytes.begin()); + cur_control_params.rrm_policy_group.value().pol_member.plmn_id.from_bytes(plmn_bytes); ctrl_cfg.param_list.push_back(cur_control_params); } else if (action_params[ran_param_id] == "SST") { if (ctrl_cfg.param_list.size()) { @@ -257,7 +265,7 @@ e2sm_ric_control_response e2sm_rc_control_action_2_6_du_executor::convert_to_e2s srs_du::control_config_params req = du_config_req_.param_list[0]; if (req.rrm_policy_group.has_value()) { e2sm_rc_ctrl_outcome_format1_item_s min_prb_outcome; - min_prb_outcome.ran_param_id = 10; + min_prb_outcome.ran_param_id = 11; if (req.rrm_policy_group.value().min_prb_policy_ratio.has_value()) { min_prb_outcome.ran_param_value.set_value_int() = req.rrm_policy_group.value().min_prb_policy_ratio.value(); ctrl_outcome.ran_p_list.push_back(min_prb_outcome); @@ -266,7 +274,7 @@ e2sm_ric_control_response e2sm_rc_control_action_2_6_du_executor::convert_to_e2s if (req.rrm_policy_group.has_value()) { e2sm_rc_ctrl_outcome_format1_item_s max_prb_outcome; - max_prb_outcome.ran_param_id = 11; + max_prb_outcome.ran_param_id = 12; if (req.rrm_policy_group.value().max_prb_policy_ratio.has_value()) { max_prb_outcome.ran_param_value.set_value_int() = req.rrm_policy_group.value().max_prb_policy_ratio.value(); ctrl_outcome.ran_p_list.push_back(max_prb_outcome); diff --git a/tests/unittests/e2/e2_ric_control_procedure_test.cpp b/tests/unittests/e2/e2_ric_control_procedure_test.cpp index 1371d71a32..6b99854c67 100644 --- a/tests/unittests/e2/e2_ric_control_procedure_test.cpp +++ b/tests/unittests/e2/e2_ric_control_procedure_test.cpp @@ -66,12 +66,13 @@ TEST_F(e2_test_setup, ric_control_procedure_packed) { e2->handle_e2_tnl_connection_request(); uint8_t e2ap_ctrl_req[] = { - 0x00, 0x04, 0x00, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x03, 0x00, 0x16, 0x00, 0x09, 0x08, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, 0x17, 0x00, - 0x46, 0x45, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x00, 0x03, 0x00, 0x02, 0x44, 0x00, 0x00, 0x00, - 0x03, 0x60, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x05, 0x2a, 0x00, 0x05, 0x30, 0x30, 0x31, 0x30, 0x31, 0x00, 0x06, - 0x44, 0x00, 0x01, 0x00, 0x07, 0x2a, 0x00, 0x01, 0x31, 0x00, 0x08, 0x2a, 0x00, 0x01, 0x30, 0x00, 0x09, 0x28, 0x80, - 0x01, 0x01, 0x00, 0x0a, 0x28, 0x80, 0x01, 0x05, 0x00, 0x0b, 0x28, 0x80, 0x01, 0x64, 0x00, 0x15, 0x00, 0x01, 0x40}; + 0x00, 0x04, 0x00, 0x78, 0x00, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x02, 0x00, 0x03, 0x00, 0x16, 0x00, 0x09, 0x08, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, + 0x17, 0x00, 0x50, 0x4f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x44, + 0x00, 0x03, 0x00, 0x02, 0x44, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x05, 0x44, + 0x00, 0x01, 0x00, 0x06, 0x2a, 0x00, 0x03, 0x00, 0xf1, 0x10, 0x00, 0x07, 0x44, 0x00, 0x01, 0x00, 0x08, 0x2a, + 0x00, 0x01, 0x01, 0x00, 0x09, 0x2a, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x28, 0x80, 0x01, 0x01, 0x00, + 0x0b, 0x28, 0x80, 0x01, 0x32, 0x00, 0x0c, 0x28, 0x80, 0x01, 0x64, 0x00, 0x15, 0x00, 0x01, 0x40}; byte_buffer e2ap_ctrl_req_buf = byte_buffer::create(e2ap_ctrl_req, e2ap_ctrl_req + sizeof(e2ap_ctrl_req)).value(); packer->handle_packed_pdu(std::move(e2ap_ctrl_req_buf)); From 92c27d6e0f6010207f52698cd22dbfa88c822f5d Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 30 Oct 2024 11:59:17 +0100 Subject: [PATCH 05/72] e2sm_rc: apply prb limits as ratios --- .../du_ue_ric_configuration_procedure.cpp | 34 ++++++++++++++----- ...du_ue_ric_configuration_procedure_test.cpp | 11 ++++-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp b/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp index 087f6a7e5d..663117cd9d 100644 --- a/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp +++ b/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp @@ -79,15 +79,31 @@ async_task du_ue_ric_configuration_procedure::h rrm_policy_ratio_group dummy = {}; res_alloc_cfg.rrm_policy_group = req.rrm_policy_group.has_value() ? req.rrm_policy_group.value() : dummy; // TODO remove when RRM group support is added to scheduler. - res_alloc_cfg.pdsch_grant_size_limits = { - req.rrm_policy_group.has_value() ? (req.rrm_policy_group.value().min_prb_policy_ratio.has_value() - ? req.rrm_policy_group.value().min_prb_policy_ratio.value() - : 0) - : 0, - req.rrm_policy_group.has_value() ? (req.rrm_policy_group.value().max_prb_policy_ratio.has_value() - ? req.rrm_policy_group.value().max_prb_policy_ratio.value() - : MAX_NOF_PRBS) - : MAX_NOF_PRBS}; + int min_prb_limit = 0; + int max_prb_limit = MAX_NOF_PRBS; + if (req.rrm_policy_group.has_value()) { + unsigned int nof_prbs = get_max_Nprb(du_params.ran.cells[0].dl_carrier.carrier_bw_mhz, + du_params.ran.cells[0].scs_common, + band_helper::get_freq_range(du_params.ran.cells[0].dl_carrier.band)); + + min_prb_limit = req.rrm_policy_group.value().min_prb_policy_ratio.has_value() + ? req.rrm_policy_group.value().min_prb_policy_ratio.value() + : 0; + max_prb_limit = req.rrm_policy_group.value().max_prb_policy_ratio.has_value() + ? req.rrm_policy_group.value().max_prb_policy_ratio.value() + : MAX_NOF_PRBS; + + min_prb_limit = std::max(0, std::min(min_prb_limit, 100)); + max_prb_limit = std::max(0, std::min(max_prb_limit, 100)); + + if (max_prb_limit < min_prb_limit) { + std::swap(max_prb_limit, min_prb_limit); + } + + min_prb_limit = static_cast((1.0 * min_prb_limit / 100) * nof_prbs); + max_prb_limit = static_cast((1.0 * max_prb_limit / 100) * nof_prbs); + } + res_alloc_cfg.pdsch_grant_size_limits = {min_prb_limit, max_prb_limit}; res_alloc_cfg.max_pdsch_harq_retxs = req.num_harq_retransmissions.has_value() ? req.num_harq_retransmissions.value() diff --git a/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp b/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp index 3e41a4b253..a1ed50a33d 100644 --- a/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp +++ b/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp @@ -48,15 +48,22 @@ TEST_F(du_ue_ric_config_tester, { std::vector param_list; rrm_policy_ratio_group pol; - pol.max_prb_policy_ratio = 10; + pol.max_prb_policy_ratio = 50; pol.min_prb_policy_ratio = 5; + + unsigned int nof_prbs = get_max_Nprb(params.ran.cells[0].dl_carrier.carrier_bw_mhz, + params.ran.cells[0].scs_common, + band_helper::get_freq_range(params.ran.cells[0].dl_carrier.band)); + int expected_min_prb = static_cast((1.0 * pol.min_prb_policy_ratio.value() / 100) * nof_prbs); + int expected_max_prb = static_cast((1.0 * pol.max_prb_policy_ratio.value() / 100) * nof_prbs); + param_list.emplace_back(control_config_params{std::nullopt, std::nullopt, pol}); start_procedure(du_mac_sched_control_config{(uint64_t)test_ue->f1ap_ue_id, param_list}); ASSERT_TRUE(mac.last_ue_reconf_msg.has_value()) << "MAC should have received new configuration"; ASSERT_EQ(mac.last_ue_reconf_msg->ue_index, test_ue->ue_index); ASSERT_TRUE(mac.last_ue_reconf_msg->sched_cfg.res_alloc_cfg.has_value()); - prb_interval expected_prbs{5, 10}; + prb_interval expected_prbs{expected_min_prb, expected_max_prb}; ASSERT_EQ(mac.last_ue_reconf_msg->sched_cfg.res_alloc_cfg->pdsch_grant_size_limits, expected_prbs); ASSERT_FALSE(mac.last_ue_reconf_msg->sched_cfg.cells.has_value()) << "Cells should not have been configured"; ASSERT_FALSE(mac.last_ue_reconf_msg->sched_cfg.lc_config_list.has_value()) From ef116af5d658eac9fff79c69bfe0396298ef82b9 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 30 Oct 2024 12:36:18 +0100 Subject: [PATCH 06/72] e2sm_rc: apply PRB limits also to PUSCH --- .../du_manager/procedures/du_ue_ric_configuration_procedure.cpp | 1 + .../procedures/du_ue_ric_configuration_procedure_test.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp b/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp index 663117cd9d..ad4f18a291 100644 --- a/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp +++ b/lib/du/du_high/du_manager/procedures/du_ue_ric_configuration_procedure.cpp @@ -104,6 +104,7 @@ async_task du_ue_ric_configuration_procedure::h max_prb_limit = static_cast((1.0 * max_prb_limit / 100) * nof_prbs); } res_alloc_cfg.pdsch_grant_size_limits = {min_prb_limit, max_prb_limit}; + res_alloc_cfg.pusch_grant_size_limits = {min_prb_limit, max_prb_limit}; res_alloc_cfg.max_pdsch_harq_retxs = req.num_harq_retransmissions.has_value() ? req.num_harq_retransmissions.value() diff --git a/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp b/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp index a1ed50a33d..9da503e5cc 100644 --- a/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp +++ b/tests/unittests/du_manager/procedures/du_ue_ric_configuration_procedure_test.cpp @@ -65,6 +65,7 @@ TEST_F(du_ue_ric_config_tester, ASSERT_TRUE(mac.last_ue_reconf_msg->sched_cfg.res_alloc_cfg.has_value()); prb_interval expected_prbs{expected_min_prb, expected_max_prb}; ASSERT_EQ(mac.last_ue_reconf_msg->sched_cfg.res_alloc_cfg->pdsch_grant_size_limits, expected_prbs); + ASSERT_EQ(mac.last_ue_reconf_msg->sched_cfg.res_alloc_cfg->pusch_grant_size_limits, expected_prbs); ASSERT_FALSE(mac.last_ue_reconf_msg->sched_cfg.cells.has_value()) << "Cells should not have been configured"; ASSERT_FALSE(mac.last_ue_reconf_msg->sched_cfg.lc_config_list.has_value()) << "Logical channels should not have been configured"; From 01eac5c8bbdf436921ad56b1d97fbec16517e0f2 Mon Sep 17 00:00:00 2001 From: faluco Date: Mon, 4 Nov 2024 18:17:57 +0100 Subject: [PATCH 07/72] MAC: Lower no HARW buffers available logline from error to warning --- lib/mac/mac_dl/dl_sch_pdu_assembler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp index fecb293435..303af5ccac 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp @@ -311,7 +311,7 @@ shared_transport_block dl_sch_pdu_assembler::assemble_newtx_pdu(rnti_t auto shared_buffer = harq_buffers.allocate_dl_harq_buffer(ue_idx, h_id); if (not shared_buffer or shared_buffer->get_buffer().size() < tb_size_bytes) { - logger.error( + logger.warning( "DL ue={} rnti={} h_id={}: Failed to assemble MAC PDU. Cause: No HARQ buffers available", ue_idx, rnti, h_id); return make_shared_zero_buffer(tb_size_bytes); } @@ -460,10 +460,10 @@ dl_sch_pdu_assembler::assemble_retx_pdu(rnti_t rnti, harq_id_t h_id, unsigned tb auto shared_buffer = harq_buffers.allocate_dl_harq_buffer(ue_idx, h_id); if (not shared_buffer or shared_buffer->get_buffer().size() < tbs_bytes) { - logger.error("DL ue={} rnti={} h_id={}: Failed to assemble MAC PDU. Cause: No HARQ buffers available", - ue_mng.get_ue_index(rnti), - rnti, - h_id); + logger.warning("DL ue={} rnti={} h_id={}: Failed to assemble MAC PDU. Cause: No HARQ buffers available", + ue_mng.get_ue_index(rnti), + rnti, + h_id); return make_shared_zero_buffer(tbs_bytes); } From 291a8b26e006dbf58c7add5906f98a9df1cc1f0a Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 5 Nov 2024 16:35:08 +0000 Subject: [PATCH 08/72] support: added RTSAN support This includes helpers in CMakeLists.txt to enable the feature, a helper include for using RTSAN attributes only if it's supported by the compiler and decorating the pull_pdu, handle_status_report and handle_slot_indication_impl functions. --- CMakeLists.txt | 7 ++++++ include/srsran/support/rtsan.h | 30 ++++++++++++++++++++++++++ lib/mac/mac_dl/mac_cell_processor.cpp | 3 ++- lib/rlc/rlc_tx_am_entity.cpp | 5 +++-- tests/unittests/rlc/rlc_tx_am_test.cpp | 5 +++++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 include/srsran/support/rtsan.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5099acc8e8..5d85f13e20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ option(STOP_ON_WARNING "Interrupt application on warning" OFF) option(ENABLE_WERROR "Stop compilation on errors" ON) option(ENABLE_TSAN "Enable clang thread sanitizer" OFF) option(ENABLE_ASAN "Enable clang address sanitizer" OFF) +option(ENABLE_RTSAN "Enable clang real-time sanitizer" OFF) option(ENABLE_GCOV "Enable code coverage" OFF) option(ENABLE_UHD "Enable UHD" ON) option(ENABLE_ZEROMQ "Enable ZeroMQ" ON) @@ -198,6 +199,12 @@ if (ENABLE_TSAN) add_definitions(-DENABLE_TSAN) endif (ENABLE_TSAN) +if (ENABLE_RTSAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=realtime") + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-fsanitize=realtime" HAVE_RPATH_FORCE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=realtime") +endif () + if (FORCE_DEBUG_INFO) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") endif (FORCE_DEBUG_INFO) diff --git a/include/srsran/support/rtsan.h b/include/srsran/support/rtsan.h new file mode 100644 index 0000000000..0f937731f6 --- /dev/null +++ b/include/srsran/support/rtsan.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief Defines helper macros to use RTSAN, if supported. + +#pragma once + +#ifdef __has_feature +#if __has_feature(realtime_sanitizer) +#define SRSRAN_RTSAN_ENABLED +#endif +#endif + +#ifdef SRSRAN_RTSAN_ENABLED +#include + +#define SRSRAN_RTSAN_NONBLOCKING [[clang::nonblocking]] +#define SRSRAN_RTSAN_SCOPED_DISABLER(VAR) __rtsan::ScopedDisabler(VAR); +#else +#define SRSRAN_RTSAN_NONBLOCKING +#define SRSRAN_RTSAN_SCOPED_DISABLER(VAR) +#endif diff --git a/lib/mac/mac_dl/mac_cell_processor.cpp b/lib/mac/mac_dl/mac_cell_processor.cpp index 5f22d8770f..4b9b869aac 100644 --- a/lib/mac/mac_dl/mac_cell_processor.cpp +++ b/lib/mac/mac_dl/mac_cell_processor.cpp @@ -13,6 +13,7 @@ #include "srsran/mac/mac_cell_result.h" #include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/support/async/execute_on_blocking.h" +#include "srsran/support/rtsan.h" using namespace srsran; @@ -208,7 +209,7 @@ async_task mac_cell_processor::remove_bearers(du_ue_index_t ue_index, span }); } -void mac_cell_processor::handle_slot_indication_impl(slot_point sl_tx) +void mac_cell_processor::handle_slot_indication_impl(slot_point sl_tx) SRSRAN_RTSAN_NONBLOCKING { // * Start of Critical Path * // diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index 48ede78c2c..033bf7d2be 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -14,6 +14,7 @@ #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/pdcp/pdcp_sn_util.h" #include "srsran/ran/pdsch/pdsch_constants.h" +#include "srsran/support/rtsan.h" #include "srsran/support/srsran_assert.h" #include "srsran/support/tracing/event_tracing.h" @@ -130,7 +131,7 @@ void rlc_tx_am_entity::discard_sdu(uint32_t pdcp_sn) } // TS 38.322 v16.2.0 Sec. 5.2.3.1 -size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) +size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) SRSRAN_RTSAN_NONBLOCKING { std::chrono::time_point pull_begin; if (metrics_low.is_enabled()) { @@ -636,7 +637,7 @@ void rlc_tx_am_entity::on_status_pdu(rlc_am_status_pdu status) } } -void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) +void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_NONBLOCKING { trace_point status_tp = l2_tracer.now(); auto t_start = std::chrono::high_resolution_clock::now(); diff --git a/tests/unittests/rlc/rlc_tx_am_test.cpp b/tests/unittests/rlc/rlc_tx_am_test.cpp index 1d61a8e409..eed89988e1 100644 --- a/tests/unittests/rlc/rlc_tx_am_test.cpp +++ b/tests/unittests/rlc/rlc_tx_am_test.cpp @@ -12,6 +12,7 @@ #include "tests/test_doubles/pdcp/pdcp_pdu_generator.h" #include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/support/executors/manual_task_worker.h" +#include "srsran/support/rtsan.h" #include #include @@ -43,6 +44,7 @@ class rlc_tx_am_test_frame : public rlc_tx_upper_layer_data_notifier, // rlc_tx_upper_layer_data_notifier interface void on_transmitted_sdu(uint32_t max_tx_pdcp_sn, uint32_t desired_buf_size) override { + SRSRAN_RTSAN_SCOPED_DISABLER(d); // store in list highest_transmitted_pdcp_sn_list.push_back(max_tx_pdcp_sn); desired_buf_size_list.push_back(desired_buf_size); @@ -50,18 +52,21 @@ class rlc_tx_am_test_frame : public rlc_tx_upper_layer_data_notifier, void on_delivered_sdu(uint32_t max_deliv_pdcp_sn) override { + SRSRAN_RTSAN_SCOPED_DISABLER(d); // store in list highest_delivered_pdcp_sn_list.push_back(max_deliv_pdcp_sn); } void on_retransmitted_sdu(uint32_t max_retx_pdcp_sn) override { + SRSRAN_RTSAN_SCOPED_DISABLER(d); // store in list highest_retransmitted_pdcp_sn_list.push_back(max_retx_pdcp_sn); } void on_delivered_retransmitted_sdu(uint32_t max_deliv_retx_pdcp_sn) override { + SRSRAN_RTSAN_SCOPED_DISABLER(d); // store in list highest_delivered_retransmitted_pdcp_sn_list.push_back(max_deliv_retx_pdcp_sn); } From 0f6d799fab88bdbfebf05fc31885b06437b9b6cf Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Mon, 4 Nov 2024 15:49:19 +0100 Subject: [PATCH 09/72] du: add the UEs defined in testmode to all cells worker_manager: added the DU multicell flag to the DU high worker manager configuration. Creates one executor mapper with all the cells executors in this case. --- apps/du/du_appconfig_translators.cpp | 7 ++-- apps/gnb/gnb_appconfig_translators.cpp | 7 ++-- apps/services/worker_manager.cpp | 42 +++++++++++++++---- apps/services/worker_manager_config.h | 2 + .../adapters/du_high_adapter_factories.h | 4 +- lib/du/du_high/du_high_impl.cpp | 28 ++++++++----- .../test_mode/mac_test_mode_adapter.cpp | 14 ++++--- .../du_high/test_mode/mac_test_mode_adapter.h | 8 ++-- .../du_high/mac_test_mode_adapter_test.cpp | 2 +- 9 files changed, 76 insertions(+), 38 deletions(-) diff --git a/apps/du/du_appconfig_translators.cpp b/apps/du/du_appconfig_translators.cpp index 917c303c1f..3e582963ba 100644 --- a/apps/du/du_appconfig_translators.cpp +++ b/apps/du/du_appconfig_translators.cpp @@ -49,7 +49,8 @@ void srsran::fill_du_worker_manager_config(worker_manager_config& config, const { srsran_assert(config.du_hi_cfg, "DU high worker config does not exist"); - config.du_hi_cfg->pdu_queue_size = unit_cfg.nru_cfg.pdu_queue_size; - config.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; - config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; + config.du_hi_cfg->pdu_queue_size = unit_cfg.nru_cfg.pdu_queue_size; + config.du_hi_cfg->is_du_multicell_enabled = unit_cfg.du_multicell_enabled; + config.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; + config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; } diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 344c61f06d..5a21dcded8 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -51,7 +51,8 @@ void srsran::fill_gnb_worker_manager_config(worker_manager_config& config, const srsran_assert(config.cu_up_cfg, "CU-UP worker config does not exist"); srsran_assert(config.du_hi_cfg, "DU high worker config does not exist"); - config.du_hi_cfg->pdu_queue_size = config.cu_up_cfg->gtpu_queue_size; - config.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; - config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; + config.du_hi_cfg->pdu_queue_size = config.cu_up_cfg->gtpu_queue_size; + config.du_hi_cfg->is_du_multicell_enabled = unit_cfg.du_multicell_enabled; + config.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; + config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; } diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager.cpp index 7745ac61da..3e8223784e 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager.cpp @@ -243,15 +243,17 @@ void worker_manager::create_du_executors(const worker_manager_config::du_high_co } // Instantiate DU-high executor mapper. - du_high_executors.resize(du_hi.nof_cells); - for (unsigned i = 0; i != du_hi.nof_cells; ++i) { - auto& du_item = du_high_executors[i]; - const std::string cell_id_str = std::to_string(i); - - // DU-high executor mapper creation. - srs_du::du_high_executor_config cfg; - cfg.cell_executors = srs_du::du_high_executor_config::dedicated_cell_worker_list{ - {*exec_map.at("slot_exec#" + cell_id_str), *exec_map.at("cell_exec#" + cell_id_str)}}; + srs_du::du_high_executor_config cfg; + if (du_hi.is_du_multicell_enabled) { + // DU multicell enabled. Create one executor mapper. + du_high_executors.resize(1); + auto& du_item = du_high_executors[0]; + srs_du::du_high_executor_config::dedicated_cell_worker_list cell_workers; + for (unsigned i = 0; i != du_hi.nof_cells; ++i) { + const std::string cell_id_str = std::to_string(i); + cell_workers.push_back({*exec_map.at("slot_exec#" + cell_id_str), *exec_map.at("cell_exec#" + cell_id_str)}); + } + cfg.cell_executors.emplace(std::move(cell_workers)); cfg.ue_executors.policy = srs_du::du_high_executor_config::ue_executor_config::map_policy::per_cell; cfg.ue_executors.max_nof_strands = 1; cfg.ue_executors.ctrl_queue_size = task_worker_queue_size; @@ -263,6 +265,28 @@ void worker_manager::create_du_executors(const worker_manager_config::du_high_co cfg.trace_exec_tasks = false; du_item.du_high_exec_mapper = srs_du::create_du_high_executor_mapper(cfg); + } else { + // DU single cell enabled. Create one executor mapper per DU/cell. + du_high_executors.resize(du_hi.nof_cells); + for (unsigned i = 0; i != du_hi.nof_cells; ++i) { + auto& du_item = du_high_executors[i]; + const std::string cell_id_str = std::to_string(i); + + // DU-high executor mapper creation. + cfg.cell_executors = srs_du::du_high_executor_config::dedicated_cell_worker_list{ + {*exec_map.at("slot_exec#" + cell_id_str), *exec_map.at("cell_exec#" + cell_id_str)}}; + cfg.ue_executors.policy = srs_du::du_high_executor_config::ue_executor_config::map_policy::per_cell; + cfg.ue_executors.max_nof_strands = 1; + cfg.ue_executors.ctrl_queue_size = task_worker_queue_size; + cfg.ue_executors.pdu_queue_size = du_hi.pdu_queue_size; + cfg.ue_executors.pool_executor = exec_map.at("low_prio_exec"); + cfg.ctrl_executors.task_queue_size = task_worker_queue_size; + cfg.ctrl_executors.pool_executor = exec_map.at("high_prio_exec"); + cfg.is_rt_mode_enabled = du_hi.is_rt_mode_enabled; + cfg.trace_exec_tasks = false; + + du_item.du_high_exec_mapper = srs_du::create_du_high_executor_mapper(cfg); + } } if (du_low) { diff --git a/apps/services/worker_manager_config.h b/apps/services/worker_manager_config.h index aa5b3bf6da..5fcdde227b 100644 --- a/apps/services/worker_manager_config.h +++ b/apps/services/worker_manager_config.h @@ -71,6 +71,8 @@ struct worker_manager_config { unsigned nof_cells; /// Real-time mode enabled flag. bool is_rt_mode_enabled; + /// Multicell DU enabled flag. + bool is_du_multicell_enabled; }; // CU-UP worker configuration diff --git a/lib/du/du_high/adapters/du_high_adapter_factories.h b/lib/du/du_high/adapters/du_high_adapter_factories.h index 6a42ac4d25..9d6fc470c7 100644 --- a/lib/du/du_high/adapters/du_high_adapter_factories.h +++ b/lib/du/du_high/adapters/du_high_adapter_factories.h @@ -18,8 +18,8 @@ namespace srsran { namespace srs_du { /// \brief Create a MAC instance for DU-high. In case the test mode is enabled, the MAC messages will be intercepted. -std::unique_ptr create_du_high_mac(const mac_config& mac_cfg, - const srs_du::du_test_mode_config& test_cfg); +std::unique_ptr +create_du_high_mac(const mac_config& mac_cfg, const srs_du::du_test_mode_config& test_cfg, unsigned nof_cells); } // namespace srs_du } // namespace srsran diff --git a/lib/du/du_high/du_high_impl.cpp b/lib/du/du_high/du_high_impl.cpp index ac5e44727e..53092c19c7 100644 --- a/lib/du/du_high/du_high_impl.cpp +++ b/lib/du/du_high/du_high_impl.cpp @@ -113,7 +113,8 @@ du_high_impl::du_high_impl(const du_high_configuration& config_) : cfg.ran.sched_cfg, cfg.sched_ue_metrics_notifier ? *cfg.sched_ue_metrics_notifier : *metrics_notifier, timers}, - cfg.test_cfg); + cfg.test_cfg, + cfg.ran.cells.size()); f1ap = create_du_high_f1ap(*cfg.f1c_client, adapters->f1_to_du_notifier, cfg.exec_mapper->du_control_executor(), @@ -166,17 +167,22 @@ void du_high_impl::start() // If test mode is enabled, create a test-mode UE by injecting a Msg3. if (cfg.test_cfg.test_ue.has_value()) { - // Push an UL-CCCH message that will trigger the creation of a UE for testing purposes. - for (unsigned ue_num = 0, nof_ues = cfg.test_cfg.test_ue->nof_ues; ue_num != nof_ues; ++ue_num) { - auto rx_buf = byte_buffer::create({0x34, 0x1e, 0x4f, 0xc0, 0x4f, 0xa6, 0x06, 0x3f, 0x00, 0x00, 0x00}); - if (not rx_buf.has_value()) { - logger.warning("Unable to allocate byte_buffer"); - continue; + for (unsigned cell_id = 0, cell_end = cfg.ran.cells.size(); cell_id != cell_end; ++cell_id) { + // Push an UL-CCCH message that will trigger the creation of a UE for testing purposes. + for (unsigned ue_num = 0, nof_ues = cfg.test_cfg.test_ue->nof_ues; ue_num != nof_ues; ++ue_num) { + auto rx_buf = byte_buffer::create({0x34, 0x1e, 0x4f, 0xc0, 0x4f, 0xa6, 0x06, 0x3f, 0x00, 0x00, 0x00}); + if (not rx_buf.has_value()) { + logger.warning("Unable to allocate byte_buffer"); + continue; + } + mac->get_pdu_handler().handle_rx_data_indication(mac_rx_data_indication{ + slot_point{0, 0}, + to_du_cell_index(cell_id), + {mac_rx_pdu{to_rnti(to_value(cfg.test_cfg.test_ue->rnti) + (cell_id * nof_ues) + ue_num), + 0, + 0, + std::move(rx_buf.value())}}}); } - mac->get_pdu_handler().handle_rx_data_indication(mac_rx_data_indication{ - slot_point{0, 0}, - to_du_cell_index(0), - {mac_rx_pdu{to_rnti(to_value(cfg.test_cfg.test_ue->rnti) + ue_num), 0, 0, std::move(rx_buf.value())}}}); } } } diff --git a/lib/du/du_high/test_mode/mac_test_mode_adapter.cpp b/lib/du/du_high/test_mode/mac_test_mode_adapter.cpp index ff1dd8db97..3f223317e0 100644 --- a/lib/du/du_high/test_mode/mac_test_mode_adapter.cpp +++ b/lib/du/du_high/test_mode/mac_test_mode_adapter.cpp @@ -61,8 +61,8 @@ size_t get_ring_size(const mac_cell_creation_request& cell_cfg) } // namespace -test_ue_info_manager::test_ue_info_manager(rnti_t rnti_start_, uint16_t nof_ues_) : - rnti_start(rnti_start_), nof_ues(nof_ues_), pending_tasks(128) +test_ue_info_manager::test_ue_info_manager(rnti_t rnti_start_, uint16_t nof_ues_, uint16_t nof_cells_) : + rnti_start(rnti_start_), nof_ues(nof_ues_), nof_cells(nof_cells_), pending_tasks(128) { } @@ -464,9 +464,10 @@ void phy_test_mode_adapter::phy_cell::on_cell_results_completion(slot_point slot // ---- mac_test_mode_adapter::mac_test_mode_adapter(const srs_du::du_test_mode_config::test_mode_ue_config& test_ue_cfg_, - mac_result_notifier& phy_notifier_) : + mac_result_notifier& phy_notifier_, + unsigned nof_cells) : test_ue(test_ue_cfg_), - ue_info_mgr(test_ue.rnti, test_ue.nof_ues), + ue_info_mgr(test_ue.rnti, test_ue.nof_ues, nof_cells), phy_notifier(std::make_unique(phy_notifier_)) { } @@ -608,14 +609,15 @@ void mac_test_mode_adapter::handle_ue_config_applied(du_ue_index_t ue_idx) } std::unique_ptr srsran::srs_du::create_du_high_mac(const mac_config& mac_cfg, - const srs_du::du_test_mode_config& test_cfg) + const srs_du::du_test_mode_config& test_cfg, + unsigned nof_cells) { if (not test_cfg.test_ue.has_value()) { return create_mac(mac_cfg); } // Create a MAC test mode adapter that wraps the real MAC. - auto mac_testmode = std::make_unique(*test_cfg.test_ue, mac_cfg.phy_notifier); + auto mac_testmode = std::make_unique(*test_cfg.test_ue, mac_cfg.phy_notifier, nof_cells); mac_testmode->connect(create_mac(mac_config{mac_cfg.ul_ccch_notifier, mac_cfg.ue_exec_mapper, mac_cfg.cell_exec_mapper, diff --git a/lib/du/du_high/test_mode/mac_test_mode_adapter.h b/lib/du/du_high/test_mode/mac_test_mode_adapter.h index 063287a7f8..85663027d6 100644 --- a/lib/du/du_high/test_mode/mac_test_mode_adapter.h +++ b/lib/du/du_high/test_mode/mac_test_mode_adapter.h @@ -26,7 +26,7 @@ namespace srs_du { class test_ue_info_manager { public: - test_ue_info_manager(rnti_t rnti_start_, uint16_t nof_ues_); + test_ue_info_manager(rnti_t rnti_start_, uint16_t nof_ues_, uint16_t nof_cells_); du_ue_index_t rnti_to_du_ue_idx(rnti_t rnti) const { @@ -40,7 +40,7 @@ class test_ue_info_manager bool is_test_ue(rnti_t rnti) const { - return (rnti >= rnti_start) and (rnti < to_rnti(to_value(rnti_start) + nof_ues)); + return (rnti >= rnti_start) and (rnti < to_rnti(to_value(rnti_start) + nof_ues * nof_cells)); } void add_ue(rnti_t rnti, du_ue_index_t ue_idx_, const sched_ue_config_request& sched_ue_cfg_req_); @@ -85,6 +85,7 @@ class test_ue_info_manager // Parameters received from configuration. rnti_t rnti_start; uint16_t nof_ues; + uint16_t nof_cells; // Mapping between UE RNTI and test UE information. std::unordered_map rnti_to_ue_info_lookup; @@ -195,7 +196,8 @@ class mac_test_mode_adapter final : public mac_interface, { public: explicit mac_test_mode_adapter(const srs_du::du_test_mode_config::test_mode_ue_config& test_ue_cfg, - mac_result_notifier& phy_notifier_); + mac_result_notifier& phy_notifier_, + unsigned nof_cells); ~mac_test_mode_adapter() override; void connect(std::unique_ptr mac_ptr); diff --git a/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp b/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp index 08956a1d33..72932593e4 100644 --- a/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp +++ b/tests/integrationtests/du_high/mac_test_mode_adapter_test.cpp @@ -146,7 +146,7 @@ static mac_uci_pdu make_random_uci_with_csi(rnti_t test_rnti = to_rnti(0x4601)) class base_mac_test_mode_test { protected: - base_mac_test_mode_test(const test_params& params_) : params(params_), adapter{params.test_ue_cfg, phy} + base_mac_test_mode_test(const test_params& params_) : params(params_), adapter{params.test_ue_cfg, phy, 1} { adapter.connect(std::make_unique(mac_events, adapter.get_phy_notifier())); From dbbb0c488e3bd2061d50e18481af77c843fc956f Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Tue, 5 Nov 2024 10:51:36 +0100 Subject: [PATCH 10/72] apps: added the worker manager service. Moved the CLI11 parsing of the isolated CPUs to the new service. Removed the gNB dependencies of the CU application. --- apps/cu/CMakeLists.txt | 3 +- apps/cu/cu.cpp | 53 +++--- apps/cu/cu_appconfig.h | 5 +- apps/cu/cu_appconfig_cli11_schema.cpp | 5 +- apps/du/CMakeLists.txt | 2 +- apps/du/du.cpp | 17 +- apps/du/du_appconfig.h | 3 +- apps/du/du_appconfig_cli11_schema.cpp | 173 +---------------- apps/du/du_appconfig_translators.cpp | 2 +- apps/gnb/CMakeLists.txt | 2 +- apps/gnb/gnb.cpp | 61 +++--- apps/gnb/gnb_appconfig.h | 33 +--- apps/gnb/gnb_appconfig_cli11_schema.cpp | 175 +----------------- apps/gnb/gnb_appconfig_translators.cpp | 2 +- apps/gnb/gnb_appconfig_translators.h | 9 - apps/services/CMakeLists.txt | 6 +- apps/services/worker_manager/CMakeLists.txt | 20 ++ .../cli11_cpu_affinities_parser_helper.cpp | 2 +- .../cli11_cpu_affinities_parser_helper.h | 0 .../os_sched_affinity_manager.h | 0 .../{ => worker_manager}/worker_manager.cpp | 2 +- .../{ => worker_manager}/worker_manager.h | 4 +- .../worker_manager/worker_manager_appconfig.h | 47 +++++ .../worker_manager_cli11_schema.cpp | 92 +++++++++ .../worker_manager_cli11_schema.h | 22 +++ .../worker_manager_config.h | 0 .../worker_manager_worker_getter.h | 0 apps/units/cu_cp/cu_cp_builder.cpp | 1 - apps/units/cu_cp/cu_cp_config_translators.cpp | 2 +- apps/units/cu_cp/cu_cp_unit_config.h | 1 - .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 1 + apps/units/cu_cp/pcap_factory.h | 2 +- apps/units/cu_up/cu_up_builder.cpp | 2 +- .../cu_up/cu_up_unit_config_translators.cpp | 2 +- apps/units/cu_up/pcap_factory.h | 2 +- apps/units/flexible_du/CMakeLists.txt | 1 - .../o_du_high/du_high/CMakeLists.txt | 2 +- .../o_du_high/du_high/du_high_config.h | 2 +- .../du_high/du_high_config_cli11_schema.cpp | 2 +- .../du_high/du_high_config_translators.cpp | 2 +- .../o_du_high/du_high/pcap_factory.h | 2 +- .../o_du_high/fapi/fapi_config_translator.cpp | 2 +- .../units/flexible_du/o_du_low/CMakeLists.txt | 2 +- .../flexible_du/o_du_low/du_low_config.h | 2 +- .../o_du_low/du_low_config_cli11_schema.cpp | 2 +- .../o_du_low/du_low_config_translator.cpp | 2 +- .../o_du_low/o_du_low_unit_factory.cpp | 2 +- .../split_7_2/helpers/CMakeLists.txt | 2 +- .../split_7_2/helpers/ru_ofh_config.h | 2 +- .../helpers/ru_ofh_config_cli11_schema.cpp | 2 +- .../helpers/ru_ofh_config_translator.cpp | 2 +- .../helpers/ru_ofh_config_validator.h | 2 +- .../split_7_2/helpers/ru_ofh_factories.cpp | 2 +- .../split_7_2_du_unit_cli11_schema.cpp | 3 - .../split_8/helpers/CMakeLists.txt | 2 +- .../split_8/helpers/ru_sdr_config.h | 3 +- .../helpers/ru_sdr_config_cli11_schema.cpp | 2 +- .../helpers/ru_sdr_config_translator.cpp | 2 +- .../split_8/helpers/ru_sdr_factories.cpp | 2 +- .../split_8/split_8_du_unit_cli11_schema.cpp | 1 - .../split_dynamic/dynamic_du_factory.cpp | 2 +- .../split_dynamic/dynamic_du_translators.cpp | 2 +- .../dynamic_du_unit_cli11_schema.cpp | 2 +- .../multicell_dynamic_du_factory.cpp | 2 +- .../split_helpers/flexible_du_factory.cpp | 2 +- .../multicell_flexible_du_factory.cpp | 8 +- .../split_helpers/o_du_high_factory.cpp | 2 +- apps/units/flexible_du/support/CMakeLists.txt | 13 -- .../du_high/du_manager/du_ue/CMakeLists.txt | 2 +- lib/f1u/CMakeLists.txt | 12 +- tests/unittests/f1u/CMakeLists.txt | 6 +- 71 files changed, 310 insertions(+), 546 deletions(-) create mode 100644 apps/services/worker_manager/CMakeLists.txt rename apps/{units/flexible_du/support => services/worker_manager}/cli11_cpu_affinities_parser_helper.cpp (98%) rename apps/{units/flexible_du/support => services/worker_manager}/cli11_cpu_affinities_parser_helper.h (100%) rename apps/services/{ => worker_manager}/os_sched_affinity_manager.h (100%) rename apps/services/{ => worker_manager}/worker_manager.cpp (99%) rename apps/services/{ => worker_manager}/worker_manager.h (98%) create mode 100644 apps/services/worker_manager/worker_manager_appconfig.h create mode 100644 apps/services/worker_manager/worker_manager_cli11_schema.cpp create mode 100644 apps/services/worker_manager/worker_manager_cli11_schema.h rename apps/services/{ => worker_manager}/worker_manager_config.h (100%) rename apps/services/{ => worker_manager}/worker_manager_worker_getter.h (100%) delete mode 100644 apps/units/flexible_du/support/CMakeLists.txt diff --git a/apps/cu/CMakeLists.txt b/apps/cu/CMakeLists.txt index 62aad010da..213cadd097 100644 --- a/apps/cu/CMakeLists.txt +++ b/apps/cu/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable(srscu cu_appconfig_cli11_schema.cpp cu_appconfig_validator.cpp cu_appconfig_yaml_writer.cpp - ../gnb/gnb_appconfig_translators.cpp ) install(TARGETS srscu @@ -27,7 +26,7 @@ target_link_libraries(srscu srsran_f1c_gateway srsran_e1_gateway srsran_e2 - srsgnb_app_f1u_cu_up_split_connector + srsran_f1u_cu_up_split_connector srsran_pcap ngap_asn1 ) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index cddd90f381..46a51411be 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -8,12 +8,35 @@ * */ +#include "apps/cu/adapters/e2_gateways.h" +#include "apps/cu/cu_appconfig_cli11_schema.h" +#include "apps/services/application_message_banners.h" +#include "apps/services/application_tracer.h" +#include "apps/services/buffer_pool/buffer_pool_manager.h" +#include "apps/services/metrics/metrics_manager.h" +#include "apps/services/metrics/metrics_notifier_proxy.h" +#include "apps/services/stdin_command_dispatcher.h" +#include "apps/services/worker_manager/worker_manager.h" +#include "apps/services/worker_manager/worker_manager_config.h" +#include "apps/units/cu_cp/cu_cp_application_unit.h" +#include "apps/units/cu_cp/cu_cp_config_translators.h" +#include "apps/units/cu_cp/cu_cp_unit_config.h" +#include "apps/units/cu_cp/pcap_factory.h" +#include "apps/units/cu_up/cu_up_application_unit.h" +#include "apps/units/cu_up/cu_up_unit_config.h" +#include "apps/units/cu_up/pcap_factory.h" +#include "cu_appconfig.h" +#include "cu_appconfig_validator.h" +#include "cu_appconfig_yaml_writer.h" +#include "srsran/cu_up/cu_up.h" +#include "srsran/e1ap/gateways/e1_local_connector_factory.h" #include "srsran/f1ap/gateways/f1c_network_server_factory.h" #include "srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h" #include "srsran/gateways/udp_network_gateway.h" #include "srsran/gtpu/gtpu_config.h" #include "srsran/gtpu/gtpu_demux_factory.h" #include "srsran/gtpu/ngu_gateway.h" +#include "srsran/ngap/gateways/n2_connection_client_factory.h" #include "srsran/pcap/dlt_pcap.h" #include "srsran/support/backtrace.h" #include "srsran/support/config_parsers.h" @@ -28,36 +51,6 @@ #include "srsran/support/tracing/event_tracing.h" #include "srsran/support/versioning/build_info.h" #include "srsran/support/versioning/version.h" - -#include "apps/cu/cu_appconfig_cli11_schema.h" -#include "apps/units/cu_cp/cu_cp_application_unit.h" -#include "apps/units/cu_cp/cu_cp_config_translators.h" -#include "apps/units/cu_cp/cu_cp_unit_config.h" -#include "apps/units/cu_cp/pcap_factory.h" -#include "apps/units/cu_up/cu_up_application_unit.h" -#include "apps/units/cu_up/cu_up_unit_config.h" -#include "apps/units/cu_up/pcap_factory.h" -#include "srsran/cu_up/cu_up.h" - -// TODO remove apps/gnb/*.h -#include "apps/cu/adapters/e2_gateways.h" -#include "apps/gnb/gnb_appconfig_translators.h" - -#include "apps/services/application_message_banners.h" -#include "apps/services/application_tracer.h" -#include "apps/services/buffer_pool/buffer_pool_manager.h" -#include "apps/services/metrics/metrics_manager.h" -#include "apps/services/metrics/metrics_notifier_proxy.h" -#include "apps/services/stdin_command_dispatcher.h" -#include "apps/services/worker_manager.h" -#include "apps/services/worker_manager_config.h" -#include "cu_appconfig.h" -#include "cu_appconfig_validator.h" -#include "cu_appconfig_yaml_writer.h" - -#include "srsran/e1ap/gateways/e1_local_connector_factory.h" -#include "srsran/ngap/gateways/n2_connection_client_factory.h" - #include #include diff --git a/apps/cu/cu_appconfig.h b/apps/cu/cu_appconfig.h index 971fdef201..5c8bab843d 100644 --- a/apps/cu/cu_appconfig.h +++ b/apps/cu/cu_appconfig.h @@ -10,9 +10,10 @@ #pragma once -#include "apps/gnb/gnb_appconfig.h" #include "apps/services/buffer_pool/buffer_pool_appconfig.h" +#include "apps/services/e2/e2_appconfig.h" #include "apps/services/logger/logger_appconfig.h" +#include "apps/services/worker_manager/worker_manager_appconfig.h" #include namespace srsran { @@ -34,7 +35,7 @@ struct cu_f1ap_appconfig { } // namespace srs_cu -/// Monolithic gnb application configuration. +/// CU application configuration. struct cu_appconfig { /// Default constructor to update the log filename. cu_appconfig() { log_cfg.filename = "/tmp/cu.log"; } diff --git a/apps/cu/cu_appconfig_cli11_schema.cpp b/apps/cu/cu_appconfig_cli11_schema.cpp index 22a8ba5dfc..b75625741c 100644 --- a/apps/cu/cu_appconfig_cli11_schema.cpp +++ b/apps/cu/cu_appconfig_cli11_schema.cpp @@ -11,9 +11,9 @@ #include "cu_appconfig_cli11_schema.h" #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" +#include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "cu_appconfig.h" #include "srsran/support/cli11_utils.h" -#include "CLI/CLI11.hpp" using namespace srsran; @@ -48,6 +48,9 @@ void srsran::configure_cli11_with_cu_appconfig_schema(CLI::App& app, cu_appconfi // Buffer pool section. configure_cli11_with_buffer_pool_appconfig_schema(app, cu_cfg.buffer_pool_config); + // Expert execution section. + configure_cli11_with_worker_manager_appconfig_schema(app, cu_cfg.expert_execution_cfg); + // F1AP section. CLI::App* cu_cp_subcmd = add_subcommand(app, "cu_cp", "CU-UP parameters")->configurable(); CLI::App* f1ap_subcmd = add_subcommand(*cu_cp_subcmd, "f1ap", "F1AP parameters")->configurable(); diff --git a/apps/du/CMakeLists.txt b/apps/du/CMakeLists.txt index 71a5ac3049..fa2da38faa 100644 --- a/apps/du/CMakeLists.txt +++ b/apps/du/CMakeLists.txt @@ -19,7 +19,7 @@ install(TARGETS srsdu target_link_libraries(srsdu srsran_app_services - srsgnb_app_f1u_du_split_connector + srsran_f1u_du_split_connector srsran_cu_cp srsran_network srsran_e2 diff --git a/apps/du/du.cpp b/apps/du/du.cpp index a93c7c7566..ebc2893771 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -29,21 +29,13 @@ #include "du_appconfig_translators.h" #include "du_appconfig_validators.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/split_dynamic/dynamic_du_factory.h" #include "apps/du/adapters/e2_gateways.h" #include "apps/services/e2/e2_metric_connector_manager.h" #include "srsran/e2/gateways/e2_connection_client.h" -// Include ThreadSanitizer (TSAN) options if thread sanitization is enabled. -// This include is not unused - it helps prevent false alarms from the thread sanitizer. -#include "du_appconfig_yaml_writer.h" - -#include "srsran/support/tsan_options.h" - -#include - #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" @@ -54,12 +46,15 @@ #include "apps/units/flexible_du/flexible_du_application_unit.h" #include "apps/units/flexible_du/o_du_high/du_high/du_high_config.h" #include "apps/units/flexible_du/o_du_high/du_high/pcap_factory.h" - +#include "du_appconfig_yaml_writer.h" #include "srsran/du/du_power_controller.h" - +#include #ifdef DPDK_FOUND #include "srsran/hal/dpdk/dpdk_eal_factory.h" #endif +// Include ThreadSanitizer (TSAN) options if thread sanitization is enabled. +// This include is not unused - it helps prevent false alarms from the thread sanitizer. +#include "srsran/support/tsan_options.h" using namespace srsran; diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index 861437ea99..5f2e36872b 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -13,8 +13,7 @@ #include "../gnb/gnb_appconfig.h" // TODO: Remove #include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/logger/logger_appconfig.h" -#include "apps/services/os_sched_affinity_manager.h" -#include "srsran/support/executors/unique_thread.h" +#include "apps/services/worker_manager/worker_manager_appconfig.h" #include namespace srsran { diff --git a/apps/du/du_appconfig_cli11_schema.cpp b/apps/du/du_appconfig_cli11_schema.cpp index 2d2c59332d..d6664c9ee0 100644 --- a/apps/du/du_appconfig_cli11_schema.cpp +++ b/apps/du/du_appconfig_cli11_schema.cpp @@ -11,24 +11,13 @@ #include "du_appconfig_cli11_schema.h" #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" +#include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "du_appconfig.h" #include "srsran/adt/interval.h" #include "srsran/support/cli11_utils.h" using namespace srsran; -template -static expected parse_int(const std::string& value) -{ - try { - return std::stoi(value); - } catch (const std::invalid_argument& e) { - return make_unexpected(e.what()); - } catch (const std::out_of_range& e) { - return make_unexpected(e.what()); - } -} - static void configure_cli11_metrics_args(CLI::App& app, srs_du::metrics_appconfig& metrics_params) { app.add_option("--addr", metrics_params.addr, "Metrics address.")->capture_default_str()->check(CLI::ValidIPV4); @@ -56,159 +45,6 @@ static void configure_cli11_e2_args(CLI::App& app, e2_appconfig& e2_params) add_option(app, "--e2sm_rc_enabled", e2_params.e2sm_rc_enabled, "Enable RC service module")->capture_default_str(); } -static error_type is_valid_cpu_index(unsigned cpu_idx) -{ - std::string error_message = fmt::format("Invalid CPU core selected '{}'. Valid CPU ids: {}", - cpu_idx, - os_sched_affinity_bitmask::available_cpus().get_cpu_ids()); - - os_sched_affinity_bitmask one_cpu_mask; - if (cpu_idx >= one_cpu_mask.size()) { - return make_unexpected(error_message); - } - one_cpu_mask.set(cpu_idx); - if (not one_cpu_mask.subtract(os_sched_affinity_bitmask::available_cpus()).empty()) { - return make_unexpected(error_message); - } - return default_success_t(); -} - -static expected parse_one_cpu(const std::string& value) -{ - expected result = parse_int(value); - - if (not result.has_value()) { - return make_unexpected(fmt::format("Could not parse '{}' string as a CPU index", value)); - } - - error_type validation_result = is_valid_cpu_index(result.value()); - if (not validation_result.has_value()) { - return make_unexpected(validation_result.error()); - } - - return result.value(); -} - -static expected, std::string> parse_cpu_range(const std::string& value) -{ - std::vector range; - std::stringstream ss(value); - while (ss.good()) { - std::string str; - getline(ss, str, '-'); - auto parse_result = parse_one_cpu(str); - if (not parse_result.has_value()) { - return make_unexpected(fmt::format("{}. Could not parse '{}' as a range", parse_result.error(), value)); - } - - range.push_back(parse_result.value()); - } - - // A range is defined by two numbers. - if (range.size() != 2) { - return make_unexpected(fmt::format("Could not parse '{}' as a range", value)); - } - - if (range[1] <= range[0]) { - return make_unexpected(fmt::format("Invalid CPU core range detected [{}-{}]", range[0], range[1])); - } - - return interval(range[0], range[1]); -} - -static void -parse_affinity_mask(os_sched_affinity_bitmask& mask, const std::string& value, const std::string& property_name) -{ - std::stringstream ss(value); - - while (ss.good()) { - std::string str; - getline(ss, str, ','); - if (str.find('-') != std::string::npos) { - auto range = parse_cpu_range(str); - if (not range.has_value()) { - report_error("{} in the '{}' property", range.error(), property_name); - } - - // Add 1 to the stop value as the fill method excludes the end position. - mask.fill(range.value().start(), range.value().stop() + 1); - } else { - auto cpu_idx = parse_one_cpu(str); - if (not cpu_idx.has_value()) { - report_error("{} in the '{}' property", cpu_idx.error(), property_name); - } - - mask.set(cpu_idx.value()); - } - } -} - -static void configure_cli11_cpu_affinities_args(CLI::App& app, cpu_affinities_appconfig& config) -{ - auto parsing_isolated_cpus_fcn = [](std::optional& isolated_cpu_cfg, - const std::string& value, - const std::string& property_name) { - isolated_cpu_cfg.emplace(); - parse_affinity_mask(*isolated_cpu_cfg, value, property_name); - - if (isolated_cpu_cfg->all()) { - report_error("Error in '{}' property: can not assign all available CPUs to the gNB app", property_name); - } - }; - - add_option_function( - app, - "--isolated_cpus", - [&config, &parsing_isolated_cpus_fcn](const std::string& value) { - parsing_isolated_cpus_fcn(config.isolated_cpus, value, "isolated_cpus"); - }, - "CPU cores isolated for gNB application"); - - add_option_function( - app, - "--low_priority_cpus", - [&config](const std::string& value) { - parse_affinity_mask(config.low_priority_cpu_cfg.mask, value, "low_priority_cpus"); - }, - "CPU cores assigned to low priority tasks"); - - add_option_function( - app, - "--low_priority_pinning", - [&config](const std::string& value) { - config.low_priority_cpu_cfg.pinning_policy = to_affinity_mask_policy(value); - if (config.low_priority_cpu_cfg.pinning_policy == sched_affinity_mask_policy::last) { - report_error("Incorrect value={} used in {} property", value, "low_priority_pinning"); - } - }, - "Policy used for assigning CPU cores to low priority tasks"); -} - -static void configure_cli11_non_rt_threads_args(CLI::App& app, non_rt_threads_appconfig& config) -{ - add_option(app, - "--nof_non_rt_threads", - config.nof_non_rt_threads, - "Number of non real time threads for processing of CP and UP data in upper layers.") - ->capture_default_str() - ->check(CLI::Number); -} - -static void configure_cli11_expert_execution_args(CLI::App& app, expert_execution_appconfig& config) -{ - // Affinity section. - CLI::App* affinities_subcmd = add_subcommand(app, "affinities", "gNB CPU affinities configuration")->configurable(); - configure_cli11_cpu_affinities_args(*affinities_subcmd, config.affinities); - - // Threads section. - CLI::App* threads_subcmd = add_subcommand(app, "threads", "Threads configuration")->configurable(); - - // Non real time threads. - CLI::App* non_rt_threads_subcmd = - add_subcommand(*threads_subcmd, "non_rt", "Non real time thread configuration")->configurable(); - configure_cli11_non_rt_threads_args(*non_rt_threads_subcmd, config.threads.non_rt_threads); -} - static void configure_cli11_f1ap_args(CLI::App& app, srs_du::f1ap_appconfig& f1c_params) { app.add_option("--cu_cp_addr", f1c_params.cu_cp_address, "CU-CP F1-C address to connect to")->capture_default_str(); @@ -249,6 +85,9 @@ void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfi // Buffer pool section. configure_cli11_with_buffer_pool_appconfig_schema(app, du_cfg.buffer_pool_config); + // Expert execution section. + configure_cli11_with_worker_manager_appconfig_schema(app, du_cfg.expert_execution_cfg); + // F1-C section. CLI::App* f1ap_subcmd = app.add_subcommand("f1ap", "F1AP interface configuration")->configurable(); configure_cli11_f1ap_args(*f1ap_subcmd, du_cfg.f1ap_cfg); @@ -265,10 +104,6 @@ void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfi CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); configure_cli11_e2_args(*e2_subcmd, du_cfg.e2_cfg); - // Expert section. - CLI::App* expert_subcmd = app.add_subcommand("expert_execution", "Expert execution configuration")->configurable(); - configure_cli11_expert_execution_args(*expert_subcmd, du_cfg.expert_execution_cfg); - // HAL section. CLI::App* hal_subcmd = add_subcommand(app, "hal", "HAL configuration")->configurable(); configure_cli11_hal_args(*hal_subcmd, du_cfg.hal_config); diff --git a/apps/du/du_appconfig_translators.cpp b/apps/du/du_appconfig_translators.cpp index 3e582963ba..94bbf83c91 100644 --- a/apps/du/du_appconfig_translators.cpp +++ b/apps/du/du_appconfig_translators.cpp @@ -9,7 +9,7 @@ */ #include "du_appconfig_translators.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "du_appconfig.h" using namespace srsran; diff --git a/apps/gnb/CMakeLists.txt b/apps/gnb/CMakeLists.txt index 45f7db3009..b05179eb24 100644 --- a/apps/gnb/CMakeLists.txt +++ b/apps/gnb/CMakeLists.txt @@ -19,7 +19,7 @@ install(TARGETS gnb target_link_libraries(gnb srsran_app_services - srsgnb_app_f1u_connector + srsran_f1u_connector srsran_cu_cp srsran_network srsran_ngap diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index e77a72d3f3..136ceb8185 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -8,29 +8,8 @@ * */ -#include "srsran/support/backtrace.h" -#include "srsran/support/config_parsers.h" -#include "srsran/support/cpu_features.h" -#include "srsran/support/dynlink_manager.h" -#include "srsran/support/io/io_broker_factory.h" -#include "srsran/support/signal_handling.h" -#include "srsran/support/tracing/event_tracing.h" -#include "srsran/support/versioning/build_info.h" -#include "srsran/support/versioning/version.h" - -#include "srsran/du/du_power_controller.h" -#include "srsran/e1ap/gateways/e1_local_connector_factory.h" -#include "srsran/f1ap/gateways/f1c_local_connector_factory.h" -#include "srsran/f1u/local_connector/f1u_local_connector.h" -#include "srsran/gtpu/ngu_gateway.h" -#include "srsran/ngap/gateways/n2_connection_client_factory.h" - -#include "gnb_appconfig.h" -#include "gnb_appconfig_cli11_schema.h" -#include "gnb_appconfig_translators.h" -#include "gnb_appconfig_validators.h" -#include "gnb_appconfig_yaml_writer.h" - +#include "apps/cu/adapters/e2_gateways.h" +#include "apps/du/adapters/e2_gateways.h" #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" @@ -39,16 +18,7 @@ #include "apps/services/metrics/metrics_manager.h" #include "apps/services/metrics/metrics_notifier_proxy.h" #include "apps/services/stdin_command_dispatcher.h" -#include "apps/services/worker_manager.h" - -#include "apps/cu/adapters/e2_gateways.h" -#include "apps/du/adapters/e2_gateways.h" -#include "apps/services/e2/e2_metric_connector_manager.h" - -// Include ThreadSanitizer (TSAN) options if thread sanitization is enabled. -// This include is not unused - it helps prevent false alarms from the thread sanitizer. -#include "srsran/support/tsan_options.h" - +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/cu_cp/cu_cp_application_unit.h" #include "apps/units/cu_cp/cu_cp_config_translators.h" #include "apps/units/cu_cp/cu_cp_unit_config.h" @@ -59,13 +29,34 @@ #include "apps/units/flexible_du/flexible_du_application_unit.h" #include "apps/units/flexible_du/o_du_high/du_high/du_high_config.h" #include "apps/units/flexible_du/o_du_high/du_high/pcap_factory.h" - +#include "gnb_appconfig.h" +#include "gnb_appconfig_cli11_schema.h" +#include "gnb_appconfig_translators.h" +#include "gnb_appconfig_validators.h" +#include "gnb_appconfig_yaml_writer.h" +#include "srsran/du/du_power_controller.h" +#include "srsran/e1ap/gateways/e1_local_connector_factory.h" +#include "srsran/f1ap/gateways/f1c_local_connector_factory.h" +#include "srsran/f1u/local_connector/f1u_local_connector.h" +#include "srsran/gtpu/ngu_gateway.h" +#include "srsran/ngap/gateways/n2_connection_client_factory.h" +#include "srsran/support/backtrace.h" +#include "srsran/support/config_parsers.h" +#include "srsran/support/cpu_features.h" +#include "srsran/support/dynlink_manager.h" +#include "srsran/support/io/io_broker_factory.h" +#include "srsran/support/signal_handling.h" +#include "srsran/support/tracing/event_tracing.h" +#include "srsran/support/versioning/build_info.h" +#include "srsran/support/versioning/version.h" #include #include - #ifdef DPDK_FOUND #include "srsran/hal/dpdk/dpdk_eal_factory.h" #endif +// Include ThreadSanitizer (TSAN) options if thread sanitization is enabled. +// This include is not unused - it helps prevent false alarms from the thread sanitizer. +#include "srsran/support/tsan_options.h" using namespace srsran; diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 4cea348fc4..ba309402a2 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -13,9 +13,8 @@ #include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/e2/e2_appconfig.h" #include "apps/services/logger/logger_appconfig.h" -#include "apps/services/os_sched_affinity_manager.h" +#include "apps/services/worker_manager/worker_manager_appconfig.h" #include "srsran/ran/gnb_id.h" -#include "srsran/support/executors/unique_thread.h" #include namespace srsran { @@ -32,36 +31,6 @@ struct metrics_appconfig { uint16_t port = 55555; }; -/// CPU affinities configuration for the gNB app. -struct cpu_affinities_appconfig { - /// CPUs isolation. - std::optional isolated_cpus; - /// Low priority workers CPU affinity mask. - os_sched_affinity_config low_priority_cpu_cfg = {sched_affinity_mask_types::low_priority, - {}, - sched_affinity_mask_policy::mask}; -}; - -/// Non real time thread configuration for the gNB. -struct non_rt_threads_appconfig { - /// Number of non real time threads for processing of CP and UP data in the upper layers - unsigned nof_non_rt_threads = 4; -}; - -/// Expert threads configuration of the gNB app. -struct expert_threads_appconfig { - /// Non real time thread configuration of the gNB app. - non_rt_threads_appconfig non_rt_threads; -}; - -/// Expert configuration of the gNB app. -struct expert_execution_appconfig { - /// gNB CPU affinities. - cpu_affinities_appconfig affinities; - /// Expert thread configuration of the gNB app. - expert_threads_appconfig threads; -}; - /// HAL configuration of the gNB app. struct hal_appconfig { /// EAL configuration arguments. diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 158e19a018..5c19676956 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -11,26 +11,13 @@ #include "gnb_appconfig_cli11_schema.h" #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" +#include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "gnb_appconfig.h" -#include "srsran/adt/interval.h" #include "srsran/support/cli11_utils.h" -#include "srsran/support/error_handling.h" #include "CLI/CLI11.hpp" using namespace srsran; -template -static expected parse_int(const std::string& value) -{ - try { - return std::stoi(value); - } catch (const std::invalid_argument& e) { - return make_unexpected(e.what()); - } catch (const std::out_of_range& e) { - return make_unexpected(e.what()); - } -} - static void configure_cli11_metrics_args(CLI::App& app, metrics_appconfig& metrics_params) { app.add_option("--addr", metrics_params.addr, "Metrics address.")->capture_default_str(); @@ -66,159 +53,6 @@ static void configure_cli11_hal_args(CLI::App& app, std::optional add_option(app, "--eal_args", config->eal_args, "EAL configuration parameters used to initialize DPDK"); } -static error_type is_valid_cpu_index(unsigned cpu_idx) -{ - std::string error_message = fmt::format("Invalid CPU core selected '{}'. Valid CPU ids: {}", - cpu_idx, - os_sched_affinity_bitmask::available_cpus().get_cpu_ids()); - - os_sched_affinity_bitmask one_cpu_mask; - if (cpu_idx >= one_cpu_mask.size()) { - return make_unexpected(error_message); - } - one_cpu_mask.set(cpu_idx); - if (not one_cpu_mask.subtract(os_sched_affinity_bitmask::available_cpus()).empty()) { - return make_unexpected(error_message); - } - return default_success_t(); -} - -static expected parse_one_cpu(const std::string& value) -{ - expected result = parse_int(value); - - if (not result.has_value()) { - return make_unexpected(fmt::format("Could not parse '{}' string as a CPU index", value)); - } - - error_type validation_result = is_valid_cpu_index(result.value()); - if (not validation_result.has_value()) { - return make_unexpected(validation_result.error()); - } - - return result.value(); -} - -static expected, std::string> parse_cpu_range(const std::string& value) -{ - std::vector range; - std::stringstream ss(value); - while (ss.good()) { - std::string str; - getline(ss, str, '-'); - auto parse_result = parse_one_cpu(str); - if (not parse_result.has_value()) { - return make_unexpected(fmt::format("{}. Could not parse '{}' as a range", parse_result.error(), value)); - } - - range.push_back(parse_result.value()); - } - - // A range is defined by two numbers. - if (range.size() != 2) { - return make_unexpected(fmt::format("Could not parse '{}' as a range", value)); - } - - if (range[1] <= range[0]) { - return make_unexpected(fmt::format("Invalid CPU core range detected [{}-{}]", range[0], range[1])); - } - - return interval(range[0], range[1]); -} - -static void -parse_affinity_mask(os_sched_affinity_bitmask& mask, const std::string& value, const std::string& property_name) -{ - std::stringstream ss(value); - - while (ss.good()) { - std::string str; - getline(ss, str, ','); - if (str.find('-') != std::string::npos) { - auto range = parse_cpu_range(str); - if (not range.has_value()) { - report_error("{} in the '{}' property", range.error(), property_name); - } - - // Add 1 to the stop value as the fill method excludes the end position. - mask.fill(range.value().start(), range.value().stop() + 1); - } else { - auto cpu_idx = parse_one_cpu(str); - if (not cpu_idx.has_value()) { - report_error("{} in the '{}' property", cpu_idx.error(), property_name); - } - - mask.set(cpu_idx.value()); - } - } -} - -static void configure_cli11_non_rt_threads_args(CLI::App& app, non_rt_threads_appconfig& config) -{ - add_option(app, - "--nof_non_rt_threads", - config.nof_non_rt_threads, - "Number of non real time threads for processing of CP and UP data in upper layers.") - ->capture_default_str() - ->check(CLI::Number); -} - -static void configure_cli11_cpu_affinities_args(CLI::App& app, cpu_affinities_appconfig& config) -{ - auto parsing_isolated_cpus_fcn = [](std::optional& isolated_cpu_cfg, - const std::string& value, - const std::string& property_name) { - isolated_cpu_cfg.emplace(); - parse_affinity_mask(*isolated_cpu_cfg, value, property_name); - - if (isolated_cpu_cfg->all()) { - report_error("Error in '{}' property: can not assign all available CPUs to the gNB app", property_name); - } - }; - - add_option_function( - app, - "--isolated_cpus", - [&config, &parsing_isolated_cpus_fcn](const std::string& value) { - parsing_isolated_cpus_fcn(config.isolated_cpus, value, "isolated_cpus"); - }, - "CPU cores isolated for gNB application"); - - add_option_function( - app, - "--low_priority_cpus", - [&config](const std::string& value) { - parse_affinity_mask(config.low_priority_cpu_cfg.mask, value, "low_priority_cpus"); - }, - "CPU cores assigned to low priority tasks"); - - add_option_function( - app, - "--low_priority_pinning", - [&config](const std::string& value) { - config.low_priority_cpu_cfg.pinning_policy = to_affinity_mask_policy(value); - if (config.low_priority_cpu_cfg.pinning_policy == sched_affinity_mask_policy::last) { - report_error("Incorrect value={} used in {} property", value, "low_priority_pinning"); - } - }, - "Policy used for assigning CPU cores to low priority tasks"); -} - -static void configure_cli11_expert_execution_args(CLI::App& app, expert_execution_appconfig& config) -{ - // Affinity section. - CLI::App* affinities_subcmd = add_subcommand(app, "affinities", "gNB CPU affinities configuration")->configurable(); - configure_cli11_cpu_affinities_args(*affinities_subcmd, config.affinities); - - // Threads section. - CLI::App* threads_subcmd = add_subcommand(app, "threads", "Threads configuration")->configurable(); - - // Non real time threads. - CLI::App* non_rt_threads_subcmd = - add_subcommand(*threads_subcmd, "non_rt", "Non real time thread configuration")->configurable(); - configure_cli11_non_rt_threads_args(*non_rt_threads_subcmd, config.threads.non_rt_threads); -} - static void manage_hal_optional(CLI::App& app, gnb_appconfig& gnb_cfg) { // Clean the HAL optional. @@ -247,6 +81,9 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon // Buffer pool section. configure_cli11_with_buffer_pool_appconfig_schema(app, gnb_cfg.buffer_pool_config); + // Expert execution section. + configure_cli11_with_worker_manager_appconfig_schema(app, gnb_cfg.expert_execution_cfg); + // Metrics section. CLI::App* metrics_subcmd = app.add_subcommand("metrics", "Metrics configuration")->configurable(); configure_cli11_metrics_args(*metrics_subcmd, gnb_cfg.metrics_cfg); @@ -255,10 +92,6 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); configure_cli11_e2_args(*e2_subcmd, gnb_cfg.e2_cfg); - // Expert section. - CLI::App* expert_subcmd = app.add_subcommand("expert_execution", "Expert execution configuration")->configurable(); - configure_cli11_expert_execution_args(*expert_subcmd, gnb_cfg.expert_execution_cfg); - // HAL section. CLI::App* hal_subcmd = add_subcommand(app, "hal", "HAL configuration")->configurable(); configure_cli11_hal_args(*hal_subcmd, gnb_cfg.hal_config); diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 5a21dcded8..1812d8b571 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -9,7 +9,7 @@ */ #include "gnb_appconfig_translators.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "apps/units/cu_cp/cu_cp_unit_config.h" #include "gnb_appconfig.h" #include "srsran/ran/subcarrier_spacing.h" diff --git a/apps/gnb/gnb_appconfig_translators.h b/apps/gnb/gnb_appconfig_translators.h index 197a7aadbf..7c3e440c59 100644 --- a/apps/gnb/gnb_appconfig_translators.h +++ b/apps/gnb/gnb_appconfig_translators.h @@ -12,16 +12,7 @@ #include "apps/services/e2/e2_appconfig.h" #include "srsran/cu_cp/cu_cp_configuration.h" -#include "srsran/cu_up/cu_up_configuration.h" -#include "srsran/du/du_cell_config.h" -#include "srsran/du/du_high/du_qos_config.h" -#include "srsran/du/du_high/du_srb_config.h" #include "srsran/gateways/sctp_network_gateway.h" -#include "srsran/mac/mac_config.h" -#include "srsran/phy/upper/upper_phy_factories.h" -#include "srsran/ru/ru_configuration.h" -#include -#include namespace srsran { diff --git a/apps/services/CMakeLists.txt b/apps/services/CMakeLists.txt index 2b3859c52d..98b5367f9f 100644 --- a/apps/services/CMakeLists.txt +++ b/apps/services/CMakeLists.txt @@ -8,14 +8,14 @@ add_subdirectory(buffer_pool) add_subdirectory(logger) +add_subdirectory(worker_manager) set(SOURCES - stdin_command_dispatcher.cpp - worker_manager.cpp) + stdin_command_dispatcher.cpp) add_library(srsran_app_services STATIC ${SOURCES}) target_include_directories(srsran_app_services PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(srsran_app_services srsran_logger_app_service srsran_buffer_pool_app_service - srsran_du_high) # TODO: Temp + srsran_worker_manager_service) diff --git a/apps/services/worker_manager/CMakeLists.txt b/apps/services/worker_manager/CMakeLists.txt new file mode 100644 index 0000000000..1d5608a063 --- /dev/null +++ b/apps/services/worker_manager/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +set(SOURCES + worker_manager.cpp + worker_manager_cli11_schema.cpp) + +add_library(srsran_cpu_affinities_helper STATIC cli11_cpu_affinities_parser_helper.cpp) + +add_library(srsran_worker_manager_service STATIC ${SOURCES}) +target_include_directories(srsran_worker_manager_service PRIVATE ${CMAKE_SOURCE_DIR}) +target_link_libraries(srsran_worker_manager_service + srsran_cpu_affinities_helper + srsran_du_high # TODO: Temp + srsran_cu_up) # TODO: Temp diff --git a/apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.cpp b/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp similarity index 98% rename from apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.cpp rename to apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp index 231b3175e4..cecf4cfadf 100644 --- a/apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.cpp +++ b/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp @@ -9,7 +9,7 @@ */ #include "cli11_cpu_affinities_parser_helper.h" -#include "apps/services/os_sched_affinity_manager.h" +#include "os_sched_affinity_manager.h" #include "srsran/adt/expected.h" #include "srsran/adt/interval.h" diff --git a/apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h b/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h similarity index 100% rename from apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h rename to apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h diff --git a/apps/services/os_sched_affinity_manager.h b/apps/services/worker_manager/os_sched_affinity_manager.h similarity index 100% rename from apps/services/os_sched_affinity_manager.h rename to apps/services/worker_manager/os_sched_affinity_manager.h diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager/worker_manager.cpp similarity index 99% rename from apps/services/worker_manager.cpp rename to apps/services/worker_manager/worker_manager.cpp index 3e8223784e..3655b7921a 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager/worker_manager.cpp @@ -553,7 +553,7 @@ void worker_manager::create_lower_phy_executors(const worker_manager_config::ru_ { using namespace execution_config_helper; - // Radio Unit worker and executor. As the radio is unique per gNB, use the first cell of the affinity manager. + // Radio Unit worker and executor. As the radio is unique per application, use the first cell of the affinity manager. create_prio_worker("radio", task_worker_queue_size, {{"radio_exec"}}, diff --git a/apps/services/worker_manager.h b/apps/services/worker_manager/worker_manager.h similarity index 98% rename from apps/services/worker_manager.h rename to apps/services/worker_manager/worker_manager.h index 19235c5612..ef2149c5e4 100644 --- a/apps/services/worker_manager.h +++ b/apps/services/worker_manager/worker_manager.h @@ -10,8 +10,8 @@ #pragma once -#include "apps/services/worker_manager_config.h" -#include "apps/services/worker_manager_worker_getter.h" +#include "worker_manager_config.h" +#include "worker_manager_worker_getter.h" #include "srsran/cu_up/cu_up_executor_mapper.h" #include "srsran/du/du_high/du_high_executor_mapper.h" #include "srsran/support/executors/task_execution_manager.h" diff --git a/apps/services/worker_manager/worker_manager_appconfig.h b/apps/services/worker_manager/worker_manager_appconfig.h new file mode 100644 index 0000000000..43e24dbf53 --- /dev/null +++ b/apps/services/worker_manager/worker_manager_appconfig.h @@ -0,0 +1,47 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "os_sched_affinity_manager.h" + +namespace srsran { + +/// CPU affinities configuration for the application. +struct cpu_affinities_appconfig { + /// CPUs isolation. + std::optional isolated_cpus; + /// Low priority workers CPU affinity mask. + os_sched_affinity_config low_priority_cpu_cfg = {sched_affinity_mask_types::low_priority, + {}, + sched_affinity_mask_policy::mask}; +}; + +/// Non real time thread configuration for the application. +struct non_rt_threads_appconfig { + /// Number of non real time threads for processing of CP and UP data in the upper layers + unsigned nof_non_rt_threads = 4; +}; + +/// Expert threads configuration of the application. +struct expert_threads_appconfig { + /// Non real time thread configuration of the application. + non_rt_threads_appconfig non_rt_threads; +}; + +/// Expert configuration of the application. +struct expert_execution_appconfig { + /// Application CPU affinities. + cpu_affinities_appconfig affinities; + /// Expert thread configuration of the application. + expert_threads_appconfig threads; +}; + +} // namespace srsran diff --git a/apps/services/worker_manager/worker_manager_cli11_schema.cpp b/apps/services/worker_manager/worker_manager_cli11_schema.cpp new file mode 100644 index 0000000000..d2f2ab5b15 --- /dev/null +++ b/apps/services/worker_manager/worker_manager_cli11_schema.cpp @@ -0,0 +1,92 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "worker_manager_cli11_schema.h" +#include "cli11_cpu_affinities_parser_helper.h" +#include "worker_manager_appconfig.h" +#include "srsran/adt/expected.h" +#include "srsran/support/cli11_utils.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; + +static void configure_cli11_non_rt_threads_args(CLI::App& app, non_rt_threads_appconfig& config) +{ + add_option(app, + "--nof_non_rt_threads", + config.nof_non_rt_threads, + "Number of non real time threads for processing of CP and UP data in upper layers.") + ->capture_default_str() + ->check(CLI::Number); +} + +static void configure_cli11_cpu_affinities_args(CLI::App& app, cpu_affinities_appconfig& config) +{ + auto parsing_isolated_cpus_fcn = [](std::optional& isolated_cpu_cfg, + const std::string& value, + const std::string& property_name) { + isolated_cpu_cfg.emplace(); + parse_affinity_mask(*isolated_cpu_cfg, value, property_name); + + if (isolated_cpu_cfg->all()) { + report_error("Error in '{}' property: can not assign all available CPUs to the application", property_name); + } + }; + + add_option_function( + app, + "--isolated_cpus", + [&config, &parsing_isolated_cpus_fcn](const std::string& value) { + parsing_isolated_cpus_fcn(config.isolated_cpus, value, "isolated_cpus"); + }, + "CPU cores isolated for application"); + + add_option_function( + app, + "--low_priority_cpus", + [&config](const std::string& value) { + parse_affinity_mask(config.low_priority_cpu_cfg.mask, value, "low_priority_cpus"); + }, + "CPU cores assigned to low priority tasks"); + + add_option_function( + app, + "--low_priority_pinning", + [&config](const std::string& value) { + config.low_priority_cpu_cfg.pinning_policy = to_affinity_mask_policy(value); + if (config.low_priority_cpu_cfg.pinning_policy == sched_affinity_mask_policy::last) { + report_error("Incorrect value={} used in {} property", value, "low_priority_pinning"); + } + }, + "Policy used for assigning CPU cores to low priority tasks"); +} + +static void configure_cli11_expert_execution_args(CLI::App& app, expert_execution_appconfig& config) +{ + // Affinity section. + CLI::App* affinities_subcmd = + add_subcommand(app, "affinities", "Application CPU affinities configuration")->configurable(); + configure_cli11_cpu_affinities_args(*affinities_subcmd, config.affinities); + + // Threads section. + CLI::App* threads_subcmd = add_subcommand(app, "threads", "Threads configuration")->configurable(); + + // Non real time threads. + CLI::App* non_rt_threads_subcmd = + add_subcommand(*threads_subcmd, "non_rt", "Non real time thread configuration")->configurable(); + configure_cli11_non_rt_threads_args(*non_rt_threads_subcmd, config.threads.non_rt_threads); +} + +void srsran::configure_cli11_with_worker_manager_appconfig_schema(CLI::App& app, expert_execution_appconfig& config) +{ + // Expert section. + CLI::App* expert_subcmd = app.add_subcommand("expert_execution", "Expert execution configuration")->configurable(); + configure_cli11_expert_execution_args(*expert_subcmd, config); +} diff --git a/apps/services/worker_manager/worker_manager_cli11_schema.h b/apps/services/worker_manager/worker_manager_cli11_schema.h new file mode 100644 index 0000000000..f0ceb532c3 --- /dev/null +++ b/apps/services/worker_manager/worker_manager_cli11_schema.h @@ -0,0 +1,22 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "CLI/CLI11.hpp" + +namespace srsran { + +struct expert_execution_appconfig; + +/// Configures the given CLI11 application with the worker manager application configuration schema. +void configure_cli11_with_worker_manager_appconfig_schema(CLI::App& app, expert_execution_appconfig& config); + +} // namespace srsran diff --git a/apps/services/worker_manager_config.h b/apps/services/worker_manager/worker_manager_config.h similarity index 100% rename from apps/services/worker_manager_config.h rename to apps/services/worker_manager/worker_manager_config.h diff --git a/apps/services/worker_manager_worker_getter.h b/apps/services/worker_manager/worker_manager_worker_getter.h similarity index 100% rename from apps/services/worker_manager_worker_getter.h rename to apps/services/worker_manager/worker_manager_worker_getter.h diff --git a/apps/units/cu_cp/cu_cp_builder.cpp b/apps/units/cu_cp/cu_cp_builder.cpp index c89ae02a83..bc62f093a7 100644 --- a/apps/units/cu_cp/cu_cp_builder.cpp +++ b/apps/units/cu_cp/cu_cp_builder.cpp @@ -13,7 +13,6 @@ #include "apps/units/cu_cp/cu_cp_unit_config.h" #include "cu_cp_commands.h" #include "cu_cp_config_translators.h" -#include "cu_cp_unit_config.h" #include "cu_cp_wrapper.h" #include "srsran/cu_cp/cu_cp_factory.h" #include "srsran/e2/e2_cu_metrics_connector.h" diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index d2aca70acf..dafbc2f15a 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -9,7 +9,7 @@ */ #include "cu_cp_config_translators.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "cu_cp_unit_config.h" #include "srsran/cu_cp/cu_cp_configuration_helpers.h" #include "srsran/ran/plmn_identity.h" diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index a7164531ab..3d42f3e4b8 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -14,7 +14,6 @@ #include "cu_cp_unit_logger_config.h" #include "srsran/e2/e2ap_configuration.h" #include "srsran/ran/nr_band.h" -#include "srsran/ran/nr_cell_identity.h" #include "srsran/ran/pci.h" #include "srsran/ran/qos/five_qi.h" #include "srsran/ran/s_nssai.h" diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp index cfeca6e043..b89b65231d 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -11,6 +11,7 @@ #include "cu_cp_unit_config_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_utils.h" #include "cu_cp_unit_config.h" +#include "srsran/ran/nr_cell_identity.h" #include "srsran/support/cli11_utils.h" #include "srsran/support/config_parsers.h" diff --git a/apps/units/cu_cp/pcap_factory.h b/apps/units/cu_cp/pcap_factory.h index d46bd696ce..9abb07830e 100644 --- a/apps/units/cu_cp/pcap_factory.h +++ b/apps/units/cu_cp/pcap_factory.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/worker_manager_worker_getter.h" +#include "apps/services/worker_manager/worker_manager_worker_getter.h" #include "apps/units/cu_cp/cu_cp_unit_pcap_config.h" #include "srsran/pcap/dlt_pcap.h" diff --git a/apps/units/cu_up/cu_up_builder.cpp b/apps/units/cu_up/cu_up_builder.cpp index 8613e5e688..b07ad84b80 100644 --- a/apps/units/cu_up/cu_up_builder.cpp +++ b/apps/units/cu_up/cu_up_builder.cpp @@ -10,7 +10,7 @@ #include "cu_up_builder.h" #include "apps/services/e2/e2_metric_connector_manager.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/cu_up/metrics/cu_up_pdcp_metrics_consumers.h" #include "apps/units/cu_up/metrics/cu_up_pdcp_metrics_producer.h" #include "cu_up_unit_config.h" diff --git a/apps/units/cu_up/cu_up_unit_config_translators.cpp b/apps/units/cu_up/cu_up_unit_config_translators.cpp index fedbb6601c..d20441f293 100644 --- a/apps/units/cu_up/cu_up_unit_config_translators.cpp +++ b/apps/units/cu_up/cu_up_unit_config_translators.cpp @@ -9,7 +9,7 @@ */ #include "cu_up_unit_config_translators.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "cu_up_unit_config.h" #include "srsran/cu_up/cu_up_configuration_helpers.h" #include "srsran/e2/e2ap_configuration_helpers.h" diff --git a/apps/units/cu_up/pcap_factory.h b/apps/units/cu_up/pcap_factory.h index 5fe18c4104..a8967cf104 100644 --- a/apps/units/cu_up/pcap_factory.h +++ b/apps/units/cu_up/pcap_factory.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/worker_manager_worker_getter.h" +#include "apps/services/worker_manager/worker_manager_worker_getter.h" #include "apps/units/cu_up/cu_up_unit_pcap_config.h" #include "srsran/pcap/dlt_pcap.h" diff --git a/apps/units/flexible_du/CMakeLists.txt b/apps/units/flexible_du/CMakeLists.txt index d33a594b8d..b5ea6a39e6 100644 --- a/apps/units/flexible_du/CMakeLists.txt +++ b/apps/units/flexible_du/CMakeLists.txt @@ -7,7 +7,6 @@ # add_subdirectory(o_du_high) -add_subdirectory(support) if (NOT DU_SPLIT_6) add_subdirectory(split_helpers) endif () diff --git a/apps/units/flexible_du/o_du_high/du_high/CMakeLists.txt b/apps/units/flexible_du/o_du_high/du_high/CMakeLists.txt index 507e37b36b..01488b00b5 100644 --- a/apps/units/flexible_du/o_du_high/du_high/CMakeLists.txt +++ b/apps/units/flexible_du/o_du_high/du_high/CMakeLists.txt @@ -16,4 +16,4 @@ set(SOURCES add_library(srsran_du_high_unit_helpers STATIC ${SOURCES}) target_include_directories(srsran_du_high_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_du_high_unit_helpers sched_config srsran_du_high_unit_metrics_helpers) +target_link_libraries(srsran_du_high_unit_helpers sched_config srsran_du_high_unit_metrics_helpers srsran_cpu_affinities_helper) diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_du/o_du_high/du_high/du_high_config.h index b54e7b8b38..bca06b39c2 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/os_sched_affinity_manager.h" +#include "apps/services/worker_manager/os_sched_affinity_manager.h" #include "srsran/e2/e2ap_configuration.h" #include "srsran/ran/band_helper.h" #include "srsran/ran/bs_channel_bandwidth.h" diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 38cdf206c9..1863b097ba 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -10,7 +10,7 @@ #include "du_high_config_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_utils.h" -#include "apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h" +#include "apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h" #include "du_high_config.h" #include "srsran/ran/du_types.h" #include "srsran/ran/duplex_mode.h" diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp index 9c5d388073..4795169e65 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp @@ -9,7 +9,7 @@ */ #include "du_high_config_translators.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "du_high_config.h" #include "srsran/du/du_cell_config_helpers.h" #include "srsran/du/du_cell_config_validation.h" diff --git a/apps/units/flexible_du/o_du_high/du_high/pcap_factory.h b/apps/units/flexible_du/o_du_high/du_high/pcap_factory.h index 2cf4999b0f..eaf94e3287 100644 --- a/apps/units/flexible_du/o_du_high/du_high/pcap_factory.h +++ b/apps/units/flexible_du/o_du_high/du_high/pcap_factory.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "srsran/pcap/dlt_pcap.h" #include "srsran/pcap/mac_pcap.h" #include "srsran/pcap/rlc_pcap.h" diff --git a/apps/units/flexible_du/o_du_high/fapi/fapi_config_translator.cpp b/apps/units/flexible_du/o_du_high/fapi/fapi_config_translator.cpp index 5b2a77ec31..5e42ac15eb 100644 --- a/apps/units/flexible_du/o_du_high/fapi/fapi_config_translator.cpp +++ b/apps/units/flexible_du/o_du_high/fapi/fapi_config_translator.cpp @@ -9,7 +9,7 @@ */ #include "fapi_config_translator.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "fapi_config.h" using namespace srsran; diff --git a/apps/units/flexible_du/o_du_low/CMakeLists.txt b/apps/units/flexible_du/o_du_low/CMakeLists.txt index d2074bdf43..1c2cbdb695 100644 --- a/apps/units/flexible_du/o_du_low/CMakeLists.txt +++ b/apps/units/flexible_du/o_du_low/CMakeLists.txt @@ -15,7 +15,7 @@ set(SOURCES add_library(srsran_o_du_low_unit_helpers STATIC ${SOURCES}) target_include_directories(srsran_o_du_low_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) -set(DU_LOW_UNIT_HELPERS_LIBRARIES srsran_upper_phy) +set(DU_LOW_UNIT_HELPERS_LIBRARIES srsran_upper_phy srsran_cpu_affinities_helper) # Hardware acceleration for both PUSCH and PDSCH is enabled by default when using DPDK. if (DPDK_FOUND) diff --git a/apps/units/flexible_du/o_du_low/du_low_config.h b/apps/units/flexible_du/o_du_low/du_low_config.h index 36b581b3c1..176704e5da 100644 --- a/apps/units/flexible_du/o_du_low/du_low_config.h +++ b/apps/units/flexible_du/o_du_low/du_low_config.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/os_sched_affinity_manager.h" +#include "apps/services/worker_manager/os_sched_affinity_manager.h" #include #include #include diff --git a/apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.cpp b/apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.cpp index f3b0270ec7..0e560dff5b 100644 --- a/apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.cpp +++ b/apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.cpp @@ -10,7 +10,7 @@ #include "du_low_config_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_utils.h" -#include "apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h" +#include "apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h" #include "du_low_config.h" #include "srsran/adt/expected.h" #include "srsran/support/cli11_utils.h" diff --git a/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp b/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp index 7e6562dd02..fc1e46a550 100644 --- a/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp +++ b/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp @@ -9,7 +9,7 @@ */ #include "du_low_config_translator.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "du_low_config.h" #include "srsran/du/du_cell_config.h" #include "srsran/phy/upper/upper_phy_factories.h" diff --git a/apps/units/flexible_du/o_du_low/o_du_low_unit_factory.cpp b/apps/units/flexible_du/o_du_low/o_du_low_unit_factory.cpp index f312bab971..887d6920a6 100644 --- a/apps/units/flexible_du/o_du_low/o_du_low_unit_factory.cpp +++ b/apps/units/flexible_du/o_du_low/o_du_low_unit_factory.cpp @@ -9,7 +9,7 @@ */ #include "o_du_low_unit_factory.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "du_low_config.h" #include "du_low_config_translator.h" #include "srsran/du/du_low/o_du_low_factory.h" diff --git a/apps/units/flexible_du/split_7_2/helpers/CMakeLists.txt b/apps/units/flexible_du/split_7_2/helpers/CMakeLists.txt index 065f71b1b8..855b7b4651 100644 --- a/apps/units/flexible_du/split_7_2/helpers/CMakeLists.txt +++ b/apps/units/flexible_du/split_7_2/helpers/CMakeLists.txt @@ -18,5 +18,5 @@ set(SOURCES ru_ofh_config_yaml_writer.cpp) add_library(srsran_split_7_2_app_unit_helpers STATIC ${SOURCES}) -target_link_libraries(srsran_split_7_2_app_unit_helpers srsran_ru_ofh srsran_flexible_du_support) +target_link_libraries(srsran_split_7_2_app_unit_helpers srsran_ru_ofh srsran_cpu_affinities_helper) target_include_directories(srsran_split_7_2_app_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config.h b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config.h index 0a9130b4a1..d0771fd868 100644 --- a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config.h +++ b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/os_sched_affinity_manager.h" +#include "apps/services/worker_manager/os_sched_affinity_manager.h" #include "srsran/ran/bs_channel_bandwidth.h" #include "srsran/support/units.h" #include diff --git a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp index 8bde6b7a67..925bc01411 100644 --- a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp +++ b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp @@ -10,7 +10,7 @@ #include "ru_ofh_config_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_utils.h" -#include "apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h" +#include "apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h" #include "ru_ofh_config.h" #include "srsran/support/cli11_utils.h" #include "srsran/support/config_parsers.h" diff --git a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_translator.cpp b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_translator.cpp index bfc7ccba14..9d515def4f 100644 --- a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_translator.cpp +++ b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_translator.cpp @@ -9,7 +9,7 @@ */ #include "ru_ofh_config_translator.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "ru_ofh_config.h" #include "srsran/du/du_cell_config.h" diff --git a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_validator.h b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_validator.h index 91985b560a..d926449a4a 100644 --- a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_validator.h +++ b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_validator.h @@ -10,7 +10,7 @@ #pragma once -#include "apps/services/os_sched_affinity_manager.h" +#include "apps/services/worker_manager/os_sched_affinity_manager.h" #include "ru_ofh_config.h" #include "srsran/ran/subcarrier_spacing.h" diff --git a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.cpp b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.cpp index 64e6e5c7bb..746ae25171 100644 --- a/apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.cpp +++ b/apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.cpp @@ -9,7 +9,7 @@ */ #include "ru_ofh_factories.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/split_helpers/flexible_du_configs.h" #include "ru_ofh_config_translator.h" #include "srsran/ru/ru_ofh_factory.h" diff --git a/apps/units/flexible_du/split_7_2/split_7_2_du_unit_cli11_schema.cpp b/apps/units/flexible_du/split_7_2/split_7_2_du_unit_cli11_schema.cpp index 2cf82c7dd6..79f0dcf553 100644 --- a/apps/units/flexible_du/split_7_2/split_7_2_du_unit_cli11_schema.cpp +++ b/apps/units/flexible_du/split_7_2/split_7_2_du_unit_cli11_schema.cpp @@ -12,10 +12,7 @@ #include "apps/units/flexible_du/o_du_high/o_du_high_unit_config_cli11_schema.h" #include "apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.h" #include "apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_cli11_schema.h" -#include "apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h" #include "split_7_2_du_unit_config.h" -#include "srsran/support/cli11_utils.h" -#include "srsran/support/config_parsers.h" using namespace srsran; diff --git a/apps/units/flexible_du/split_8/helpers/CMakeLists.txt b/apps/units/flexible_du/split_8/helpers/CMakeLists.txt index 0879c71620..ddaf208ed1 100644 --- a/apps/units/flexible_du/split_8/helpers/CMakeLists.txt +++ b/apps/units/flexible_du/split_8/helpers/CMakeLists.txt @@ -14,5 +14,5 @@ set(SOURCES ru_sdr_factories.cpp) add_library(srsran_split_8_app_unit_helpers STATIC ${SOURCES}) -target_link_libraries(srsran_split_8_app_unit_helpers srsran_ru_generic srsran_lower_phy srsran_flexible_du_support) +target_link_libraries(srsran_split_8_app_unit_helpers srsran_ru_generic srsran_lower_phy srsran_cpu_affinities_helper) target_include_directories(srsran_split_8_app_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/flexible_du/split_8/helpers/ru_sdr_config.h b/apps/units/flexible_du/split_8/helpers/ru_sdr_config.h index a1cd17d138..b3f3141a1d 100644 --- a/apps/units/flexible_du/split_8/helpers/ru_sdr_config.h +++ b/apps/units/flexible_du/split_8/helpers/ru_sdr_config.h @@ -10,8 +10,7 @@ #pragma once -#include "apps/services/os_sched_affinity_manager.h" - +#include "apps/services/worker_manager/os_sched_affinity_manager.h" #include namespace srsran { diff --git a/apps/units/flexible_du/split_8/helpers/ru_sdr_config_cli11_schema.cpp b/apps/units/flexible_du/split_8/helpers/ru_sdr_config_cli11_schema.cpp index 25a6265532..986feb10e0 100644 --- a/apps/units/flexible_du/split_8/helpers/ru_sdr_config_cli11_schema.cpp +++ b/apps/units/flexible_du/split_8/helpers/ru_sdr_config_cli11_schema.cpp @@ -10,7 +10,7 @@ #include "ru_sdr_config_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_utils.h" -#include "apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h" +#include "apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h" #include "ru_sdr_config.h" #include "srsran/support/cli11_utils.h" #include "srsran/support/config_parsers.h" diff --git a/apps/units/flexible_du/split_8/helpers/ru_sdr_config_translator.cpp b/apps/units/flexible_du/split_8/helpers/ru_sdr_config_translator.cpp index 9b329f42ab..9db6e2d989 100644 --- a/apps/units/flexible_du/split_8/helpers/ru_sdr_config_translator.cpp +++ b/apps/units/flexible_du/split_8/helpers/ru_sdr_config_translator.cpp @@ -9,7 +9,7 @@ */ #include "ru_sdr_config_translator.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "ru_sdr_config.h" #include "srsran/du/du_cell_config.h" diff --git a/apps/units/flexible_du/split_8/helpers/ru_sdr_factories.cpp b/apps/units/flexible_du/split_8/helpers/ru_sdr_factories.cpp index ea0c275c0c..006b2dced5 100644 --- a/apps/units/flexible_du/split_8/helpers/ru_sdr_factories.cpp +++ b/apps/units/flexible_du/split_8/helpers/ru_sdr_factories.cpp @@ -9,7 +9,7 @@ */ #include "ru_sdr_factories.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/split_helpers/flexible_du_configs.h" #include "ru_sdr_config_translator.h" #include "srsran/ru/ru_generic_factory.h" diff --git a/apps/units/flexible_du/split_8/split_8_du_unit_cli11_schema.cpp b/apps/units/flexible_du/split_8/split_8_du_unit_cli11_schema.cpp index db0e9c87f8..2d3b2e182f 100644 --- a/apps/units/flexible_du/split_8/split_8_du_unit_cli11_schema.cpp +++ b/apps/units/flexible_du/split_8/split_8_du_unit_cli11_schema.cpp @@ -13,7 +13,6 @@ #include "apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.h" #include "apps/units/flexible_du/split_8/helpers/ru_sdr_config_cli11_schema.h" #include "split_8_du_unit_config.h" -#include "srsran/support/cli11_utils.h" using namespace srsran; diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp index a4c53c4410..bf78d38144 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_factory.cpp @@ -9,7 +9,7 @@ */ #include "dynamic_du_factory.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.h" #include "apps/units/flexible_du/split_8/helpers/ru_sdr_factories.h" #include "dynamic_du_translators.h" diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_translators.cpp b/apps/units/flexible_du/split_dynamic/dynamic_du_translators.cpp index 7d87026ce8..c115fe37c9 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_translators.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_translators.cpp @@ -9,7 +9,7 @@ */ #include "dynamic_du_translators.h" -#include "apps/services/worker_manager_config.h" +#include "apps/services/worker_manager/worker_manager_config.h" #include "apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.h" #include "apps/units/flexible_du/o_du_high/o_du_high_unit_config_translators.h" #include "apps/units/flexible_du/o_du_low/du_low_config_translator.h" diff --git a/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp b/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp index 3b79a97ea5..95724a57af 100644 --- a/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp +++ b/apps/units/flexible_du/split_dynamic/dynamic_du_unit_cli11_schema.cpp @@ -9,11 +9,11 @@ */ #include "dynamic_du_unit_cli11_schema.h" +#include "apps/services/worker_manager/cli11_cpu_affinities_parser_helper.h" #include "apps/units/flexible_du/o_du_high/o_du_high_unit_config_cli11_schema.h" #include "apps/units/flexible_du/o_du_low/du_low_config_cli11_schema.h" #include "apps/units/flexible_du/split_7_2/helpers/ru_ofh_config_cli11_schema.h" #include "apps/units/flexible_du/split_8/helpers/ru_sdr_config_cli11_schema.h" -#include "apps/units/flexible_du/support/cli11_cpu_affinities_parser_helper.h" #include "dynamic_du_unit_config.h" #include "srsran/support/cli11_utils.h" #include "srsran/support/config_parsers.h" diff --git a/apps/units/flexible_du/split_dynamic/multicell_dynamic_du_factory.cpp b/apps/units/flexible_du/split_dynamic/multicell_dynamic_du_factory.cpp index 8959ba9e04..f578b1aa4d 100644 --- a/apps/units/flexible_du/split_dynamic/multicell_dynamic_du_factory.cpp +++ b/apps/units/flexible_du/split_dynamic/multicell_dynamic_du_factory.cpp @@ -9,7 +9,7 @@ */ #include "multicell_dynamic_du_factory.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.h" #include "apps/units/flexible_du/split_8/helpers/ru_sdr_factories.h" #include "dynamic_du_translators.h" diff --git a/apps/units/flexible_du/split_helpers/flexible_du_factory.cpp b/apps/units/flexible_du/split_helpers/flexible_du_factory.cpp index 9cd226393e..4708cb7b26 100644 --- a/apps/units/flexible_du/split_helpers/flexible_du_factory.cpp +++ b/apps/units/flexible_du/split_helpers/flexible_du_factory.cpp @@ -10,7 +10,7 @@ #include "flexible_du_factory.h" #include "apps/services/e2/e2_metric_connector_manager.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/flexible_du_commands.h" #include "apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.h" #include "apps/units/flexible_du/o_du_high/o_du_high_unit_factory.h" diff --git a/apps/units/flexible_du/split_helpers/multicell_flexible_du_factory.cpp b/apps/units/flexible_du/split_helpers/multicell_flexible_du_factory.cpp index 4197abb003..38db6e8b14 100644 --- a/apps/units/flexible_du/split_helpers/multicell_flexible_du_factory.cpp +++ b/apps/units/flexible_du/split_helpers/multicell_flexible_du_factory.cpp @@ -10,20 +10,14 @@ #include "multicell_flexible_du_factory.h" #include "apps/services/e2/e2_metric_connector_manager.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/flexible_du_commands.h" #include "apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.h" #include "apps/units/flexible_du/o_du_high/o_du_high_unit_factory.h" #include "apps/units/flexible_du/o_du_low/o_du_low_unit_factory.h" -#include "apps/units/flexible_du/split_7_2/helpers/ru_ofh_factories.h" -#include "apps/units/flexible_du/split_8/helpers/ru_sdr_factories.h" #include "multicell_flexible_du_impl.h" - -#include "srsran/du/o_du.h" #include "srsran/du/o_du_factory.h" #include "srsran/e2/e2_du_metrics_connector.h" -#include "srsran/pcap/rlc_pcap.h" -#include "srsran/ru/ru_dummy_factory.h" using namespace srsran; diff --git a/apps/units/flexible_du/split_helpers/o_du_high_factory.cpp b/apps/units/flexible_du/split_helpers/o_du_high_factory.cpp index a09f16b558..79f24e61b4 100644 --- a/apps/units/flexible_du/split_helpers/o_du_high_factory.cpp +++ b/apps/units/flexible_du/split_helpers/o_du_high_factory.cpp @@ -9,7 +9,7 @@ */ #include "o_du_high_factory.h" -#include "apps/services/worker_manager.h" +#include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.h" #include "apps/units/flexible_du/o_du_high/o_du_high_unit_config.h" diff --git a/apps/units/flexible_du/support/CMakeLists.txt b/apps/units/flexible_du/support/CMakeLists.txt deleted file mode 100644 index 5153bd53ac..0000000000 --- a/apps/units/flexible_du/support/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# -# Copyright 2021-2024 Software Radio Systems Limited -# -# By using this file, you agree to the terms and conditions set -# forth in the LICENSE file which can be found at the top level of -# the distribution. -# - -set(SOURCES - cli11_cpu_affinities_parser_helper.cpp) - -add_library(srsran_flexible_du_support STATIC ${SOURCES}) -target_include_directories(srsran_flexible_du_support PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/lib/du/du_high/du_manager/du_ue/CMakeLists.txt b/lib/du/du_high/du_manager/du_ue/CMakeLists.txt index a7fc917465..6c6e7b3669 100644 --- a/lib/du/du_high/du_manager/du_ue/CMakeLists.txt +++ b/lib/du/du_high/du_manager/du_ue/CMakeLists.txt @@ -7,4 +7,4 @@ # add_library(du_ue du_bearer.cpp du_ue_adapters.cpp du_ue_bearer_manager.cpp du_ue_controller_impl.cpp du_ue_manager.cpp) -target_link_libraries(du_ue srsran_du_manager_procedures srsran_f1u_du) +target_link_libraries(du_ue srsran_du_manager_procedures srsran_f1u_du srsran_gtpu) diff --git a/lib/f1u/CMakeLists.txt b/lib/f1u/CMakeLists.txt index 9c9f040912..1409d8c276 100644 --- a/lib/f1u/CMakeLists.txt +++ b/lib/f1u/CMakeLists.txt @@ -10,12 +10,12 @@ add_library(srsran_f1u_cu_up cu_up/f1u_bearer_impl.cpp cu_up/f1u_bearer_factory. add_library(srsran_f1u_du du/f1u_bearer_impl.cpp du/f1u_bearer_factory.cpp) # Local connector -add_library(srsgnb_app_f1u_connector local_connector/f1u_local_connector.cpp) -target_link_libraries(srsgnb_app_f1u_connector srsran_f1u_cu_up) +add_library(srsran_f1u_connector local_connector/f1u_local_connector.cpp) +target_link_libraries(srsran_f1u_connector srsran_f1u_cu_up) #Split connector -add_library(srsgnb_app_f1u_cu_up_split_connector cu_up/split_connector/f1u_split_connector_factory.cpp cu_up/split_connector/f1u_split_connector.cpp ) -target_link_libraries(srsgnb_app_f1u_cu_up_split_connector srsran_f1u_cu_up) +add_library(srsran_f1u_cu_up_split_connector cu_up/split_connector/f1u_split_connector_factory.cpp cu_up/split_connector/f1u_split_connector.cpp ) +target_link_libraries(srsran_f1u_cu_up_split_connector srsran_f1u_cu_up) -add_library(srsgnb_app_f1u_du_split_connector du/split_connector/f1u_split_connector.cpp du/split_connector/f1u_split_connector_factory.cpp) -target_link_libraries(srsgnb_app_f1u_du_split_connector srsran_f1u_du) +add_library(srsran_f1u_du_split_connector du/split_connector/f1u_split_connector.cpp du/split_connector/f1u_split_connector_factory.cpp) +target_link_libraries(srsran_f1u_du_split_connector srsran_f1u_du) diff --git a/tests/unittests/f1u/CMakeLists.txt b/tests/unittests/f1u/CMakeLists.txt index 03f0a85eaf..36d6847b6f 100644 --- a/tests/unittests/f1u/CMakeLists.txt +++ b/tests/unittests/f1u/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(du) add_executable(f1u_local_connector_test common/f1u_connector_test.cpp) target_link_libraries(f1u_local_connector_test -srsgnb_app_f1u_connector +srsran_f1u_connector srsran_f1u_du srsran_f1u_cu_up srsran_support @@ -24,7 +24,7 @@ gtest_discover_tests(f1u_local_connector_test) add_executable(f1u_cu_up_split_connector_test common/f1u_cu_split_connector_test.cpp) target_link_libraries(f1u_cu_up_split_connector_test -srsgnb_app_f1u_cu_up_split_connector +srsran_f1u_cu_up_split_connector srsran_f1u_cu_up srsran_gtpu srsran_network @@ -38,7 +38,7 @@ gtest_discover_tests(f1u_cu_up_split_connector_test) add_executable(f1u_du_split_connector_test common/f1u_du_split_connector_test.cpp) target_link_libraries(f1u_du_split_connector_test -srsgnb_app_f1u_du_split_connector +srsran_f1u_du_split_connector srsran_f1u_du srsran_gtpu srsran_network From 04d797a352daa28ebe8107342964a5a962c5e5e3 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Wed, 6 Nov 2024 14:30:09 +0000 Subject: [PATCH 11/72] gnb: suppress TSAN warnings about race-conditions inside DPDK libs --- include/srsran/support/tsan_options.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/srsran/support/tsan_options.h b/include/srsran/support/tsan_options.h index 2e75c9924b..69fbbd8d71 100644 --- a/include/srsran/support/tsan_options.h +++ b/include/srsran/support/tsan_options.h @@ -42,6 +42,8 @@ const char* __tsan_default_suppressions() "called_from_lib:libpgm-5.2.so\n" "called_from_lib:libusb*\n" "called_from_lib:libuhd*\n" + "called_from_lib:librte_eal*\n" + "called_from_lib:librte_net_iavf*\n" // Races detected inside uninstrumented libraries. This may hide legit races if any of the libraries appear in the // backtrace "race:libusb*\n" From 08da6bdc2499aa62fec0d37ce4d50dfc7ae7c2ce Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Tue, 5 Nov 2024 09:39:34 +0100 Subject: [PATCH 12/72] phy: fix PRACH detector memory allocation in runtime --- .../upper/channel_processors/CMakeLists.txt | 1 + .../prach_detector_generic_impl.cpp | 4 +- .../prach_detector_generic_thresholds.cpp | 705 ++++++++++++++++++ .../prach_detector_generic_thresholds.h | 704 +---------------- .../prach_detector_phy_validator_impl.cpp | 5 +- 5 files changed, 727 insertions(+), 692 deletions(-) create mode 100644 lib/phy/upper/channel_processors/prach_detector_generic_thresholds.cpp diff --git a/lib/phy/upper/channel_processors/CMakeLists.txt b/lib/phy/upper/channel_processors/CMakeLists.txt index 7dbe7ccb98..e056efcf43 100644 --- a/lib/phy/upper/channel_processors/CMakeLists.txt +++ b/lib/phy/upper/channel_processors/CMakeLists.txt @@ -28,6 +28,7 @@ target_link_libraries(srsran_pdcch_processor srsran_ran) add_library(srsran_prach_detector STATIC prach_detector_generic_impl.cpp + prach_detector_generic_thresholds.cpp prach_generator_impl.cpp prach_detector_phy_validator_impl.cpp) target_link_libraries(srsran_prach_detector srsran_ran srsvec) diff --git a/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp b/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp index 48bbfa2b02..ed2602ec97 100644 --- a/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp +++ b/lib/phy/upper/channel_processors/prach_detector_generic_impl.cpp @@ -29,8 +29,6 @@ using namespace srsran; -static const detail::threshold_and_margin_finder threshold_and_margin_table(detail::all_threshold_and_margins); - error_type prach_detector_validator_impl::is_valid(const prach_detector::configuration& config) const { return validate_prach_detector_phy(config.format, config.ra_scs, config.zero_correlation_zone, config.nof_rx_ports); @@ -136,7 +134,7 @@ prach_detection_result prach_detector_generic_impl::detect(const prach_buffer& i th_params.zero_correlation_zone = config.zero_correlation_zone; th_params.combine_symbols = combine_symbols; - auto th_and_margin = threshold_and_margin_table.get(th_params); + auto th_and_margin = detail::get_threshold_and_margin(th_params); float threshold = std::get<0>(th_and_margin); unsigned win_margin = std::get<1>(th_and_margin); srsran_assert((win_margin > 0) && (threshold > 0.0), diff --git a/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.cpp b/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.cpp new file mode 100644 index 0000000000..56f89d84da --- /dev/null +++ b/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.cpp @@ -0,0 +1,705 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ +#include "prach_detector_generic_thresholds.h" +#include "srsran/adt/span.h" +#include "srsran/adt/to_array.h" +#include "srsran/ran/prach/prach_format_type.h" +#include "srsran/ran/prach/prach_subcarrier_spacing.h" + +using namespace srsran; +using namespace detail; + +namespace { + +/// Overloaded less-than comparison operator. +inline bool operator<(const threshold_params& lhs, const threshold_params& rhs) +{ + if (lhs.nof_rx_ports < rhs.nof_rx_ports) { + return true; + } + if (lhs.nof_rx_ports > rhs.nof_rx_ports) { + return false; + } + + // If we are here, nof_rx_ports is equal. + if (lhs.scs < rhs.scs) { + return true; + } + if (lhs.scs > rhs.scs) { + return false; + } + + // If we are here, nof_rx_ports and scs are equal. + if (lhs.format < rhs.format) { + return true; + } + if (lhs.format > rhs.format) { + return false; + } + + // If we are here, nof_rx_ports, scs and format are equal. + if (lhs.zero_correlation_zone < rhs.zero_correlation_zone) { + return true; + } + if (lhs.zero_correlation_zone > rhs.zero_correlation_zone) { + return false; + } + + // If we are here, nof_rx_ports, scs, format and zero_correlation_zone are equal. + if (!lhs.combine_symbols && rhs.combine_symbols) { + return true; + } + return false; +} + +/// Overloaded equal-to comparison operator. +inline bool operator==(const threshold_params& lhs, const threshold_params& rhs) +{ + if (lhs.nof_rx_ports != rhs.nof_rx_ports) { + return false; + } + + // If we are here, nof_rx_ports is equal. + if (lhs.scs != rhs.scs) { + return false; + } + + // If we are here, nof_rx_ports and scs are equal. + if (lhs.format != rhs.format) { + return false; + } + + // If we are here, nof_rx_ports, scs and format are equal. + if (lhs.zero_correlation_zone != rhs.zero_correlation_zone) { + return false; + } + + // If we are here, nof_rx_ports, scs, format and zero_correlation_zone are equal. + if (lhs.combine_symbols != rhs.combine_symbols) { + return false; + } + return true; +} + +/// Manages the mapping between PRACH configuration and the (threshold, margin) pairs. +class threshold_and_margin_finder +{ +public: + /// Mapping between PRACH configuration and threshold value. + struct threshold_entry { + /// Subset of PRACH configuration parameters affecting the threshold value. + threshold_params configuration; + /// Threshold value and search margin. + threshold_and_margin_type threshold_and_margin; + /// Threshold quality flag. + threshold_flag flag; + }; + + /// Constructor: receives the list of pairings and ensures it is sorted. + explicit threshold_and_margin_finder(span in) : + sorted_thresholds_and_margins(in.begin(), in.end()) + { + std::sort(sorted_thresholds_and_margins.begin(), + sorted_thresholds_and_margins.end(), + [](const threshold_entry& a, const threshold_entry& b) { return (a.configuration < b.configuration); }); + } + + /// Retrieves the (threshold, margin) pair corresponding to the given configuration. + threshold_and_margin_type get(const threshold_params& params) const + { + auto it = + std::lower_bound(sorted_thresholds_and_margins.begin(), + sorted_thresholds_and_margins.end(), + params, + [](const threshold_entry& a, const threshold_params& b) { return (a.configuration < b); }); + + if (it != sorted_thresholds_and_margins.end()) { + return it->threshold_and_margin; + } + + // todo(david): once all cases are covered, replace this by a srsran_assert. + if (is_long_preamble(params.format)) { + return {/* threshold */ 2.0F, /* margin */ 5}; + } + return {/* threshold */ 0.3F, /* margin */ 12}; + } + + /// Checks the quality flag of the threshold for the given configurations. + threshold_flag check_flag(const threshold_params& params) const + { + auto it = + std::lower_bound(sorted_thresholds_and_margins.begin(), + sorted_thresholds_and_margins.end(), + params, + [](const threshold_entry& a, const threshold_params& b) { return (a.configuration < b); }); + + if ((it != sorted_thresholds_and_margins.end()) && (it->configuration == params)) { + return it->flag; + } + return threshold_flag::red; + } + +private: + /// Sorted list of thresholds. + std::vector sorted_thresholds_and_margins; +}; + +using th_flag = threshold_flag; + +} // namespace + +/// Unsorted list of thresholds. +static const auto all_threshold_and_margins = to_array({ + // clang-format off + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.147F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 2, /* combine symbols */ true}, {0.874F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 3, /* combine symbols */ true}, {0.774F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 4, /* combine symbols */ true}, {0.640F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 5, /* combine symbols */ true}, {0.551F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 6, /* combine symbols */ true}, {0.449F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 7, /* combine symbols */ true}, {0.388F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 8, /* combine symbols */ true}, {0.321F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 9, /* combine symbols */ true}, {0.255F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 10, /* combine symbols */ true}, {0.205F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 11, /* combine symbols */ true}, {0.167F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 12, /* combine symbols */ true}, {0.147F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 13, /* combine symbols */ true}, {0.148F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 14, /* combine symbols */ true}, {0.148F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 15, /* combine symbols */ true}, {0.148F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.085F, 5}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 1, /* combine symbols */ true}, {0.522F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 2, /* combine symbols */ true}, {0.451F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 3, /* combine symbols */ true}, {0.404F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 4, /* combine symbols */ true}, {0.344F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 5, /* combine symbols */ true}, {0.301F, 5}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 6, /* combine symbols */ true}, {0.249F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 7, /* combine symbols */ true}, {0.219F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 8, /* combine symbols */ true}, {0.180F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 9, /* combine symbols */ true}, {0.146F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 10, /* combine symbols */ true}, {0.118F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 11, /* combine symbols */ true}, {0.098F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 12, /* combine symbols */ true}, {0.085F, 5}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 13, /* combine symbols */ true}, {0.086F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 14, /* combine symbols */ true}, {0.085F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 15, /* combine symbols */ true}, {0.085F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.053F, 5}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 1, /* combine symbols */ true}, {0.307F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 2, /* combine symbols */ true}, {0.269F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 3, /* combine symbols */ true}, {0.240F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 4, /* combine symbols */ true}, {0.207F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 5, /* combine symbols */ true}, {0.180F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 6, /* combine symbols */ true}, {0.149F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 7, /* combine symbols */ true}, {0.131F, 5}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 8, /* combine symbols */ true}, {0.112F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 9, /* combine symbols */ true}, {0.090F, 5}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 10, /* combine symbols */ true}, {0.072F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 11, /* combine symbols */ true}, {0.060F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 12, /* combine symbols */ true}, {0.052F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 13, /* combine symbols */ true}, {0.052F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 14, /* combine symbols */ true}, {0.052F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 15, /* combine symbols */ true}, {0.053F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 0, /* combine symbols */ true}, {0.025F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 2, /* combine symbols */ true}, {0.869F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 3, /* combine symbols */ true}, {0.781F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 4, /* combine symbols */ true}, {0.636F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 5, /* combine symbols */ true}, {0.548F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 6, /* combine symbols */ true}, {0.455F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 7, /* combine symbols */ true}, {0.387F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 8, /* combine symbols */ true}, {0.328F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 9, /* combine symbols */ true}, {0.256F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 10, /* combine symbols */ true}, {0.205F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 11, /* combine symbols */ true}, {0.169F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 12, /* combine symbols */ true}, {0.134F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 13, /* combine symbols */ true}, {0.097F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 14, /* combine symbols */ true}, {0.060F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 15, /* combine symbols */ true}, {0.041F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 0, /* combine symbols */ true}, {0.014F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 1, /* combine symbols */ true}, {0.510F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 2, /* combine symbols */ true}, {0.459F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 3, /* combine symbols */ true}, {0.409F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 4, /* combine symbols */ true}, {0.341F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 5, /* combine symbols */ true}, {0.299F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 6, /* combine symbols */ true}, {0.250F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 7, /* combine symbols */ true}, {0.213F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 8, /* combine symbols */ true}, {0.183F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 9, /* combine symbols */ true}, {0.145F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 10, /* combine symbols */ true}, {0.118F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 11, /* combine symbols */ true}, {0.097F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 12, /* combine symbols */ true}, {0.078F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 13, /* combine symbols */ true}, {0.057F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 14, /* combine symbols */ true}, {0.035F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 15, /* combine symbols */ true}, {0.024F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 0, /* combine symbols */ true}, {0.009F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 1, /* combine symbols */ true}, {0.304F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 2, /* combine symbols */ true}, {0.269F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 3, /* combine symbols */ true}, {0.242F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 4, /* combine symbols */ true}, {0.206F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 5, /* combine symbols */ true}, {0.180F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 6, /* combine symbols */ true}, {0.150F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 7, /* combine symbols */ true}, {0.132F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 8, /* combine symbols */ true}, {0.112F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 9, /* combine symbols */ true}, {0.090F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 10, /* combine symbols */ true}, {0.072F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 11, /* combine symbols */ true}, {0.060F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 12, /* combine symbols */ true}, {0.048F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 13, /* combine symbols */ true}, {0.035F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 14, /* combine symbols */ true}, {0.022F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 15, /* combine symbols */ true}, {0.015F, 5}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 0, /* combine symbols */ true}, {0.100F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 1, /* combine symbols */ true}, {0.996F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 2, /* combine symbols */ true}, {0.882F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 3, /* combine symbols */ true}, {0.772F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 4, /* combine symbols */ true}, {0.658F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 5, /* combine symbols */ true}, {0.551F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 6, /* combine symbols */ true}, {0.450F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 7, /* combine symbols */ true}, {0.387F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 8, /* combine symbols */ true}, {0.329F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 9, /* combine symbols */ true}, {0.258F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 10, /* combine symbols */ true}, {0.207F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 11, /* combine symbols */ true}, {0.169F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 12, /* combine symbols */ true}, {0.134F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 13, /* combine symbols */ true}, {0.101F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 14, /* combine symbols */ true}, {0.101F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 15, /* combine symbols */ true}, {0.101F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 0, /* combine symbols */ true}, {0.059F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 1, /* combine symbols */ true}, {0.511F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 2, /* combine symbols */ true}, {0.452F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 3, /* combine symbols */ true}, {0.407F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 4, /* combine symbols */ true}, {0.345F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 5, /* combine symbols */ true}, {0.302F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 7, /* combine symbols */ true}, {0.216F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 8, /* combine symbols */ true}, {0.180F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 9, /* combine symbols */ true}, {0.145F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 10, /* combine symbols */ true}, {0.116F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 11, /* combine symbols */ true}, {0.097F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 12, /* combine symbols */ true}, {0.077F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 13, /* combine symbols */ true}, {0.059F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 14, /* combine symbols */ true}, {0.058F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 15, /* combine symbols */ true}, {0.059F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 0, /* combine symbols */ true}, {0.036F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 1, /* combine symbols */ true}, {0.301F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 2, /* combine symbols */ true}, {0.270F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 3, /* combine symbols */ true}, {0.243F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 4, /* combine symbols */ true}, {0.208F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 5, /* combine symbols */ true}, {0.181F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 6, /* combine symbols */ true}, {0.150F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 7, /* combine symbols */ true}, {0.132F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 8, /* combine symbols */ true}, {0.111F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 9, /* combine symbols */ true}, {0.090F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 10, /* combine symbols */ true}, {0.072F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 11, /* combine symbols */ true}, {0.060F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 12, /* combine symbols */ true}, {0.048F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 13, /* combine symbols */ true}, {0.037F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 14, /* combine symbols */ true}, {0.036F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 15, /* combine symbols */ true}, {0.036F, 5}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.610F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.995F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.876F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.787F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.769F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.690F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.637F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.600F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.604F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.597F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.603F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.598F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.328F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.692F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.625F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.555F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.507F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.461F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.423F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.409F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.371F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.344F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.324F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.406F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.367F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.328F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.303F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.271F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.243F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.224F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.206F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.197F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.196F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.198F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.980F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.879F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.785F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.760F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.692F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.631F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.598F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.602F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.611F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.686F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.617F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.554F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.460F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.416F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.406F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.342F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.328F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.321F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.401F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.358F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.325F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.302F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.271F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.244F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.222F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.204F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.194F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.980F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.879F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.785F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.760F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.692F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.631F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.598F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.602F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.611F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.686F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.617F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.554F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.460F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.416F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.406F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.342F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.324F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.321F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.401F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.358F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.325F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.302F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.271F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.244F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.222F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.204F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.194F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.352F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.987F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.868F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.789F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.762F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.696F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.633F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.602F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.461F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.388F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.350F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.353F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.192F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.688F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.625F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.568F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.460F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.416F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.407F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.372F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.342F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.324F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.281F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.255F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.218F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.193F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.192F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.402F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.363F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.304F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.273F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.248F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.243F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.224F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.206F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.172F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.154F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.118F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.352F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.993F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.863F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.786F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.776F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.699F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.633F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.518F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.464F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.392F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.349F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.353F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.194F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.694F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.611F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.550F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.510F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.452F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.411F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.400F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.367F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.340F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.282F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.256F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.212F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.193F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.193F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.118F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.404F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.362F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.328F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.301F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.272F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.247F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.242F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.222F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.170F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.155F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.234F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.995F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.876F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.789F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.763F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.707F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.646F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.603F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.517F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.465F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.388F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.304F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.232F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.134F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.687F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.616F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.553F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.510F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.456F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.408F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.402F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.370F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.348F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.289F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.252F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.217F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.173F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.133F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.080F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.401F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.360F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.324F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.298F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.270F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.242F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.223F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.193F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.153F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.130F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.104F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.080F, 12}, th_flag::orange}, + // The following commented value is the calibrated one - however, we noticed that in synthetic environments with no + // noise/interference, the resulting false-alarm probability is a bit too high. We increase a bit the threshold. + // {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.229F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.986F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.883F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.783F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.770F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.700F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.637F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.599F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.464F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.385F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.304F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.232F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.677F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.622F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.553F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.511F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.414F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.409F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.345F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.283F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.255F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.213F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.132F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.404F, 12}, th_flag::red}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.363F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.298F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.268F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.219F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::orange}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.197F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.155F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.105F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.986F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.883F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.783F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.770F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.700F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.637F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.599F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.464F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.385F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.304F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.232F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.677F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.622F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.553F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.511F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.414F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.409F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.345F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.283F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.255F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.213F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.132F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.404F, 12}, th_flag::red}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.363F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.298F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.268F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.219F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::orange}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.197F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.155F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.105F, 12}, th_flag::green}, // provisional + {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, // provisional + // clang-format on +}); + +static const threshold_and_margin_finder threshold_and_margin_table(all_threshold_and_margins); + +threshold_and_margin_type srsran::detail::get_threshold_and_margin(const threshold_params& params) +{ + return threshold_and_margin_table.get(params); +} + +threshold_flag srsran::detail::get_threshold_flag(const threshold_params& params) +{ + return threshold_and_margin_table.check_flag(params); +} diff --git a/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h b/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h index 1de6735da3..449c992e68 100644 --- a/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h +++ b/lib/phy/upper/channel_processors/prach_detector_generic_thresholds.h @@ -13,13 +13,20 @@ #pragma once -#include "srsran/adt/span.h" -#include "srsran/adt/to_array.h" #include "srsran/ran/prach/prach_format_type.h" #include "srsran/ran/prach/prach_subcarrier_spacing.h" -namespace srsran { -namespace detail { +namespace srsran::detail { + +/// Flag applied to each threshold entry. +enum class threshold_flag { + /// Threshold entry not suitable for proper PRACH detection. + red, + /// Threshold entry with suboptimal PRACH detection performance. + orange, + /// Threshold entry meeting PRACH detection requirements. + green +}; /// Parameters that affect the detection threshold value. struct threshold_params { @@ -35,688 +42,13 @@ struct threshold_params { bool combine_symbols = false; }; -/// Overloaded less-than comparison operator. -inline bool operator<(const threshold_params& lhs, const threshold_params& rhs) -{ - if (lhs.nof_rx_ports < rhs.nof_rx_ports) { - return true; - } - if (lhs.nof_rx_ports > rhs.nof_rx_ports) { - return false; - } - - // If we are here, nof_rx_ports is equal. - if (lhs.scs < rhs.scs) { - return true; - } - if (lhs.scs > rhs.scs) { - return false; - } - - // If we are here, nof_rx_ports and scs are equal. - if (lhs.format < rhs.format) { - return true; - } - if (lhs.format > rhs.format) { - return false; - } - - // If we are here, nof_rx_ports, scs and format are equal. - if (lhs.zero_correlation_zone < rhs.zero_correlation_zone) { - return true; - } - if (lhs.zero_correlation_zone > rhs.zero_correlation_zone) { - return false; - } - - // If we are here, nof_rx_ports, scs, format and zero_correlation_zone are equal. - if (!lhs.combine_symbols && rhs.combine_symbols) { - return true; - } - return false; -} - -/// Overloaded equal-to comparison operator. -inline bool operator==(const threshold_params& lhs, const threshold_params& rhs) -{ - if (lhs.nof_rx_ports != rhs.nof_rx_ports) { - return false; - } - - // If we are here, nof_rx_ports is equal. - if (lhs.scs != rhs.scs) { - return false; - } - - // If we are here, nof_rx_ports and scs are equal. - if (lhs.format != rhs.format) { - return false; - } - - // If we are here, nof_rx_ports, scs and format are equal. - if (lhs.zero_correlation_zone != rhs.zero_correlation_zone) { - return false; - } - - // If we are here, nof_rx_ports, scs, format and zero_correlation_zone are equal. - if (lhs.combine_symbols != rhs.combine_symbols) { - return false; - } - return true; -} +/// Pairs the PRACH detector threshold and margin. +using threshold_and_margin_type = std::pair; -/// Manages the mapping between PRACH configuration and the (threshold, margin) pairs. -class threshold_and_margin_finder -{ -public: - /// Flag applied to each threshold entry. - enum class threshold_flag { - /// Threshold entry not suitable for proper PRACH detection. - red, - /// Threshold entry with suboptimal PRACH detection performance. - orange, - /// Threshold entry meeting PRACH detection requirements. - green - }; - - using threshold_and_margin_type = std::pair; - - /// Mapping between PRACH configuration and threshold value. - struct threshold_entry { - /// Subset of PRACH configuration parameters affecting the threshold value. - threshold_params configuration; - /// Threshold value and search margin. - threshold_and_margin_type threshold_and_margin; - /// Threshold quality flag. - threshold_flag flag; - }; - - /// Constructor: receives the list of pairings and ensures it is sorted. - explicit threshold_and_margin_finder(span in) : - sorted_thresholds_and_margins(in.begin(), in.end()) - { - std::sort(sorted_thresholds_and_margins.begin(), - sorted_thresholds_and_margins.end(), - [](const threshold_entry& a, const threshold_entry& b) { return (a.configuration < b.configuration); }); - } - - /// Retrieves the (threshold, margin) pair corresponding to the given configuration. - threshold_and_margin_type get(const threshold_params& params) const - { - auto it = - std::lower_bound(sorted_thresholds_and_margins.begin(), - sorted_thresholds_and_margins.end(), - params, - [](const threshold_entry& a, const threshold_params& b) { return (a.configuration < b); }); - - if (it != sorted_thresholds_and_margins.end()) { - return it->threshold_and_margin; - } - - // todo(david): once all cases are covered, replace this by a srsran_assert. - if (is_long_preamble(params.format)) { - return {/* threshold */ 2.0F, /* margin */ 5}; - } - return {/* threshold */ 0.3F, /* margin */ 12}; - } - - /// Checks the quality flag of the threshold for the given configurations. - threshold_flag check_flag(const threshold_params& params) const - { - auto it = - std::lower_bound(sorted_thresholds_and_margins.begin(), - sorted_thresholds_and_margins.end(), - params, - [](const threshold_entry& a, const threshold_params& b) { return (a.configuration < b); }); - - if ((it != sorted_thresholds_and_margins.end()) && (it->configuration == params)) { - return it->flag; - } - return threshold_flag::red; - } - -private: - /// Sorted list of thresholds. - std::vector sorted_thresholds_and_margins; -}; +/// Checks the quality flag of the threshold for the given configurations. +threshold_flag get_threshold_flag(const threshold_params& params); -using th_flag = threshold_and_margin_finder::threshold_flag; -/// Unsorted list of thresholds. -static const auto all_threshold_and_margins = to_array({ - // clang-format off - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.147F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 2, /* combine symbols */ true}, {0.874F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 3, /* combine symbols */ true}, {0.774F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 4, /* combine symbols */ true}, {0.640F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 5, /* combine symbols */ true}, {0.551F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 6, /* combine symbols */ true}, {0.449F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 7, /* combine symbols */ true}, {0.388F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 8, /* combine symbols */ true}, {0.321F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 9, /* combine symbols */ true}, {0.255F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 10, /* combine symbols */ true}, {0.205F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 11, /* combine symbols */ true}, {0.167F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 12, /* combine symbols */ true}, {0.147F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 13, /* combine symbols */ true}, {0.148F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 14, /* combine symbols */ true}, {0.148F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 15, /* combine symbols */ true}, {0.148F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.085F, 5}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 1, /* combine symbols */ true}, {0.522F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 2, /* combine symbols */ true}, {0.451F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 3, /* combine symbols */ true}, {0.404F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 4, /* combine symbols */ true}, {0.344F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 5, /* combine symbols */ true}, {0.301F, 5}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 6, /* combine symbols */ true}, {0.249F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 7, /* combine symbols */ true}, {0.219F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 8, /* combine symbols */ true}, {0.180F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 9, /* combine symbols */ true}, {0.146F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 10, /* combine symbols */ true}, {0.118F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 11, /* combine symbols */ true}, {0.098F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 12, /* combine symbols */ true}, {0.085F, 5}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 13, /* combine symbols */ true}, {0.086F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 14, /* combine symbols */ true}, {0.085F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 15, /* combine symbols */ true}, {0.085F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 0, /* combine symbols */ true}, {0.053F, 5}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 1, /* combine symbols */ true}, {0.307F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 2, /* combine symbols */ true}, {0.269F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 3, /* combine symbols */ true}, {0.240F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 4, /* combine symbols */ true}, {0.207F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 5, /* combine symbols */ true}, {0.180F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 6, /* combine symbols */ true}, {0.149F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 7, /* combine symbols */ true}, {0.131F, 5}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 8, /* combine symbols */ true}, {0.112F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 9, /* combine symbols */ true}, {0.090F, 5}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 10, /* combine symbols */ true}, {0.072F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 11, /* combine symbols */ true}, {0.060F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 12, /* combine symbols */ true}, {0.052F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 13, /* combine symbols */ true}, {0.052F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 14, /* combine symbols */ true}, {0.052F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::zero, /* ZCZ */ 15, /* combine symbols */ true}, {0.053F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 0, /* combine symbols */ true}, {0.025F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 2, /* combine symbols */ true}, {0.869F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 3, /* combine symbols */ true}, {0.781F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 4, /* combine symbols */ true}, {0.636F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 5, /* combine symbols */ true}, {0.548F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 6, /* combine symbols */ true}, {0.455F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 7, /* combine symbols */ true}, {0.387F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 8, /* combine symbols */ true}, {0.328F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 9, /* combine symbols */ true}, {0.256F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 10, /* combine symbols */ true}, {0.205F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 11, /* combine symbols */ true}, {0.169F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 12, /* combine symbols */ true}, {0.134F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 13, /* combine symbols */ true}, {0.097F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 14, /* combine symbols */ true}, {0.060F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 15, /* combine symbols */ true}, {0.041F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 0, /* combine symbols */ true}, {0.014F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 1, /* combine symbols */ true}, {0.510F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 2, /* combine symbols */ true}, {0.459F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 3, /* combine symbols */ true}, {0.409F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 4, /* combine symbols */ true}, {0.341F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 5, /* combine symbols */ true}, {0.299F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 6, /* combine symbols */ true}, {0.250F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 7, /* combine symbols */ true}, {0.213F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 8, /* combine symbols */ true}, {0.183F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 9, /* combine symbols */ true}, {0.145F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 10, /* combine symbols */ true}, {0.118F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 11, /* combine symbols */ true}, {0.097F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 12, /* combine symbols */ true}, {0.078F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 13, /* combine symbols */ true}, {0.057F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 14, /* combine symbols */ true}, {0.035F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 15, /* combine symbols */ true}, {0.024F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 0, /* combine symbols */ true}, {0.009F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 1, /* combine symbols */ true}, {0.304F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 2, /* combine symbols */ true}, {0.269F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 3, /* combine symbols */ true}, {0.242F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 4, /* combine symbols */ true}, {0.206F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 5, /* combine symbols */ true}, {0.180F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 6, /* combine symbols */ true}, {0.150F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 7, /* combine symbols */ true}, {0.132F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 8, /* combine symbols */ true}, {0.112F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 9, /* combine symbols */ true}, {0.090F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 10, /* combine symbols */ true}, {0.072F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 11, /* combine symbols */ true}, {0.060F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 12, /* combine symbols */ true}, {0.048F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 13, /* combine symbols */ true}, {0.035F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 14, /* combine symbols */ true}, {0.022F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::one, /* ZCZ */ 15, /* combine symbols */ true}, {0.015F, 5}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 0, /* combine symbols */ true}, {0.100F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 1, /* combine symbols */ true}, {0.996F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 2, /* combine symbols */ true}, {0.882F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 3, /* combine symbols */ true}, {0.772F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 4, /* combine symbols */ true}, {0.658F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 5, /* combine symbols */ true}, {0.551F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 6, /* combine symbols */ true}, {0.450F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 7, /* combine symbols */ true}, {0.387F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 8, /* combine symbols */ true}, {0.329F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 9, /* combine symbols */ true}, {0.258F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 10, /* combine symbols */ true}, {0.207F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 11, /* combine symbols */ true}, {0.169F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 12, /* combine symbols */ true}, {0.134F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 13, /* combine symbols */ true}, {0.101F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 14, /* combine symbols */ true}, {0.101F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 15, /* combine symbols */ true}, {0.101F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 0, /* combine symbols */ true}, {0.059F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 1, /* combine symbols */ true}, {0.511F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 2, /* combine symbols */ true}, {0.452F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 3, /* combine symbols */ true}, {0.407F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 4, /* combine symbols */ true}, {0.345F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 5, /* combine symbols */ true}, {0.302F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 7, /* combine symbols */ true}, {0.216F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 8, /* combine symbols */ true}, {0.180F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 9, /* combine symbols */ true}, {0.145F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 10, /* combine symbols */ true}, {0.116F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 11, /* combine symbols */ true}, {0.097F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 12, /* combine symbols */ true}, {0.077F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 13, /* combine symbols */ true}, {0.059F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 14, /* combine symbols */ true}, {0.058F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 15, /* combine symbols */ true}, {0.059F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 0, /* combine symbols */ true}, {0.036F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 1, /* combine symbols */ true}, {0.301F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 2, /* combine symbols */ true}, {0.270F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 3, /* combine symbols */ true}, {0.243F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 4, /* combine symbols */ true}, {0.208F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 5, /* combine symbols */ true}, {0.181F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 6, /* combine symbols */ true}, {0.150F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 7, /* combine symbols */ true}, {0.132F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 8, /* combine symbols */ true}, {0.111F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 9, /* combine symbols */ true}, {0.090F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 10, /* combine symbols */ true}, {0.072F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 11, /* combine symbols */ true}, {0.060F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 12, /* combine symbols */ true}, {0.048F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 13, /* combine symbols */ true}, {0.037F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 14, /* combine symbols */ true}, {0.036F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz1_25, prach_format_type::two, /* ZCZ */ 15, /* combine symbols */ true}, {0.036F, 5}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.610F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.995F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.876F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.787F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.769F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.690F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.637F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.600F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.604F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.597F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.603F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.598F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.328F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.692F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.625F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.555F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.507F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.461F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.423F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.409F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.371F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.344F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.324F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.406F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.367F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.328F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.303F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.271F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.243F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.224F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.206F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.197F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.196F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.198F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.980F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.879F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.785F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.760F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.692F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.631F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.598F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.602F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.611F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.686F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.617F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.554F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.460F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.416F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.406F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.342F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.328F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.321F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.401F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.358F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.325F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.302F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.271F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.244F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.222F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.204F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.194F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.196F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.980F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.879F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.785F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.760F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.692F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.631F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.598F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.602F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.611F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.605F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.686F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.617F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.554F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.460F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.416F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.406F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.342F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.324F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.321F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 0, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 1, /* combine symbols */ true}, {0.401F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 2, /* combine symbols */ true}, {0.358F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 3, /* combine symbols */ true}, {0.325F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 4, /* combine symbols */ true}, {0.302F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 5, /* combine symbols */ true}, {0.271F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 6, /* combine symbols */ true}, {0.244F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 8, /* combine symbols */ true}, {0.222F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 9, /* combine symbols */ true}, {0.204F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 10, /* combine symbols */ true}, {0.194F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 11, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 12, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 13, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 14, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::A1, /* ZCZ */ 15, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.352F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.987F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.868F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.789F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.762F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.696F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.633F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.602F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.461F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.388F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.350F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.353F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.192F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.688F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.625F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.568F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.460F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.416F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.407F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.372F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.342F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.324F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.281F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.255F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.218F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.193F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.192F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.402F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.363F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.304F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.273F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.248F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.243F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.224F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.206F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.195F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.172F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.154F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.118F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.352F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.993F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.863F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.786F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.776F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.699F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.633F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.607F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.518F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.464F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.392F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.349F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.353F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.194F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.694F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.611F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.550F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.510F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.452F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.411F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.400F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.367F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.340F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.323F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.282F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.256F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.212F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.193F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.193F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 0, /* combine symbols */ true}, {0.118F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 1, /* combine symbols */ true}, {0.404F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 2, /* combine symbols */ true}, {0.362F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 3, /* combine symbols */ true}, {0.328F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 4, /* combine symbols */ true}, {0.301F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 5, /* combine symbols */ true}, {0.272F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 6, /* combine symbols */ true}, {0.247F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 7, /* combine symbols */ true}, {0.242F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 8, /* combine symbols */ true}, {0.222F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 10, /* combine symbols */ true}, {0.195F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 11, /* combine symbols */ true}, {0.170F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 12, /* combine symbols */ true}, {0.155F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 14, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::A2, /* ZCZ */ 15, /* combine symbols */ true}, {0.119F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.234F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.995F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.876F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.789F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.763F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.707F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.646F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.603F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.517F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.465F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.388F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.304F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.232F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.134F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.687F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.616F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.553F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.510F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.456F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.408F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.402F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.370F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.348F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.326F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.289F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.252F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.217F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.173F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.133F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.080F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.401F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.360F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.324F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.298F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.270F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.242F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.223F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.193F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.153F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.130F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.104F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz15, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.080F, 12}, th_flag::orange}, - // The following commented value is the calibrated one - however, we noticed that in synthetic environments with no - // noise/interference, the resulting false-alarm probability is a bit too high. We increase a bit the threshold. - // {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.229F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.986F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.883F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.783F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.770F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.700F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.637F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.599F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.464F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.385F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.304F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.232F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.677F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.622F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.553F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.511F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.414F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.409F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.345F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.283F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.255F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.213F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.132F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.404F, 12}, th_flag::red}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.363F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.298F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.268F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.219F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::orange}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.197F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.155F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.105F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz30, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {1.000F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {1.000F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.986F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.883F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.783F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.770F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.700F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.637F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.599F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.516F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.464F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.385F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.304F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 1, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.232F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.131F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.677F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.622F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.553F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.511F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.458F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.414F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.409F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.374F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.345F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.325F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.283F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.255F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.213F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 2, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.132F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 0, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 1, /* combine symbols */ true}, {0.404F, 12}, th_flag::red}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 2, /* combine symbols */ true}, {0.363F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 3, /* combine symbols */ true}, {0.322F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 4, /* combine symbols */ true}, {0.298F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 5, /* combine symbols */ true}, {0.268F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 6, /* combine symbols */ true}, {0.246F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 7, /* combine symbols */ true}, {0.241F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 8, /* combine symbols */ true}, {0.219F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 9, /* combine symbols */ true}, {0.205F, 12}, th_flag::orange}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 10, /* combine symbols */ true}, {0.197F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 11, /* combine symbols */ true}, {0.171F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 12, /* combine symbols */ true}, {0.155F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 13, /* combine symbols */ true}, {0.131F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 14, /* combine symbols */ true}, {0.105F, 12}, th_flag::green}, // provisional - {{/* nof_rx_ports */ 4, prach_subcarrier_spacing::kHz120, prach_format_type::B4, /* ZCZ */ 15, /* combine symbols */ true}, {0.081F, 12}, th_flag::green}, // provisional - // clang-format on -}); +/// Retrieves the (threshold, margin) pair corresponding to the given configuration. +threshold_and_margin_type get_threshold_and_margin(const threshold_params& params); -} // namespace detail -} // namespace srsran +} // namespace srsran::detail diff --git a/lib/phy/upper/channel_processors/prach_detector_phy_validator_impl.cpp b/lib/phy/upper/channel_processors/prach_detector_phy_validator_impl.cpp index cdac3b1cc4..465289f0b0 100644 --- a/lib/phy/upper/channel_processors/prach_detector_phy_validator_impl.cpp +++ b/lib/phy/upper/channel_processors/prach_detector_phy_validator_impl.cpp @@ -33,10 +33,9 @@ error_type srsran::validate_prach_detector_phy(prach_format_type th_params.zero_correlation_zone = zero_correlation_zone; th_params.combine_symbols = true; - const detail::threshold_and_margin_finder threshold_and_margin_table(detail::all_threshold_and_margins); - auto flag = threshold_and_margin_table.check_flag(th_params); + auto flag = detail::get_threshold_flag(th_params); - if (flag == detail::threshold_and_margin_finder::threshold_flag::red) { + if (flag == detail::threshold_flag::red) { fmt::print("\nThe PRACH detector does not support the configuration {{Format {}, ZCZ {}, SCS {}, Rx ports {}}}.\n", to_string(format), zero_correlation_zone, From 7cddaf27b909fa923c8510344d6080e387bf4a45 Mon Sep 17 00:00:00 2001 From: ninjab3s Date: Tue, 5 Nov 2024 15:22:16 +0100 Subject: [PATCH 13/72] ci: Move ZMQ jobs to hp-generic-2 --- .gitlab/ci/e2e/.env | 2 +- .gitlab/ci/e2e/retina_request_zmq.yml | 12 ++++++------ .gitlab/ci/e2e/retina_request_zmq_cudu.yml | 12 ++++++------ .gitlab/ci/e2e/retina_request_zmq_deb.yml | 12 ++++++------ .gitlab/ci/e2e/retina_request_zmq_srsue.yml | 12 ++++++------ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 7bc128c96c..82bbb483a5 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -8,7 +8,7 @@ OPEN5GS_VERSION=2.7.0 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.3 DPDK_VERSION=23.11.1 -ZMQ_HOSTLABEL_0=kubernetes.io/hostname=rfci-virt-master +ZMQ_HOSTLABEL_0=kubernetes.io/hostname=hp-generic-2 ZMQ_HOSTLABEL_1=kubernetes.io/hostname=srskit2 AMARISOFT_TXRX_BINARY_PATH=../../build_trx_srsran/libtrx_srsran.so GNB_BINARY_PATH=../../build/apps/gnb/gnb diff --git a/.gitlab/ci/e2e/retina_request_zmq.yml b/.gitlab/ci/e2e/retina_request_zmq.yml index bf2bc2678e..3695b2bb00 100644 --- a/.gitlab/ci/e2e/retina_request_zmq.yml +++ b/.gitlab/ci/e2e/retina_request_zmq.yml @@ -15,8 +15,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -40,8 +40,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -62,8 +62,8 @@ requirements: arch: amd64 cpu: - requests: 2 - limits: 2 + requests: 1 + limits: 1 memory: requests: "8G" limits: "8G" diff --git a/.gitlab/ci/e2e/retina_request_zmq_cudu.yml b/.gitlab/ci/e2e/retina_request_zmq_cudu.yml index 960b8bdd97..8aa9318a95 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_cudu.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_cudu.yml @@ -15,8 +15,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -40,8 +40,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -63,8 +63,8 @@ requirements: arch: amd64 cpu: - requests: 2 - limits: 2 + requests: 1 + limits: 1 memory: requests: "8G" limits: "8G" diff --git a/.gitlab/ci/e2e/retina_request_zmq_deb.yml b/.gitlab/ci/e2e/retina_request_zmq_deb.yml index 8a1197e9f9..253f1910c5 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_deb.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_deb.yml @@ -15,8 +15,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -40,8 +40,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -60,8 +60,8 @@ requirements: arch: amd64 cpu: - requests: 2 - limits: 2 + requests: 1 + limits: 1 memory: requests: "8G" limits: "8G" diff --git a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml index 9f4f804687..94aef1e028 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_srsue.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_srsue.yml @@ -14,8 +14,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -35,8 +35,8 @@ requirements: arch: amd64 cpu: - requests: 10 - limits: 10 + requests: 5 + limits: 5 memory: requests: "26G" limits: "26G" @@ -57,8 +57,8 @@ requirements: arch: amd64 cpu: - requests: 2 - limits: 2 + requests: 1 + limits: 1 memory: requests: "8G" limits: "8G" From eeab20f02db5193184c73b4ae32c18ac1b4e9bc2 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 4 Nov 2024 17:05:47 +0100 Subject: [PATCH 14/72] phy: initial PUCCH benchmark phy: fix compilation phy: fix compilation --- lib/phy/upper/uplink_processor_impl.cpp | 7 +- .../upper/channel_processors/CMakeLists.txt | 1 + .../channel_processors/pucch/CMakeLists.txt | 25 + .../pucch/pucch_processor_benchmark.cpp | 577 ++++++++++++++++++ 4 files changed, 608 insertions(+), 2 deletions(-) create mode 100644 tests/benchmarks/phy/upper/channel_processors/pucch/CMakeLists.txt create mode 100644 tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp diff --git a/lib/phy/upper/uplink_processor_impl.cpp b/lib/phy/upper/uplink_processor_impl.cpp index 207681d83c..b7a9167339 100644 --- a/lib/phy/upper/uplink_processor_impl.cpp +++ b/lib/phy/upper/uplink_processor_impl.cpp @@ -116,18 +116,23 @@ void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& not switch (pdu.context.format) { case pucch_format::FORMAT_0: proc_result = pucch_proc->process(grid.get_reader(), pdu.format0); + l1_tracer << trace_event("pucch0", tp); break; case pucch_format::FORMAT_1: proc_result = pucch_proc->process(grid.get_reader(), pdu.format1); + l1_tracer << trace_event("pucch1", tp); break; case pucch_format::FORMAT_2: proc_result = pucch_proc->process(grid.get_reader(), pdu.format2); + l1_tracer << trace_event("pucch2", tp); break; case pucch_format::FORMAT_3: proc_result = pucch_proc->process(grid.get_reader(), pdu.format3); + l1_tracer << trace_event("pucch3", tp); break; case pucch_format::FORMAT_4: proc_result = pucch_proc->process(grid.get_reader(), pdu.format4); + l1_tracer << trace_event("pucch4", tp); break; default: srsran_assert(0, "Invalid PUCCH format={}", pdu.context.format); @@ -140,8 +145,6 @@ void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& not // Notify the PUCCH results. notifier.on_new_pucch_results(result); - - l1_tracer << trace_event("process_pucch", tp); } void uplink_processor_impl::process_srs(upper_phy_rx_results_notifier& notifier, diff --git a/tests/benchmarks/phy/upper/channel_processors/CMakeLists.txt b/tests/benchmarks/phy/upper/channel_processors/CMakeLists.txt index 8488d67e41..6c8120f823 100644 --- a/tests/benchmarks/phy/upper/channel_processors/CMakeLists.txt +++ b/tests/benchmarks/phy/upper/channel_processors/CMakeLists.txt @@ -6,6 +6,7 @@ # the distribution. # +add_subdirectory(pucch) add_subdirectory(pusch) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test_data) diff --git a/tests/benchmarks/phy/upper/channel_processors/pucch/CMakeLists.txt b/tests/benchmarks/phy/upper/channel_processors/pucch/CMakeLists.txt new file mode 100644 index 0000000000..d962fe0148 --- /dev/null +++ b/tests/benchmarks/phy/upper/channel_processors/pucch/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +add_executable(pucch_processor_benchmark pucch_processor_benchmark.cpp) +set(pucch_PROCESSOR_LIBRARIES srsran_phy_support + srsran_pucch_processor + srsran_channel_equalizer + srsran_channel_processors + srsran_transform_precoding + srslog + srsvec) + +target_link_libraries(pucch_processor_benchmark + srsran_channel_equalizer + srsran_channel_processors + srsran_pucch_processor + srsran_transform_precoding + srslog + srsvec) +add_test(pucch_processor_benchmark pucch_processor_benchmark -m silent -R 1 -B 1 -T 2) diff --git a/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp new file mode 100644 index 0000000000..150f60204f --- /dev/null +++ b/tests/benchmarks/phy/upper/channel_processors/pucch/pucch_processor_benchmark.cpp @@ -0,0 +1,577 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/adt/to_array.h" +#include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/support/support_factories.h" +#include "srsran/phy/upper/channel_processors/pucch/factories.h" +#include "srsran/ran/pucch/pucch_constants.h" +#include "srsran/support/benchmark_utils.h" +#include "srsran/support/complex_normal_random.h" +#include "srsran/support/executors/task_worker_pool.h" +#include "srsran/support/executors/unique_thread.h" +#include "srsran/support/math/math_utils.h" +#include "srsran/support/srsran_test.h" +#include +#include + +using namespace srsran; + +// The benchmark configuration consists any of the PUCCH configurations. +using pucch_configuration = std::variant; + +namespace { + +enum class benchmark_modes : unsigned { silent, latency, throughput_total, throughput_thread, all, invalid }; + +} // namespace + +static const char* to_string(benchmark_modes mode) +{ + switch (mode) { + case benchmark_modes::silent: + return "silent"; + case benchmark_modes::latency: + return "latency"; + case benchmark_modes::throughput_total: + return "throughput_total"; + case benchmark_modes::throughput_thread: + return "throughput_thread"; + case benchmark_modes::all: + return "all"; + case benchmark_modes::invalid: + default: + return "invalid"; + } +} + +static benchmark_modes to_benchmark_mode(const char* string) +{ + for (unsigned mode_i = static_cast(benchmark_modes::silent); + mode_i != static_cast(benchmark_modes::invalid); + ++mode_i) { + benchmark_modes mode = static_cast(mode_i); + if (strcmp(to_string(mode), string) == 0) { + return mode; + } + } + return benchmark_modes::invalid; +} + +// Maximum number of threads given the CPU hardware. +static const unsigned max_nof_threads = std::thread::hardware_concurrency(); + +// General test configuration parameters. +static constexpr subcarrier_spacing scs = subcarrier_spacing::kHz30; +static constexpr cyclic_prefix cp = cyclic_prefix::NORMAL; +static constexpr unsigned bwp_start_rb = 0; +static constexpr unsigned bwp_size_rb = MAX_RB; +static constexpr unsigned max_nof_ports = 4; +static uint64_t nof_repetitions = 1000; +static uint64_t nof_threads = 1; +static uint64_t batch_size_per_thread = 100; +static std::string selected_profile_name = "all"; +static benchmark_modes benchmark_mode = benchmark_modes::latency; +static std::unique_ptr> worker_pool = nullptr; +static std::unique_ptr> executor = nullptr; + +// Thread shared variables. +static constexpr auto thread_sync_sleep_duration = std::chrono::nanoseconds(100U); +static std::atomic thread_quit = {}; +static std::atomic pending_count = {0}; +static std::atomic finish_count = {0}; + +// Test profile structure, initialized with default profile values. +struct test_profile { + std::string name = "none"; + std::string description = "TBD."; + pucch_configuration pucch_config = pucch_processor::format0_configuration{}; +}; + +// Profile selected during test execution. +static test_profile selected_profile = {}; + +// Available test profiles. +static const auto profile_set = to_array({ + test_profile{ + .name = "Format0", + .description = + "PUCCH Format 0 with frequency hopping, the maximum number of cyclic shifts and four receive ports.", + .pucch_config = pucch_processor::format0_configuration{.context = std::nullopt, + .slot = slot_point(to_numerology_value(scs), 0), + .cp = cp, + .bwp_size_rb = bwp_size_rb, + .bwp_start_rb = bwp_start_rb, + .starting_prb = 0, + .second_hop_prb = 5, + .start_symbol_index = 0, + .nof_symbols = 2, + .initial_cyclic_shift = 0, + .n_id = 0, + .nof_harq_ack = 2, + .sr_opportunity = true, + .ports = {0, 1, 2, 3}}}, + + test_profile{ + .name = "Format1", + .description = + "PUCCH Format 1 with frequency hopping, the maximum HARQ-ACK feedback bits and four receive ports.", + .pucch_config = pucch_processor::format1_configuration{.context = std::nullopt, + .slot = slot_point(to_numerology_value(scs), 0), + .bwp_size_rb = bwp_size_rb, + .bwp_start_rb = bwp_start_rb, + .cp = cp, + .starting_prb = 0, + .second_hop_prb = 5, + .n_id = 0, + .nof_harq_ack = 2, + .ports = {0, 1, 2, 3}, + .initial_cyclic_shift = 0, + .nof_symbols = 14, + .start_symbol_index = 0, + .time_domain_occ = 1}}, + + test_profile{ + .name = "Format2_4bit", + .description = + "PUCCH Format 2 with frequency hopping, the maximum HARQ-ACK feedback bits and four receive ports.", + .pucch_config = pucch_processor::format2_configuration{.context = std::nullopt, + .slot = slot_point(to_numerology_value(scs), 0), + .cp = cp, + .ports = {0, 1, 2, 3}, + .bwp_size_rb = bwp_size_rb, + .bwp_start_rb = bwp_start_rb, + .starting_prb = 0, + .second_hop_prb = 5, + .nof_prb = 16, + .start_symbol_index = 0, + .nof_symbols = 2, + .rnti = 0x1234, + .n_id = 0, + .n_id_0 = 0, + .nof_harq_ack = 0, + .nof_csi_part1 = 4, + .nof_csi_part2 = 0}}, + + test_profile{ + .name = "Format2_10bit", + .description = + "PUCCH Format 2 with frequency hopping, the maximum HARQ-ACK feedback bits and four receive ports.", + .pucch_config = pucch_processor::format2_configuration{.context = std::nullopt, + .slot = slot_point(to_numerology_value(scs), 0), + .cp = cp, + .ports = {0, 1, 2, 3}, + .bwp_size_rb = bwp_size_rb, + .bwp_start_rb = bwp_start_rb, + .starting_prb = 0, + .second_hop_prb = 5, + .nof_prb = 16, + .start_symbol_index = 0, + .nof_symbols = 2, + .rnti = 0x1234, + .n_id = 0, + .n_id_0 = 0, + .nof_harq_ack = 0, + .nof_csi_part1 = 11, + .nof_csi_part2 = 0}}, + + test_profile{ + .name = "Format2_30bit", + .description = + "PUCCH Format 2 with frequency hopping, the maximum HARQ-ACK feedback bits and four receive ports.", + .pucch_config = pucch_processor::format2_configuration{.context = std::nullopt, + .slot = slot_point(to_numerology_value(scs), 0), + .cp = cp, + .ports = {0, 1, 2, 3}, + .bwp_size_rb = bwp_size_rb, + .bwp_start_rb = bwp_start_rb, + .starting_prb = 0, + .second_hop_prb = 5, + .nof_prb = 16, + .start_symbol_index = 0, + .nof_symbols = 2, + .rnti = 0x1234, + .n_id = 0, + .n_id_0 = 0, + .nof_harq_ack = 0, + .nof_csi_part1 = 30, + .nof_csi_part2 = 0}}, +}); + +static void usage(const char* prog) +{ + fmt::print("Usage: {} [-m benchmark mode] [-R repetitions] [-B Batch size per thread] [-T number of threads] [-P " + "profile] [-h]\n", + prog); + fmt::print("\t-m Benchmark mode. [Default {}]\n", to_string(benchmark_mode)); + fmt::print("\t\t {:<20}It does not print any result.\n", to_string(benchmark_modes::silent)); + fmt::print("\t\t {:<20}Prints the overall average execution time.\n", to_string(benchmark_modes::latency)); + fmt::print("\t\t {:<20}Prints the total aggregated throughput.\n", to_string(benchmark_modes::throughput_total)); + fmt::print("\t\t {:<20}Prints the average single thread throughput.\n", + to_string(benchmark_modes::throughput_thread)); + fmt::print("\t\t {:<20}Prints all the previous modes.\n", to_string(benchmark_modes::all)); + fmt::print("\t-R Repetitions [Default {}]\n", nof_repetitions); + fmt::print("\t-B Batch size [Default {}]\n", batch_size_per_thread); + fmt::print("\t-T Number of threads [Default {}, max. {}]\n", nof_threads, max_nof_threads); + fmt::print("\t-P Benchmark profile. [Default {}]\n", selected_profile_name); + for (const test_profile& profile : profile_set) { + fmt::print("\t\t {:<40} {}\n", profile.name, profile.description); + } + + fmt::print("\t-h Show this message\n"); +} + +static int parse_args(int argc, char** argv) +{ + int opt = 0; + while ((opt = getopt(argc, argv, "R:T:B:P:m:h")) != -1) { + switch (opt) { + case 'R': + nof_repetitions = std::strtol(optarg, nullptr, 10); + break; + case 'T': + nof_threads = std::min(max_nof_threads, static_cast(std::strtol(optarg, nullptr, 10))); + break; + case 'B': + batch_size_per_thread = std::strtol(optarg, nullptr, 10); + break; + case 'P': + selected_profile_name = std::string(optarg); + break; + case 'm': + benchmark_mode = to_benchmark_mode(optarg); + if (benchmark_mode == benchmark_modes::invalid) { + fmt::print(stderr, "Invalid benchmark mode '{}'\n", optarg); + usage(argv[0]); + return -1; + } + break; + case 'h': + default: + usage(argv[0]); + exit(0); + } + } + + if (selected_profile_name != "all") { + // Search profile. + bool profile_found = false; + for (const auto& candidate_profile : profile_set) { + if (selected_profile_name == candidate_profile.name) { + selected_profile = candidate_profile; + srslog::fetch_basic_logger("TEST").info("Loading profile: {}", selected_profile.name); + profile_found = true; + break; + } + } + if (!profile_found) { + usage(argv[0]); + srslog::fetch_basic_logger("TEST").error("Invalid profile: {}.", selected_profile_name); + fmt::print(stderr, "Invalid profile: {}.\n", selected_profile_name); + return -1; + } + } + + return 0; +} + +static pucch_processor_factory& get_pucch_processor_factory() +{ + static std::shared_ptr pucch_proc_factory = nullptr; + + if (pucch_proc_factory) { + return *pucch_proc_factory; + } + + // Create factories required by the PUCCH demodulator factory. + std::shared_ptr equalizer_factory = create_channel_equalizer_generic_factory(); + TESTASSERT(equalizer_factory); + + std::shared_ptr demod_factory = create_channel_modulation_sw_factory(); + TESTASSERT(demod_factory); + + std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); + TESTASSERT(prg_factory); + + std::shared_ptr dft_factory = create_dft_processor_factory_fftw_slow(); + TESTASSERT(dft_factory); + + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_factory, pucch_constants::FORMAT3_MAX_NPRB + 1); + TESTASSERT(precoding_factory); + + // Create PUCCH demodulator factory. + std::shared_ptr pucch_demod_factory = + create_pucch_demodulator_factory_sw(equalizer_factory, demod_factory, prg_factory, precoding_factory); + TESTASSERT(pucch_demod_factory); + + // Create factories required by the PUCCH channel estimator factory. + std::shared_ptr lpg_factory = create_low_papr_sequence_generator_sw_factory(); + TESTASSERT(lpg_factory); + + std::shared_ptr lpc_factory = + create_low_papr_sequence_collection_sw_factory(lpg_factory); + TESTASSERT(lpc_factory); + + std::shared_ptr ta_estimator_factory = + create_time_alignment_estimator_dft_factory(dft_factory); + TESTASSERT(ta_estimator_factory); + + // Create channel estimator factory. + std::shared_ptr port_chan_estimator_factory = + create_port_channel_estimator_factory_sw(ta_estimator_factory); + TESTASSERT(port_chan_estimator_factory); + + std::shared_ptr estimator_factory = + create_dmrs_pucch_estimator_factory_sw(prg_factory, lpc_factory, port_chan_estimator_factory); + TESTASSERT(estimator_factory); + + // Create PUCCH detector factory. + std::shared_ptr detector_factory = + create_pucch_detector_factory_sw(lpc_factory, prg_factory, equalizer_factory); + TESTASSERT(detector_factory); + + // Create short block detector factory. + std::shared_ptr short_block_det_factory = create_short_block_detector_factory_sw(); + TESTASSERT(short_block_det_factory); + + // Create polar decoder factory. + std::shared_ptr polar_dec_factory = create_polar_factory_sw(); + TESTASSERT(polar_dec_factory); + + // Create CRC calculator factory. + std::shared_ptr crc_calc_factory = create_crc_calculator_factory_sw("auto"); + TESTASSERT(crc_calc_factory); + + // Create UCI decoder factory. + std::shared_ptr uci_dec_factory = + create_uci_decoder_factory_generic(short_block_det_factory, polar_dec_factory, crc_calc_factory); + TESTASSERT(uci_dec_factory); + + // Create PUCCH processor factory. + channel_estimate::channel_estimate_dimensions max_dimensions = {.nof_prb = bwp_size_rb, + .nof_symbols = get_nsymb_per_slot(cp), + .nof_rx_ports = max_nof_ports, + .nof_tx_layers = pucch_constants::MAX_LAYERS}; + pucch_proc_factory = create_pucch_processor_factory_sw( + estimator_factory, detector_factory, pucch_demod_factory, uci_dec_factory, max_dimensions); + TESTASSERT(pucch_proc_factory); + + if (nof_threads > 1) { + pucch_proc_factory = create_pucch_processor_pool_factory(std::move(pucch_proc_factory), nof_threads); + TESTASSERT(pucch_proc_factory); + } + + return *pucch_proc_factory; +} + +// Instantiates the pucch processor and validator. +static std::tuple, std::unique_ptr> create_processor() +{ + pucch_processor_factory& pucch_proc_factory = get_pucch_processor_factory(); + + // Create pucch processor. + std::unique_ptr processor = pucch_proc_factory.create(); + TESTASSERT(processor); + + // Create pucch processor validator. + std::unique_ptr validator = pucch_proc_factory.create_validator(); + TESTASSERT(validator); + + return std::make_tuple(std::move(processor), std::move(validator)); +} + +template +std::optional get_config(const pucch_configuration& test_case) +{ + if (std::holds_alternative(test_case)) { + return std::get(test_case); + } + + return std::nullopt; +} + +static void thread_process(pucch_processor& proc, const pucch_configuration& config, const resource_grid_reader& grid) +{ + while (!thread_quit) { + // If the pending count is equal to or lower than zero, wait for a new start. + while (pending_count.fetch_sub(1) <= 0) { + // Wait for pending to non-negative. + while (pending_count.load() <= 0) { + // Sleep. + std::this_thread::sleep_for(thread_sync_sleep_duration); + + // Quit if signaled. + if (thread_quit) { + return; + } + } + } + + if (auto pucch0 = get_config(config)) { + proc.process(grid, *pucch0); + } else if (auto pucch1 = get_config(config)) { + proc.process(grid, *pucch1); + } else if (auto pucch2 = get_config(config)) { + proc.process(grid, *pucch2); + } else if (auto pucch3 = get_config(config)) { + proc.process(grid, *pucch3); + } else if (auto pucch4 = get_config(config)) { + proc.process(grid, *pucch4); + } + + // Notify finish count. + ++finish_count; + } +} + +// Creates a resource grid. +static std::unique_ptr create_resource_grid(unsigned nof_ports, unsigned nof_symbols, unsigned nof_subc) +{ + std::shared_ptr rg_factory = create_resource_grid_factory(); + TESTASSERT(rg_factory != nullptr, "Invalid resource grid factory."); + + return rg_factory->create(nof_ports, nof_symbols, nof_subc); +} + +int main(int argc, char** argv) +{ + int ret = parse_args(argc, argv); + if (ret < 0) { + return ret; + } + + // Inform of the benchmark configuration. + if (benchmark_mode != benchmark_modes::silent) { + fmt::print("Launching benchmark for {} threads, {} times per thread, and {} repetitions. Using {} profile.\n", + nof_threads, + batch_size_per_thread, + nof_repetitions, + selected_profile_name); + } + + benchmarker perf_meas("pucch processor", nof_repetitions); + + // Pseudo-random generator. + std::mt19937 rgen(0); + + // Create resource grid. + std::unique_ptr grid = create_resource_grid(max_nof_ports, get_nsymb_per_slot(cp), NRE * bwp_size_rb); + TESTASSERT(grid); + + // Standard complex normal distribution with zero mean. + complex_normal_distribution c_normal_dist = {}; + + // Fill the grid with the random RE. + for (unsigned i_rx_port = 0; i_rx_port != max_nof_ports; ++i_rx_port) { + for (unsigned i_symbol = 0, i_symbol_end = get_nsymb_per_slot(cp); i_symbol != i_symbol_end; ++i_symbol) { + // Obtain view of the OFDM symbol. + span re_view = grid->get_writer().get_view(i_rx_port, i_symbol); + + // Generate random RE. + std::generate(re_view.begin(), re_view.end(), [&rgen, &c_normal_dist]() { return c_normal_dist(rgen); }); + } + } + + // Create processor and validator. + std::unique_ptr processor; + std::unique_ptr validator; + std::tie(processor, validator) = create_processor(); + + for (const test_profile& profile : profile_set) { + // Skip profile if the selected is not default and does not match the current profile. + if ((selected_profile_name != "all") && (profile.name != selected_profile_name)) { + continue; + } + // Get the pucch configuration. + const pucch_configuration& config = profile.pucch_config; + + // Make sure the configuration is valid. + if (auto pucch0 = get_config(config)) { + TESTASSERT(validator->is_valid(*pucch0)); + } else if (auto pucch1 = get_config(config)) { + TESTASSERT(validator->is_valid(*pucch1)); + } else if (auto pucch2 = get_config(config)) { + TESTASSERT(validator->is_valid(*pucch2)); + } else if (auto pucch3 = get_config(config)) { + TESTASSERT(validator->is_valid(*pucch3)); + } else if (auto pucch4 = get_config(config)) { + TESTASSERT(validator->is_valid(*pucch4)); + } + + // Reset finish counter. + finish_count = 0; + pending_count = 0; + thread_quit = false; + + // Prepare threads for the current case. + std::vector threads(nof_threads); + for (unsigned thread_id = 0; thread_id != nof_threads; ++thread_id) { + // Select thread. + unique_thread& thread = threads[thread_id]; + + // Create thread. + thread = unique_thread("thread_" + std::to_string(thread_id), [&proc = *processor, &config, &grid] { + thread_process(proc, config, grid.get()->get_reader()); + }); + } + + // Wait for finish thread init. + while (pending_count.load() != -static_cast(nof_threads)) { + std::this_thread::sleep_for(thread_sync_sleep_duration); + } + + // Run the benchmark. + perf_meas.new_measure(profile.name, nof_threads * batch_size_per_thread, []() mutable { + // Notify start. + finish_count = 0; + pending_count = nof_threads * batch_size_per_thread; + + // Wait for finish. + while (finish_count.load() != (nof_threads * batch_size_per_thread)) { + std::this_thread::sleep_for(thread_sync_sleep_duration); + } + }); + + thread_quit = true; + + for (unique_thread& thread : threads) { + thread.join(); + } + } + + // Print latency. + if ((benchmark_mode == benchmark_modes::latency) || (benchmark_mode == benchmark_modes::all)) { + fmt::print("\n--- Average latency ---\n"); + perf_meas.print_percentiles_time("microseconds", 1e-3 / static_cast(batch_size_per_thread)); + } + + // Print total aggregated throughput. + if ((benchmark_mode == benchmark_modes::throughput_total) || (benchmark_mode == benchmark_modes::all)) { + fmt::print("\n--- Total throughput ---\n"); + perf_meas.print_percentiles_throughput("transmissions"); + } + + // Print average throughput per thread. + if ((benchmark_mode == benchmark_modes::throughput_thread) || (benchmark_mode == benchmark_modes::all)) { + fmt::print("\n--- Thread throughput ---\n"); + perf_meas.print_percentiles_throughput("transmissions", 1.0 / static_cast(nof_threads)); + } + + if (worker_pool) { + worker_pool->stop(); + } + + return 0; +} From 1cec7f70ac0bb154206fb40944d5be2cb9a54b60 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 5 Nov 2024 15:29:05 +0100 Subject: [PATCH 15/72] support: fix assignment of virtual tables in unique_function move ctor/assignment operator --- include/srsran/adt/unique_function.h | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/include/srsran/adt/unique_function.h b/include/srsran/adt/unique_function.h index e96eea6c19..522928b7fe 100644 --- a/include/srsran/adt/unique_function.h +++ b/include/srsran/adt/unique_function.h @@ -131,7 +131,7 @@ class unique_function template unique_function(unique_function&& rhs) noexcept { - using FunT = unique_function; + using OtherFunT = unique_function; if constexpr (capacity >= Capacity2) { // The capacity of this is equal or higher. We can just move the buffer. @@ -143,13 +143,15 @@ class unique_function static_assert(not ForbidAlloc, "Failed to store the provided unique_function in unique_function specialization that forbids heap " "allocations."); - auto& heap_oper_table = get_heap_table(); - oper_ptr = &heap_oper_table; - if (rhs.oper_ptr == heap_oper_table) { + if (not rhs.is_in_small_buffer()) { + // The functor is in the heap. Just move it. + oper_ptr = rhs.oper_ptr; rhs.oper_ptr = &empty_table; oper_ptr->move(&rhs.buffer, &buffer); } else { - ptr = static_cast(new FunT{std::move(rhs)}); + // The functor is in the small buffer of the rhs. + oper_ptr = &get_heap_table(); + ptr = static_cast(new OtherFunT{std::move(rhs)}); } } } @@ -181,7 +183,7 @@ class unique_function template unique_function& operator=(unique_function&& rhs) noexcept { - using FunT = unique_function; + using OtherFunT = unique_function; oper_ptr->dtor(&buffer); if constexpr (capacity >= Capacity2) { @@ -194,14 +196,15 @@ class unique_function static_assert(not ForbidAlloc, "Failed to store the provided unique_function in unique_function specialization that forbids heap " "allocations."); - auto& heap_oper_table = get_heap_table(); - oper_ptr = &heap_oper_table; - if (rhs.oper_ptr == heap_oper_table) { + if (not rhs.is_in_small_buffer()) { + oper_ptr = rhs.oper_ptr; rhs.oper_ptr = &empty_table; oper_ptr->move(&rhs.buffer, &buffer); } else { - ptr = static_cast(new FunT{std::move(rhs)}); + oper_ptr = &get_heap_table(); + ptr = static_cast(new OtherFunT{std::move(rhs)}); } + rhs.oper_ptr = &empty_table; } return *this; } From a6d53e4a32c94dee77fbee2a3cb3afc125572974 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 5 Nov 2024 15:34:07 +0100 Subject: [PATCH 16/72] support: fix virtual table set in move assignment operator of unique_function --- include/srsran/adt/unique_function.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/srsran/adt/unique_function.h b/include/srsran/adt/unique_function.h index 522928b7fe..9247df99b6 100644 --- a/include/srsran/adt/unique_function.h +++ b/include/srsran/adt/unique_function.h @@ -204,7 +204,6 @@ class unique_function oper_ptr = &get_heap_table(); ptr = static_cast(new OtherFunT{std::move(rhs)}); } - rhs.oper_ptr = &empty_table; } return *this; } From f6ddfe2d7ebd2b31e24e701b2ada95fa2c487843 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 5 Nov 2024 16:51:43 +0100 Subject: [PATCH 17/72] support: overwrite default move ctor and assignment operator --- include/srsran/adt/unique_function.h | 66 ++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/include/srsran/adt/unique_function.h b/include/srsran/adt/unique_function.h index 9247df99b6..c661138077 100644 --- a/include/srsran/adt/unique_function.h +++ b/include/srsran/adt/unique_function.h @@ -98,6 +98,19 @@ template struct is_unique_function> : std::true_type { }; +template +const auto& get_unique_heap_oper_ptr() +{ + static const task_details::heap_table_t heap_oper_table{}; + return heap_oper_table; +} +template +const auto& get_unique_small_oper_ptr() +{ + static const task_details::smallbuffer_table_t small_oper_table{}; + return small_oper_table; +} + } // namespace task_details template @@ -108,31 +121,31 @@ class unique_function using oper_table_t = task_details::oper_table_t; static const task_details::empty_table_t empty_table; - template - static const auto& get_heap_table() - { - static const task_details::heap_table_t heap_oper_table{}; - return heap_oper_table; - } - template - static const auto& get_small_table() - { - static const task_details::smallbuffer_table_t small_oper_table{}; - return small_oper_table; - } - public: static constexpr size_t capacity = Capacity; ///< size of buffer constexpr unique_function() noexcept : oper_ptr(&empty_table) {} + unique_function(const unique_function& rhs) = delete; template unique_function(const unique_function& rhs) = delete; + unique_function(unique_function&& rhs) noexcept + { + oper_ptr = rhs.oper_ptr; + rhs.oper_ptr = &empty_table; + oper_ptr->move(&rhs.buffer, &buffer); + } + template unique_function(unique_function&& rhs) noexcept { using OtherFunT = unique_function; + if (rhs.oper_ptr == &empty_table) { + oper_ptr = &empty_table; + return; + } + if constexpr (capacity >= Capacity2) { // The capacity of this is equal or higher. We can just move the buffer. oper_ptr = rhs.oper_ptr; @@ -150,7 +163,7 @@ class unique_function oper_ptr->move(&rhs.buffer, &buffer); } else { // The functor is in the small buffer of the rhs. - oper_ptr = &get_heap_table(); + oper_ptr = &task_details::get_unique_heap_oper_ptr(); ptr = static_cast(new OtherFunT{std::move(rhs)}); } } @@ -163,29 +176,44 @@ class unique_function if constexpr (sizeof(FunT) <= capacity) { // Fits in small buffer. - oper_ptr = &get_small_table(); + oper_ptr = &task_details::get_unique_small_oper_ptr(); ::new (&buffer) FunT(std::forward(rhs)); } else { // Does not fit in small buffer. static_assert( not ForbidAlloc, "Failed to store provided callback in unique_function specialization that forbids heap allocations."); - oper_ptr = &get_heap_table(); + oper_ptr = &task_details::get_unique_heap_oper_ptr(); ptr = static_cast(new FunT{std::forward(rhs)}); } } ~unique_function() { oper_ptr->dtor(&buffer); } + unique_function& operator=(const unique_function& rhs) = delete; template unique_function& operator=(const unique_function& rhs) = delete; + unique_function& operator=(unique_function&& rhs) noexcept + { + oper_ptr->dtor(&buffer); + oper_ptr = rhs.oper_ptr; + rhs.oper_ptr = &empty_table; + oper_ptr->move(&rhs.buffer, &buffer); + return *this; + } + template unique_function& operator=(unique_function&& rhs) noexcept { using OtherFunT = unique_function; oper_ptr->dtor(&buffer); + if (rhs.oper_ptr == &empty_table) { + oper_ptr = &empty_table; + return *this; + } + if constexpr (capacity >= Capacity2) { // The capacity of this is equal or higher. We can just move the buffer. oper_ptr = rhs.oper_ptr; @@ -201,7 +229,7 @@ class unique_function rhs.oper_ptr = &empty_table; oper_ptr->move(&rhs.buffer, &buffer); } else { - oper_ptr = &get_heap_table(); + oper_ptr = &task_details::get_unique_heap_oper_ptr(); ptr = static_cast(new OtherFunT{std::move(rhs)}); } } @@ -216,14 +244,14 @@ class unique_function oper_ptr->dtor(&buffer); if constexpr (sizeof(FunT) <= capacity) { // Fits in small buffer. - oper_ptr = &get_small_table(); + oper_ptr = &task_details::get_unique_small_oper_ptr(); ::new (&buffer) FunT(std::forward(rhs)); } else { // Does not fit in small buffer. static_assert( not ForbidAlloc, "Failed to store provided callback in unique_function specialization that forbids heap allocations."); - oper_ptr = &get_heap_table(); + oper_ptr = &task_details::get_unique_heap_oper_ptr(); ptr = static_cast(new FunT{std::forward(rhs)}); } return *this; From a71d6fedc05342b147644a840f5902280a8d66b6 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 28 Oct 2024 14:42:23 +0100 Subject: [PATCH 18/72] cu_cp: improve readability of pdu session handling --- ..._session_resource_modification_routine.cpp | 176 ++++++------- .../pdu_session_resource_release_routine.cpp | 34 +-- .../pdu_session_resource_setup_routine.cpp | 234 +++++++++--------- 3 files changed, 226 insertions(+), 218 deletions(-) diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index 102cead465..fb52121923 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -20,26 +20,28 @@ using namespace asn1::rrc_nr; // sub-procedures and update the succeeded/failed fields. /// \brief Handle first Bearer Context Modification response and prepare subsequent UE context modification request. -bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& response_msg, - f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_modify_request modify_request, - const e1ap_bearer_context_modification_response& bearer_context_modification_response, - up_config_update& next_config, - srslog::basic_logger& logger); +bool handle_bearer_context_modification_response( + cu_cp_pdu_session_resource_modify_response& response_msg, + f1ap_ue_context_modification_request& ue_context_mod_request, + const cu_cp_pdu_session_resource_modify_request& modify_request, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_config_update& next_config, + srslog::basic_logger& logger); /// \brief Handle UE context modification response and prepare second Bearer Context Modification. -bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& response_msg, - e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const cu_cp_pdu_session_resource_modify_request modify_request, - const f1ap_ue_context_modification_response& ue_context_modification_response, - const up_config_update& next_config, - const srslog::basic_logger& logger); - -/// \brief Handle RRC reconfiguration result -bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& response_msg, - const cu_cp_pdu_session_resource_modify_request& modify_request, - bool rrc_reconfig_result, - const srslog::basic_logger& logger); +bool handle_ue_context_modification_response( + cu_cp_pdu_session_resource_modify_response& response_msg, + e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const cu_cp_pdu_session_resource_modify_request& modify_request, + const f1ap_ue_context_modification_response& ue_context_modification_response, + const up_config_update& next_config, + const srslog::basic_logger& logger); + +/// \brief Handle RRC reconfiguration result. +bool handle_rrc_reconfiguration_response(cu_cp_pdu_session_resource_modify_response& response_msg, + const cu_cp_pdu_session_resource_modify_request& modify_request, + bool rrc_reconfig_result, + const srslog::basic_logger& logger); pdu_session_resource_modification_routine::pdu_session_resource_modification_routine( const cu_cp_pdu_session_resource_modify_request& modify_request_, @@ -80,72 +82,72 @@ void pdu_session_resource_modification_routine::operator()( } { - // prepare first BearerContextModificationRequest + // Prepare first BearerContextModificationRequest. bearer_context_modification_request.ng_ran_bearer_context_mod_request.emplace(); // initialize fresh message fill_initial_e1ap_bearer_context_modification_request(bearer_context_modification_request); - // call E1AP procedure and wait for BearerContextModificationResponse + // Call E1AP procedure and wait for BearerContextModificationResponse. CORO_AWAIT_VALUE( bearer_context_modification_response, e1ap_bearer_ctxt_mng.handle_bearer_context_modification_request(bearer_context_modification_request)); - // Handle BearerContextModificationResponse and fill subsequent UE context modification - if (handle_procedure_response(response_msg, - ue_context_mod_request, - modify_request, - bearer_context_modification_response, - next_config, - logger) == false) { + // Handle BearerContextModificationResponse and fill subsequent UEContextModificationRequest. + if (!handle_bearer_context_modification_response(response_msg, + ue_context_mod_request, + modify_request, + bearer_context_modification_response, + next_config, + logger)) { logger.warning("ue={}: \"{}\" failed to modify bearer at CU-UP", modify_request.ue_index, name()); CORO_EARLY_RETURN(generate_pdu_session_resource_modify_response(false)); } } { - // prepare UE Context Modification Request and call F1 notifier + // Prepare UEContextModificationRequest and call F1 notifier. ue_context_mod_request.ue_index = modify_request.ue_index; CORO_AWAIT_VALUE(ue_context_modification_response, f1ap_ue_ctxt_mng.handle_ue_context_modification_request(ue_context_mod_request)); - // Handle UE Context Modification Response - if (handle_procedure_response(response_msg, - bearer_context_modification_request, - modify_request, - ue_context_modification_response, - next_config, - logger) == false) { + // Handle UEContextModificationResponse. + if (!handle_ue_context_modification_response(response_msg, + bearer_context_modification_request, + modify_request, + ue_context_modification_response, + next_config, + logger)) { logger.warning("ue={}: \"{}\" failed to modify UE context at DU", modify_request.ue_index, name()); CORO_EARLY_RETURN(generate_pdu_session_resource_modify_response(false)); } } - // If needed, inform CU-UP about the new TEID for UL F1u traffic + // If needed, inform CU-UP about the new TEID for UL F1u traffic. if (bearer_context_modification_request.ng_ran_bearer_context_mod_request.has_value()) { - // add remaining fields to BearerContextModificationRequest + // Add remaining fields to BearerContextModificationRequest. bearer_context_modification_request.ue_index = modify_request.ue_index; - // call E1AP procedure and wait for BearerContextModificationResponse + // Call E1AP procedure and wait for BearerContextModificationResponse. CORO_AWAIT_VALUE( bearer_context_modification_response, e1ap_bearer_ctxt_mng.handle_bearer_context_modification_request(bearer_context_modification_request)); - // Handle BearerContextModificationResponse - if (handle_procedure_response(response_msg, - ue_context_mod_request, - modify_request, - bearer_context_modification_response, - next_config, - logger) == false) { + // Handle BearerContextModificationResponse. + if (!handle_bearer_context_modification_response(response_msg, + ue_context_mod_request, + modify_request, + bearer_context_modification_response, + next_config, + logger)) { logger.warning("ue={}: \"{}\" failed to modify bearer at CU-UP", modify_request.ue_index, name()); CORO_EARLY_RETURN(generate_pdu_session_resource_modify_response(false)); } } { - // prepare RRC Reconfiguration and call RRC UE notifier + // Prepare RRCReconfiguration and call RRC UE notifier. { - // get NAS PDUs as received by AMF + // Get NAS PDUs as received by AMF. std::vector nas_pdus; for (const auto& pdu_session : modify_request.pdu_session_res_modify_items) { if (!pdu_session.nas_pdu.empty()) { @@ -172,17 +174,17 @@ void pdu_session_resource_modification_routine::operator()( CORO_AWAIT_VALUE(rrc_reconfig_result, rrc_ue->handle_rrc_reconfiguration_request(rrc_reconfig_args)); - // Handle RRC Reconfiguration result. - if (handle_procedure_response(response_msg, modify_request, rrc_reconfig_result, logger) == false) { + // Handle RRCReconfiguration result. + if (!handle_rrc_reconfiguration_response(response_msg, modify_request, rrc_reconfig_result, logger)) { logger.warning("ue={}: \"{}\" RRC reconfiguration failed", modify_request.ue_index, name()); - // Notify NGAP to request UE context release from AMF + // Notify NGAP to request UE context release from AMF. ue_task_sched.schedule_async_task(cu_cp_notifier.handle_ue_context_release( {modify_request.ue_index, {}, ngap_cause_radio_network_t::release_due_to_ngran_generated_reason})); CORO_EARLY_RETURN(generate_pdu_session_resource_modify_response(false)); } } - // we are done + // We are done. CORO_RETURN(generate_pdu_session_resource_modify_response(true)); } @@ -242,25 +244,26 @@ void pdu_session_resource_modification_routine::fill_initial_e1ap_bearer_context } } -// \brief Handle first Bearer Context Modification response and prepare subsequent UE context modification request. -bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& response_msg, - f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_modify_request modify_request, - const e1ap_bearer_context_modification_response& bearer_context_modification_response, - up_config_update& next_config, - srslog::basic_logger& logger) +// \brief Handle first BearerContextModificationResponse and prepare subsequent UEContextModificationRequest. +bool handle_bearer_context_modification_response( + cu_cp_pdu_session_resource_modify_response& response_msg, + f1ap_ue_context_modification_request& ue_context_mod_request, + const cu_cp_pdu_session_resource_modify_request& modify_request, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_config_update& next_config, + srslog::basic_logger& logger) { - // Traverse modify list - if (update_modify_list(response_msg.pdu_session_res_modify_list, - ue_context_mod_request, - modify_request.pdu_session_res_modify_items, - bearer_context_modification_response.pdu_session_resource_modified_list, - next_config, - logger) == false) { + // Traverse modify list. + if (!update_modify_list(response_msg.pdu_session_res_modify_list, + ue_context_mod_request, + modify_request.pdu_session_res_modify_items, + bearer_context_modification_response.pdu_session_resource_modified_list, + next_config, + logger)) { return false; } - // Traverse failed list + // Traverse failed list. update_failed_list(response_msg.pdu_session_res_failed_to_modify_list, bearer_context_modification_response.pdu_session_resource_failed_list, next_config); @@ -268,21 +271,22 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& return bearer_context_modification_response.success; } -// Handle UE context modification response and prepare second Bearer Context Modification. -bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& response_msg, - e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const cu_cp_pdu_session_resource_modify_request modify_request, - const f1ap_ue_context_modification_response& ue_context_modification_response, - const up_config_update& next_config, - const srslog::basic_logger& logger) +// Handle UEContextModificationResponse and prepare second BearerContextModificationRequest. +bool handle_ue_context_modification_response( + cu_cp_pdu_session_resource_modify_response& response_msg, + e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const cu_cp_pdu_session_resource_modify_request& modify_request, + const f1ap_ue_context_modification_response& ue_context_modification_response, + const up_config_update& next_config, + const srslog::basic_logger& logger) { - // Traverse modify list - if (update_modify_list(response_msg.pdu_session_res_modify_list, - bearer_ctxt_mod_request, - modify_request.pdu_session_res_modify_items, - ue_context_modification_response, - next_config, - logger) == false) { + // Traverse modify list. + if (!update_modify_list(response_msg.pdu_session_res_modify_list, + bearer_ctxt_mod_request, + modify_request.pdu_session_res_modify_items, + ue_context_modification_response, + next_config, + logger)) { return false; } @@ -301,14 +305,14 @@ void fill_modify_failed_list(cu_cp_pdu_session_resource_modify_response& re } } -// Handle RRC reconfiguration result -bool handle_procedure_response(cu_cp_pdu_session_resource_modify_response& response_msg, - const cu_cp_pdu_session_resource_modify_request& modify_request, - bool rrc_reconfig_result, - const srslog::basic_logger& logger) +// Handle RRCReconfiguration result. +bool handle_rrc_reconfiguration_response(cu_cp_pdu_session_resource_modify_response& response_msg, + const cu_cp_pdu_session_resource_modify_request& modify_request, + bool rrc_reconfig_result, + const srslog::basic_logger& logger) { // Let all PDU sessions fail if response is negative. - if (rrc_reconfig_result == false) { + if (!rrc_reconfig_result) { fill_modify_failed_list(response_msg, modify_request); } diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp index 4160d5992b..1e20eb20b1 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -36,10 +36,10 @@ pdu_session_resource_release_routine::pdu_session_resource_release_routine( } // Handle RRC reconfiguration result. -bool handle_procedure_response(cu_cp_pdu_session_resource_release_response& response_msg, - const cu_cp_pdu_session_resource_release_command& release_cmd, - bool rrc_reconfig_result, - const srslog::basic_logger& logger) +bool handle_rrc_reconfiguration_response(cu_cp_pdu_session_resource_release_response& response_msg, + const cu_cp_pdu_session_resource_release_command& release_cmd, + bool rrc_reconfig_result, + const srslog::basic_logger& logger) { // Let all PDU sessions fail if response is negative. if (!rrc_reconfig_result) { @@ -67,19 +67,19 @@ void pdu_session_resource_release_routine::operator()( next_config = up_resource_mng.calculate_update(release_cmd); } - // Inform the CU-UP about the release of the bearer context + // Inform the CU-UP about the release of the bearer context. if (next_config.pdu_sessions_to_remove_list.size() == up_resource_mng.get_nof_pdu_sessions()) { bearer_context_release_command.ue_index = release_cmd.ue_index; bearer_context_release_command.cause = e1ap_cause_radio_network_t::unspecified; /// NOTE: Only the Bearer Context at the CU-UP will be released. We don't want to release the UE. - // Request BearerContextRelease + // Request BearerContextRelease. CORO_AWAIT(e1ap_bearer_ctxt_mng.handle_bearer_context_release_command(bearer_context_release_command)); - } else { // Inform CU-UP about the release of a bearer + } else { // Inform CU-UP about the release of a bearer. - // prepare BearerContextModificationRequest and call e1 notifier + // Prepare BearerContextModificationRequest and call E1 notifier. bearer_context_modification_request.ue_index = release_cmd.ue_index; for (const auto& pdu_session_res_to_release : next_config.pdu_sessions_to_remove_list) { @@ -88,20 +88,20 @@ void pdu_session_resource_release_routine::operator()( bearer_context_modification_request.ng_ran_bearer_context_mod_request = bearer_context_mod_request; } - // call E1AP procedure and wait for BearerContextModificationResponse + // Call E1AP procedure and wait for BearerContextModificationResponse. CORO_AWAIT_VALUE( bearer_context_modification_response, e1ap_bearer_ctxt_mng.handle_bearer_context_modification_request(bearer_context_modification_request)); - // Handle BearerContextModificationResponse + // Handle BearerContextModificationResponse. if (not bearer_context_modification_response.success) { logger.warning("ue={}: \"{}\" failed to release bearer(s) at CU-UP", release_cmd.ue_index, name()); } } - // Release DRB resources at DU + // Release DRB resources at DU. { - // prepare UeContextModificationRequest and call F1 notifier + // Prepare UeContextModificationRequest and call F1 notifier. ue_context_mod_request.ue_index = release_cmd.ue_index; for (const auto& drb_id : next_config.drb_to_remove_list) { ue_context_mod_request.drbs_to_be_released_list.push_back(drb_id); @@ -110,16 +110,16 @@ void pdu_session_resource_release_routine::operator()( CORO_AWAIT_VALUE(ue_context_modification_response, f1ap_ue_ctxt_mng.handle_ue_context_modification_request(ue_context_mod_request)); - // Handle UE Context Modification Response + // Handle UEContextModificationResponse. if (not ue_context_modification_response.success) { logger.warning("ue={}: \"{}\" failed to release bearer(s) at DU", release_cmd.ue_index, name()); } } { - // prepare RRC Reconfiguration and call RRC UE notifier + // Prepare RRCReconfiguration and call RRC UE notifier. { - // get NAS PDUs as received by AMF + // Get NAS PDUs as received by AMF. std::vector nas_pdus; if (!release_cmd.nas_pdu.empty()) { nas_pdus.push_back(release_cmd.nas_pdu); @@ -144,8 +144,8 @@ void pdu_session_resource_release_routine::operator()( CORO_AWAIT_VALUE(rrc_reconfig_result, rrc_ue->handle_rrc_reconfiguration_request(rrc_reconfig_args)); - // Handle RRC Reconfiguration result. - if (not handle_procedure_response(response_msg, release_cmd, rrc_reconfig_result, logger)) { + // Handle RRCReconfiguration result. + if (not handle_rrc_reconfiguration_response(response_msg, release_cmd, rrc_reconfig_result, logger)) { logger.warning("ue={}: \"{}\" RRC reconfiguration failed", release_cmd.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_release_response(false)); } diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index d4dd5e1a4f..930b43b259 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -18,39 +18,41 @@ using namespace asn1::rrc_nr; // Free function to amend to the final procedure response message. This will take the results from the various // sub-procedures and update the succeeded/failed fields. -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_setup_request setup_msg, - const e1ap_bearer_context_modification_response& bearer_context_modification_response, - up_config_update& next_config, - up_resource_manager& up_resource_mng_, - const security_indication_t& default_security_indication, - srslog::basic_logger& logger); - -// Same as above but taking the result from E1AP Bearer Context Setup message -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_setup_request& setup_msg, - const e1ap_bearer_context_setup_response& bearer_context_setup_response, - up_config_update& next_config, - up_resource_manager& up_resource_mng_, - const security_indication_t& default_security_indication, - srslog::basic_logger& logger); +bool handle_bearer_context_modification_response( + cu_cp_pdu_session_resource_setup_response& response_msg, + f1ap_ue_context_modification_request& ue_context_mod_request, + const cu_cp_pdu_session_resource_setup_request setup_msg, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_config_update& next_config, + up_resource_manager& up_resource_mng_, + const security_indication_t& default_security_indication, + srslog::basic_logger& logger); + +// Same as above but taking the result from E1AP Bearer Context Setup message. +bool handle_bearer_context_setup_response(cu_cp_pdu_session_resource_setup_response& response_msg, + f1ap_ue_context_modification_request& ue_context_mod_request, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + const e1ap_bearer_context_setup_response& bearer_context_setup_response, + up_config_update& next_config, + up_resource_manager& up_resource_mng_, + const security_indication_t& default_security_indication, + srslog::basic_logger& logger); // This method takes the F1AP UE Context Modification Response message and pre-fills the subsequent // bearer context modification message to be send to the CU-UP. // In case of a negative outcome it also prefills the final PDU session resource setup respone message. -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const cu_cp_pdu_session_resource_setup_request& setup_msg, - const f1ap_ue_context_modification_response& ue_context_modification_response, - const up_config_update& next_config, - const srslog::basic_logger& logger); - -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - const cu_cp_pdu_session_resource_setup_request& setup_msg, - bool rrc_reconfig_result, - const srslog::basic_logger& logger); +bool handle_ue_context_modification_response( + cu_cp_pdu_session_resource_setup_response& response_msg, + e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + const f1ap_ue_context_modification_response& ue_context_modification_response, + const up_config_update& next_config, + const srslog::basic_logger& logger); + +bool handle_rrc_reconfiguration_response(cu_cp_pdu_session_resource_setup_response& response_msg, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + bool rrc_reconfig_result, + const srslog::basic_logger& logger); pdu_session_resource_setup_routine::pdu_session_resource_setup_routine( const cu_cp_pdu_session_resource_setup_request& setup_msg_, @@ -96,57 +98,57 @@ void pdu_session_resource_setup_routine::operator()( next_config = up_resource_mng.calculate_update(setup_msg.pdu_session_res_setup_items); } - // sanity check passed, decide whether we have to create a Bearer Context at the CU-UP or modify an existing one. + // Sanity check passed, decide whether we have to create a Bearer Context at the CU-UP or modify an existing one. if (next_config.initial_context_creation) { - // prepare BearerContextSetupRequest + // Prepare BearerContextSetupRequest. if (!fill_e1ap_bearer_context_setup_request(bearer_context_setup_request)) { logger.warning("ue={}: \"{}\" failed to fill bearer context at CU-UP", setup_msg.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } - // call E1AP procedure + // Call E1AP procedure. CORO_AWAIT_VALUE(bearer_context_setup_response, e1ap_bearer_ctxt_mng.handle_bearer_context_setup_request(bearer_context_setup_request)); - // Handle BearerContextSetupResponse - if (!handle_procedure_response(response_msg, - ue_context_mod_request, - setup_msg, - bearer_context_setup_response, - next_config, - up_resource_mng, - default_security_indication, - logger)) { + // Handle BearerContextSetupResponse. + if (!handle_bearer_context_setup_response(response_msg, + ue_context_mod_request, + setup_msg, + bearer_context_setup_response, + next_config, + up_resource_mng, + default_security_indication, + logger)) { logger.warning("ue={}: \"{}\" failed to setup bearer at CU-UP", setup_msg.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } } else { - // prepare BearerContextModificationRequest and modify existing bearer + // Prepare BearerContextModificationRequest and modify existing bearer. bearer_context_modification_request.ng_ran_bearer_context_mod_request.emplace(); // initialize fresh message fill_initial_e1ap_bearer_context_modification_request(bearer_context_modification_request); - // call E1AP procedure and wait for BearerContextModificationResponse + // Call E1AP procedure and wait for BearerContextModificationResponse. CORO_AWAIT_VALUE( bearer_context_modification_response, e1ap_bearer_ctxt_mng.handle_bearer_context_modification_request(bearer_context_modification_request)); - // Handle BearerContextModificationResponse - if (!handle_procedure_response(response_msg, - ue_context_mod_request, - setup_msg, - bearer_context_modification_response, - next_config, - up_resource_mng, - default_security_indication, - logger)) { + // Handle BearerContextModificationResponse. + if (!handle_bearer_context_modification_response(response_msg, + ue_context_mod_request, + setup_msg, + bearer_context_modification_response, + next_config, + up_resource_mng, + default_security_indication, + logger)) { logger.warning("ue={}: \"{}\" failed to modify bearer at CU-UP", setup_msg.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } } - // Register required SRB and DRB resources at DU + // Register required SRB and DRB resources at DU. { - // prepare UE Context Modification Request and call F1 + // Prepare UE Context Modification Request and call F1. ue_context_mod_request.ue_index = setup_msg.ue_index; ue_context_mod_request.cu_to_du_rrc_info.emplace(); ue_context_mod_request.cu_to_du_rrc_info.value().ue_cap_rat_container_list = @@ -156,47 +158,47 @@ void pdu_session_resource_setup_routine::operator()( CORO_AWAIT_VALUE(ue_context_modification_response, f1ap_ue_ctxt_mng.handle_ue_context_modification_request(ue_context_mod_request)); - // Handle UE Context Modification Response - if (!handle_procedure_response(response_msg, - bearer_context_modification_request, - setup_msg, - ue_context_modification_response, - next_config, - logger)) { + // Handle UE Context Modification Response. + if (!handle_ue_context_modification_response(response_msg, + bearer_context_modification_request, + setup_msg, + ue_context_modification_response, + next_config, + logger)) { logger.warning("ue={}: \"{}\" failed to modify UE context at DU", setup_msg.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } } - // Inform CU-UP about the new TEID for UL F1u traffic + // Inform CU-UP about the new TEID for UL F1u traffic. { - // add remaining fields to BearerContextModificationRequest + // Add remaining fields to BearerContextModificationRequest. bearer_context_modification_request.ue_index = setup_msg.ue_index; - // call E1AP procedure and wait for BearerContextModificationResponse + // Call E1AP procedure and wait for BearerContextModificationResponse. CORO_AWAIT_VALUE( bearer_context_modification_response, e1ap_bearer_ctxt_mng.handle_bearer_context_modification_request(bearer_context_modification_request)); - // Handle BearerContextModificationResponse - if (!handle_procedure_response(response_msg, - ue_context_mod_request, - setup_msg, - bearer_context_modification_response, - next_config, - up_resource_mng, - default_security_indication, - logger)) { + // Handle BearerContextModificationResponse. + if (!handle_bearer_context_modification_response(response_msg, + ue_context_mod_request, + setup_msg, + bearer_context_modification_response, + next_config, + up_resource_mng, + default_security_indication, + logger)) { logger.warning("ue={}: \"{}\" failed to modify bearer at CU-UP", setup_msg.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } } { - // prepare RRC Reconfiguration and call RRC UE notifier - // if default DRB is being setup, SRB2 needs to be setup as well + // Prepare RRC Reconfiguration and call RRC UE notifier. + // If default DRB is being setup, SRB2 needs to be setup as well. { - // get NAS PDUs as received by AMF + // Get NAS PDUs as received by AMF. std::vector nas_pdus; if (!setup_msg.nas_pdu.empty()) { nas_pdus.push_back(setup_msg.nas_pdu); @@ -228,32 +230,33 @@ void pdu_session_resource_setup_routine::operator()( CORO_AWAIT_VALUE(rrc_reconfig_result, rrc_ue->handle_rrc_reconfiguration_request(rrc_reconfig_args)); - // Handle RRC Reconfiguration Response - if (!handle_procedure_response(response_msg, setup_msg, rrc_reconfig_result, logger)) { + // Handle RRCReconfiguration result. + if (!handle_rrc_reconfiguration_response(response_msg, setup_msg, rrc_reconfig_result, logger)) { logger.warning("ue={}: \"{}\" RRC reconfiguration failed", setup_msg.ue_index, name()); - // Notify NGAP to request UE context release from AMF + // Notify NGAP to request UE context release from AMF. ue_task_sched.schedule_async_task(cu_cp_notifier.handle_ue_context_release( {setup_msg.ue_index, {}, ngap_cause_radio_network_t::release_due_to_ngran_generated_reason})); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } } - // we are done, all good + // We are done, all good. CORO_RETURN(handle_pdu_session_resource_setup_result(true)); } // Free function to amend to the final procedure response message. This will take the results from the various // sub-procedures and update the succeeded/failed fields. -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_setup_request setup_msg, - const e1ap_bearer_context_modification_response& bearer_context_modification_response, - up_config_update& next_config, - up_resource_manager& up_resource_mng_, - const security_indication_t& default_security_indication, - srslog::basic_logger& logger) +bool handle_bearer_context_modification_response( + cu_cp_pdu_session_resource_setup_response& response_msg, + f1ap_ue_context_modification_request& ue_context_mod_request, + const cu_cp_pdu_session_resource_setup_request setup_msg, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_config_update& next_config, + up_resource_manager& up_resource_mng_, + const security_indication_t& default_security_indication, + srslog::basic_logger& logger) { - // Traverse setup list + // Traverse setup list. if (!update_setup_list(response_msg.pdu_session_res_setup_response_items, ue_context_mod_request.srbs_to_be_setup_mod_list, ue_context_mod_request.drbs_to_be_setup_mod_list, @@ -266,35 +269,35 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& return false; } - // Traverse failed list + // Traverse failed list. update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, bearer_context_modification_response.pdu_session_resource_failed_list, next_config); for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_modified_list) { - // modified list + // Modified list. logger.info("Implement handling of resource modified item with {}", e1ap_item.pdu_session_id); } for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_failed_to_modify_list) { - // failed to modify list + // Failed to modify list. logger.info("Implement handling of resource failed to modify item with {}", e1ap_item.pdu_session_id); } return bearer_context_modification_response.success; } -// Same as above but taking the result from E1AP Bearer Context Setup message -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_setup_request& setup_msg, - const e1ap_bearer_context_setup_response& bearer_context_setup_response, - up_config_update& next_config, - up_resource_manager& up_resource_mng_, - const security_indication_t& default_security_indication, - srslog::basic_logger& logger) +// Same as above but taking the result from E1AP Bearer Context Setup message. +bool handle_bearer_context_setup_response(cu_cp_pdu_session_resource_setup_response& response_msg, + f1ap_ue_context_modification_request& ue_context_mod_request, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + const e1ap_bearer_context_setup_response& bearer_context_setup_response, + up_config_update& next_config, + up_resource_manager& up_resource_mng_, + const security_indication_t& default_security_indication, + srslog::basic_logger& logger) { - // Traverse setup list + // Traverse setup list. if (!update_setup_list(response_msg.pdu_session_res_setup_response_items, ue_context_mod_request.srbs_to_be_setup_mod_list, ue_context_mod_request.drbs_to_be_setup_mod_list, @@ -307,7 +310,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r return false; } - // Traverse failed list + // Traverse failed list. update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, bearer_context_setup_response.pdu_session_resource_failed_list, next_config); @@ -330,14 +333,15 @@ void fill_setup_failed_list(cu_cp_pdu_session_resource_setup_response& resp // This method takes the F1AP UE Context Modification Response message and pre-fills the subsequent // bearer context modification message to be send to the CU-UP. // In case of a negative outcome it also prefills the final PDU session resource setup respone message. -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const cu_cp_pdu_session_resource_setup_request& setup_msg, - const f1ap_ue_context_modification_response& ue_context_modification_response, - const up_config_update& next_config, - const srslog::basic_logger& logger) +bool handle_ue_context_modification_response( + cu_cp_pdu_session_resource_setup_response& response_msg, + e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + const f1ap_ue_context_modification_response& ue_context_modification_response, + const up_config_update& next_config, + const srslog::basic_logger& logger) { - // Fail procedure if (single) DRB couldn't be setup + // Fail procedure if (single) DRB couldn't be setup. if (!ue_context_modification_response.drbs_failed_to_be_setup_list.empty()) { logger.warning("Couldn't setup {} DRBs at DU", ue_context_modification_response.drbs_failed_to_be_setup_list.size()); @@ -359,10 +363,10 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r return ue_context_modification_response.success; } -bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& response_msg, - const cu_cp_pdu_session_resource_setup_request& setup_msg, - bool rrc_reconfig_result, - const srslog::basic_logger& logger) +bool handle_rrc_reconfiguration_response(cu_cp_pdu_session_resource_setup_response& response_msg, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + bool rrc_reconfig_result, + const srslog::basic_logger& logger) { // Let all PDU sessions fail if response is negative. if (!rrc_reconfig_result) { @@ -417,7 +421,7 @@ bool pdu_session_resource_setup_routine::fill_e1ap_bearer_context_setup_request( { e1ap_request.ue_index = setup_msg.ue_index; - // security info + // Security info. e1ap_request.security_info.security_algorithm.ciphering_algo = security_cfg.cipher_algo; e1ap_request.security_info.security_algorithm.integrity_protection_algorithm = security_cfg.integ_algo; auto k_enc_buffer = byte_buffer::create(security_cfg.k_enc); From 6f6f79ed2aa7bf7f10f0231d8a8d337421768965 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 29 Oct 2024 14:47:04 +0100 Subject: [PATCH 19/72] cu_cp: move helper functions to procedures and improve function names --- ..._session_resource_modification_routine.cpp | 196 ++++++++- .../pdu_session_resource_setup_routine.cpp | 235 +++++++++-- .../routines/pdu_session_routine_helpers.cpp | 386 +----------------- .../routines/pdu_session_routine_helpers.h | 90 ++-- 4 files changed, 428 insertions(+), 479 deletions(-) diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index fb52121923..c976b681cd 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -11,6 +11,7 @@ #include "pdu_session_resource_modification_routine.h" #include "pdu_session_routine_helpers.h" #include "srsran/cu_cp/ue_task_scheduler.h" +#include "srsran/ran/cause/e1ap_cause_converters.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -244,6 +245,127 @@ void pdu_session_resource_modification_routine::fill_initial_e1ap_bearer_context } } +/// \brief Processes the result of a Bearer Context Modification Result's PDU session modify list. +/// \param[out] ngap_response_list Reference to the final NGAP response. +/// \param[out] ue_context_mod_request Reference to the next request message - a UE context modification. +/// \param[in] ngap_modify_list Const reference to the original NGAP request. +/// \param[in] bearer_context_modification_response Const reference to the response of the previous subprocedure. +/// \param[in] next_config Const reference to the calculated config update. +/// \param[in] logger Reference to the logger. +/// \return True on success, false otherwise. +static bool update_modify_list_with_bearer_ctxt_mod_response( + slotted_id_vector& ngap_response_list, + f1ap_ue_context_modification_request& ue_context_mod_request, + const slotted_id_vector& ngap_modify_list, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_config_update& next_config, + const srslog::basic_logger& logger) +{ + for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_modified_list) { + const auto& psi = e1ap_item.pdu_session_id; + // Sanity check - make sure this session ID is present in the original modify message. + if (!ngap_modify_list.contains(psi)) { + logger.warning("PduSessionResourceSetupRequest doesn't include setup for {}", psi); + return false; + } + // Also check if PDU session is included in expected next configuration. + if (next_config.pdu_sessions_to_modify_list.find(psi) == next_config.pdu_sessions_to_modify_list.end()) { + logger.warning("Didn't expect modification for {}", psi); + return false; + } + + if (ngap_response_list.contains(psi)) { + // Load existing response item from previous call. + logger.debug("Amend to existing NGAP response item for {}", psi); + } else { + // Add empty new item. + cu_cp_pdu_session_resource_modify_response_item new_item; + new_item.pdu_session_id = psi; + ngap_response_list.emplace(new_item.pdu_session_id, new_item); + logger.debug("Insert new NGAP response item for {}", psi); + } + + // Start/continue filling response item. + cu_cp_pdu_session_resource_modify_response_item& ngap_item = ngap_response_list[psi]; + for (const auto& e1ap_drb_item : e1ap_item.drb_setup_list_ng_ran) { + const auto& drb_id = e1ap_drb_item.drb_id; + if (next_config.pdu_sessions_to_modify_list.at(psi).drb_to_add.find(drb_id) == + next_config.pdu_sessions_to_modify_list.at(psi).drb_to_add.end()) { + logger.warning("{} not part of next configuration", drb_id); + return false; + } + + const auto& request_transfer = ngap_modify_list[psi].transfer; + + // Prepare DRB creation at DU. + f1ap_drb_to_setup drb_setup_mod_item; + if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, + nullptr, + psi, + drb_id, + next_config.pdu_sessions_to_modify_list.at(psi).drb_to_add.at(drb_id), + e1ap_drb_item, + request_transfer.qos_flow_add_or_modify_request_list, + logger)) { + logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); + return false; + } + + // Note: this extra handling for the Modification could be optimized. + for (const auto& e1ap_flow : e1ap_drb_item.flow_setup_list) { + // Fill added flows in NGAP response transfer. + if (!ngap_item.transfer.qos_flow_add_or_modify_response_list.has_value()) { + // Add list if it's not present yet. + ngap_item.transfer.qos_flow_add_or_modify_response_list.emplace(); + } + + qos_flow_add_or_mod_response_item qos_flow; + qos_flow.qos_flow_id = e1ap_flow.qos_flow_id; + ngap_item.transfer.qos_flow_add_or_modify_response_list.value().emplace(qos_flow.qos_flow_id, qos_flow); + } + + // Finally add DRB to setup to UE context modification. + ue_context_mod_request.drbs_to_be_setup_mod_list.push_back(drb_setup_mod_item); + } + + // Add DRB to be removed to UE context modification. + for (const auto& drb_id : next_config.pdu_sessions_to_modify_list.at(psi).drb_to_remove) { + ue_context_mod_request.drbs_to_be_released_list.push_back(drb_id); + } + + // Fail on any DRB that fails to be setup. + if (!e1ap_item.drb_failed_list_ng_ran.empty()) { + logger.warning("Non-empty DRB failed list not supported"); + return false; + } + } + + return true; +} + +/// \brief Processes the response of a Bearer Context Modification Request. +/// \param[out] response_msg Reference to the final NGAP response. +/// \param[out] next_config Const reference to the calculated config update. +/// \param[in] pdu_session_resource_failed_list Const reference to the failed PDU sessions of the Bearer Context +/// Modification Response. +static void update_failed_list_with_bearer_ctxt_mod_response( + cu_cp_pdu_session_resource_modify_response& response_msg, + up_config_update& next_config, + const slotted_id_vector& pdu_session_resource_failed_list) +{ + for (const auto& e1ap_item : pdu_session_resource_failed_list) { + // Remove from next config. + next_config.pdu_sessions_to_setup_list.erase(e1ap_item.pdu_session_id); + response_msg.pdu_session_res_modify_list.erase(e1ap_item.pdu_session_id); + + // Add to list taking cause received from CU-UP. + cu_cp_pdu_session_res_setup_failed_item failed_item; + failed_item.pdu_session_id = e1ap_item.pdu_session_id; + failed_item.unsuccessful_transfer.cause = e1ap_to_ngap_cause(e1ap_item.cause); + response_msg.pdu_session_res_failed_to_modify_list.emplace(failed_item.pdu_session_id, failed_item); + } +} + // \brief Handle first BearerContextModificationResponse and prepare subsequent UEContextModificationRequest. bool handle_bearer_context_modification_response( cu_cp_pdu_session_resource_modify_response& response_msg, @@ -254,23 +376,67 @@ bool handle_bearer_context_modification_response( srslog::basic_logger& logger) { // Traverse modify list. - if (!update_modify_list(response_msg.pdu_session_res_modify_list, - ue_context_mod_request, - modify_request.pdu_session_res_modify_items, - bearer_context_modification_response.pdu_session_resource_modified_list, - next_config, - logger)) { + if (!update_modify_list_with_bearer_ctxt_mod_response(response_msg.pdu_session_res_modify_list, + ue_context_mod_request, + modify_request.pdu_session_res_modify_items, + bearer_context_modification_response, + next_config, + logger)) { return false; } // Traverse failed list. - update_failed_list(response_msg.pdu_session_res_failed_to_modify_list, - bearer_context_modification_response.pdu_session_resource_failed_list, - next_config); + update_failed_list_with_bearer_ctxt_mod_response( + response_msg, next_config, bearer_context_modification_response.pdu_session_resource_failed_list); return bearer_context_modification_response.success; } +/// \brief Processes the response of a UE Context Modification Request. +/// \param[out] ngap_response_list Reference to the final NGAP response. +/// \param[out] ue_context_mod_request Reference to the next request message - a Bearer context modification request. +/// \param[in] ngap_modify_list Const reference to the original NGAP request. +/// \param[in] ue_context_modification_response Const reference to the response of the UE context modification request. +/// \param[in] next_config Const reference to the calculated config update. +/// \param[in] logger Reference to the logger. +/// \return True on success, false otherwise. +static bool update_modify_list_with_ue_ctxt_mod_response( + slotted_id_vector& ngap_response_list, + e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const slotted_id_vector& ngap_modify_list, + const f1ap_ue_context_modification_response& ue_context_modification_response, + const up_config_update& next_config, + const srslog::basic_logger& logger) +{ + // Fail procedure if (single) DRB couldn't be setup. + if (!ue_context_modification_response.drbs_failed_to_be_setup_list.empty()) { + logger.warning("Couldn't setup {} DRBs at DU", + ue_context_modification_response.drbs_failed_to_be_setup_list.size()); + return false; + } + + // Only prepare bearer context modification request if needed. + if (ue_context_modification_response.drbs_setup_list.empty() and + ue_context_modification_response.drbs_modified_list.empty()) { + // No DRB added or updated. + logger.debug("Skipping preparation of bearer context modification request"); + bearer_ctxt_mod_request.ng_ran_bearer_context_mod_request.reset(); + return ue_context_modification_response.success; + } + + // Start with empty message. + e1ap_ng_ran_bearer_context_mod_request& e1ap_bearer_context_mod = + bearer_ctxt_mod_request.ng_ran_bearer_context_mod_request.emplace(); + + fill_e1ap_bearer_context_list(e1ap_bearer_context_mod.pdu_session_res_to_modify_list, + ue_context_modification_response.drbs_setup_list, + next_config.pdu_sessions_to_modify_list); + + // TODO: traverse other fields + + return ue_context_modification_response.success; +} + // Handle UEContextModificationResponse and prepare second BearerContextModificationRequest. bool handle_ue_context_modification_response( cu_cp_pdu_session_resource_modify_response& response_msg, @@ -281,12 +447,12 @@ bool handle_ue_context_modification_response( const srslog::basic_logger& logger) { // Traverse modify list. - if (!update_modify_list(response_msg.pdu_session_res_modify_list, - bearer_ctxt_mod_request, - modify_request.pdu_session_res_modify_items, - ue_context_modification_response, - next_config, - logger)) { + if (!update_modify_list_with_ue_ctxt_mod_response(response_msg.pdu_session_res_modify_list, + bearer_ctxt_mod_request, + modify_request.pdu_session_res_modify_items, + ue_context_modification_response, + next_config, + logger)) { return false; } diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 930b43b259..96d00998b0 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -10,6 +10,7 @@ #include "pdu_session_resource_setup_routine.h" #include "pdu_session_routine_helpers.h" +#include "srsran/ran/cause/e1ap_cause_converters.h" #include "srsran/ran/cause/ngap_cause.h" using namespace srsran; @@ -21,10 +22,10 @@ using namespace asn1::rrc_nr; bool handle_bearer_context_modification_response( cu_cp_pdu_session_resource_setup_response& response_msg, f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_setup_request setup_msg, - const e1ap_bearer_context_modification_response& bearer_context_modification_response, up_config_update& next_config, - up_resource_manager& up_resource_mng_, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_resource_manager& up_resource_mng, const security_indication_t& default_security_indication, srslog::basic_logger& logger); @@ -135,9 +136,9 @@ void pdu_session_resource_setup_routine::operator()( // Handle BearerContextModificationResponse. if (!handle_bearer_context_modification_response(response_msg, ue_context_mod_request, + next_config, setup_msg, bearer_context_modification_response, - next_config, up_resource_mng, default_security_indication, logger)) { @@ -183,9 +184,9 @@ void pdu_session_resource_setup_routine::operator()( // Handle BearerContextModificationResponse. if (!handle_bearer_context_modification_response(response_msg, ue_context_mod_request, + next_config, setup_msg, bearer_context_modification_response, - next_config, up_resource_mng, default_security_indication, logger)) { @@ -244,35 +245,202 @@ void pdu_session_resource_setup_routine::operator()( CORO_RETURN(handle_pdu_session_resource_setup_result(true)); } +/// \brief Processes the response of a Bearer Context Setup/Modification Request. +/// \param[out] ngap_response_list Reference to the final NGAP response. +/// \param[out] srb_setup_mod_list Reference to the successful SRB setup list. +/// \param[out] drb_setup_mod_list Reference to the successful DRB setup list. +/// \param[out] next_config Const reference to the calculated config update. +/// \param[out] ngap_setup_list Const reference to the original NGAP request. +/// \param[in] pdu_session_resource_setup_list Const reference to the PDU sessions of the Bearer Context +/// Setup/Modification Response. +/// \param[in] up_resource_mng Reference to the UP resource manager. +/// \param[in] default_security_indication Const reference to the default security indication. +/// \param[in] logger Reference to the logger. +/// \return True on success, false otherwise. +static bool update_setup_list_with_bearer_ctxt_setup_mod_response( + slotted_id_vector& ngap_response_list, + std::vector& srb_setup_mod_list, + std::vector& drb_setup_mod_list, + up_config_update& next_config, + const slotted_id_vector& ngap_setup_list, + const slotted_id_vector& + pdu_session_resource_setup_list, + up_resource_manager& up_resource_mng, + const security_indication_t& default_security_indication, + const srslog::basic_logger& logger) +{ + // Set up SRB2 if this is the first DRB to be setup. + if (up_resource_mng.get_nof_drbs() == 0) { + f1ap_srb_to_setup srb2; + srb2.srb_id = srb_id_t::srb2; + srb_setup_mod_list.push_back(srb2); + } + + for (const auto& e1ap_item : pdu_session_resource_setup_list) { + const auto& psi = e1ap_item.pdu_session_id; + + // Sanity check - make sure this session ID is present in the original setup message. + if (!ngap_setup_list.contains(psi)) { + logger.warning("PduSessionResourceSetupRequest doesn't include setup for {}", psi); + return false; + } + // Also check if PDU session is included in expected next configuration. + if (next_config.pdu_sessions_to_setup_list.find(psi) == next_config.pdu_sessions_to_setup_list.end()) { + logger.warning("Didn't expect setup for {}", psi); + return false; + } + + cu_cp_pdu_session_res_setup_response_item item; + item.pdu_session_id = psi; + + auto& transfer = item.pdu_session_resource_setup_response_transfer; + transfer.dlqos_flow_per_tnl_info.up_tp_layer_info = e1ap_item.ng_dl_up_tnl_info; + + // Determine security settings for this PDU session and decide whether we have to send the security_result via NGAP. + bool integrity_enabled = false; + bool ciphering_enabled = false; + + if (ngap_setup_list[psi].security_ind.has_value()) { + // TS 38.413 Sec. 8.2.1.2: + // For each PDU session for which the Security Indication IE is included in the PDU Session Resource Setup Request + // Transfer IE of the PDU SESSION RESOURCE SETUP REQUEST message, and the Integrity Protection Indication IE + // or Confidentiality Protection Indication IE is set to "preferred", then the NG-RAN node should, if supported, + // perform user plane integrity protection or ciphering, respectively, for the concerned PDU session and shall + // notify whether it performed the user plane integrity protection or ciphering by including the Integrity + // Protection Result IE or Confidentiality Protection Result IE, respectively, in the PDU Session Resource Setup + // Response Transfer IE of the PDU SESSION RESOURCE SETUP RESPONSE message. + const auto& ngap_sec_ind = ngap_setup_list[psi].security_ind.value(); + if (security_result_required(ngap_sec_ind)) { + // Apply security settings according to the decision in the CU-UP. + if (!e1ap_item.security_result.has_value()) { + logger.warning("Missing security result in E1AP response for {}", psi); + return false; + } + const auto& sec_res = e1ap_item.security_result.value(); + integrity_enabled = sec_res.integrity_protection_result == integrity_protection_result_t::performed; + ciphering_enabled = sec_res.confidentiality_protection_result == confidentiality_protection_result_t::performed; + // Add result to NGAP response + transfer.security_result = sec_res; + } else { + // Apply security settings that were requested via NGAP and do not require an explicit reponse. + integrity_enabled = ngap_sec_ind.integrity_protection_ind == integrity_protection_indication_t::required; + ciphering_enabled = + ngap_sec_ind.confidentiality_protection_ind == confidentiality_protection_indication_t::required; + } + } else { + // Security settings were not signaled via NGAP, we have used the defaults of CU-CP. + const auto sec_ind = default_security_indication; + if (security_result_required(sec_ind)) { + // Apply security settings according to the decision in the CU-UP. + if (!e1ap_item.security_result.has_value()) { + logger.warning("Missing security result in E1AP response for {}", psi); + return false; + } + const auto& sec_res = e1ap_item.security_result.value(); + integrity_enabled = sec_res.integrity_protection_result == integrity_protection_result_t::performed; + ciphering_enabled = sec_res.confidentiality_protection_result == confidentiality_protection_result_t::performed; + // No result in NGAP response needed here. + } else { + // Apply default security settings that do not require an explicit response. + integrity_enabled = sec_ind.integrity_protection_ind == integrity_protection_indication_t::required; + ciphering_enabled = sec_ind.confidentiality_protection_ind == confidentiality_protection_indication_t::required; + } + } + + auto& next_cfg_pdu_session = next_config.pdu_sessions_to_setup_list.at(psi); + + for (const auto& e1ap_drb_item : e1ap_item.drb_setup_list_ng_ran) { + const auto& drb_id = e1ap_drb_item.drb_id; + if (next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.find(drb_id) == + next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.end()) { + logger.warning("DRB id {} not part of next configuration", drb_id); + return false; + } + + // Update security settings of each DRB. + next_cfg_pdu_session.drb_to_add.find(drb_id)->second.pdcp_cfg.integrity_protection_required = integrity_enabled; + next_cfg_pdu_session.drb_to_add.find(drb_id)->second.pdcp_cfg.ciphering_required = ciphering_enabled; + + // Prepare DRB item for DU. + f1ap_drb_to_setup drb_setup_mod_item; + if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, + &transfer.dlqos_flow_per_tnl_info.associated_qos_flow_list, + item.pdu_session_id, + drb_id, + next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.at(drb_id), + e1ap_drb_item, + ngap_setup_list[item.pdu_session_id].qos_flow_setup_request_items, + logger)) { + logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); + return false; + } + drb_setup_mod_list.push_back(drb_setup_mod_item); + } + + // Fail on any DRB that fails to be setup. + if (!e1ap_item.drb_failed_list_ng_ran.empty()) { + logger.warning("Non-empty DRB failed list not supported"); + return false; + } + + ngap_response_list.emplace(item.pdu_session_id, item); + } + + return true; +} + +/// \brief Processes the response of a Bearer Context Setup/Modification Request. +/// \param[out] response_msg Reference to the final NGAP response. +/// \param[out] next_config Const reference to the calculated config update. +/// \param[in] pdu_session_resource_failed_list Const reference to the failed PDU sessions of the Bearer Context +/// Setup/Modification Response. +static void update_failed_list( + + cu_cp_pdu_session_resource_setup_response& response_msg, + up_config_update& next_config, + const slotted_id_vector& pdu_session_resource_failed_list) +{ + for (const auto& e1ap_item : pdu_session_resource_failed_list) { + // Remove from next config. + next_config.pdu_sessions_to_setup_list.erase(e1ap_item.pdu_session_id); + response_msg.pdu_session_res_setup_response_items.erase(e1ap_item.pdu_session_id); + + // Add to list taking cause received from CU-UP. + cu_cp_pdu_session_res_setup_failed_item failed_item; + failed_item.pdu_session_id = e1ap_item.pdu_session_id; + failed_item.unsuccessful_transfer.cause = e1ap_to_ngap_cause(e1ap_item.cause); + response_msg.pdu_session_res_failed_to_setup_items.emplace(failed_item.pdu_session_id, failed_item); + } +} + // Free function to amend to the final procedure response message. This will take the results from the various // sub-procedures and update the succeeded/failed fields. bool handle_bearer_context_modification_response( cu_cp_pdu_session_resource_setup_response& response_msg, f1ap_ue_context_modification_request& ue_context_mod_request, - const cu_cp_pdu_session_resource_setup_request setup_msg, - const e1ap_bearer_context_modification_response& bearer_context_modification_response, up_config_update& next_config, - up_resource_manager& up_resource_mng_, + const cu_cp_pdu_session_resource_setup_request& setup_msg, + const e1ap_bearer_context_modification_response& bearer_context_modification_response, + up_resource_manager& up_resource_mng, const security_indication_t& default_security_indication, srslog::basic_logger& logger) { // Traverse setup list. - if (!update_setup_list(response_msg.pdu_session_res_setup_response_items, - ue_context_mod_request.srbs_to_be_setup_mod_list, - ue_context_mod_request.drbs_to_be_setup_mod_list, - setup_msg.pdu_session_res_setup_items, - bearer_context_modification_response.pdu_session_resource_setup_list, - next_config, - up_resource_mng_, - default_security_indication, - logger)) { + if (!update_setup_list_with_bearer_ctxt_setup_mod_response( + response_msg.pdu_session_res_setup_response_items, + ue_context_mod_request.srbs_to_be_setup_mod_list, + ue_context_mod_request.drbs_to_be_setup_mod_list, + next_config, + setup_msg.pdu_session_res_setup_items, + bearer_context_modification_response.pdu_session_resource_setup_list, + up_resource_mng, + default_security_indication, + logger)) { return false; } // Traverse failed list. - update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, - bearer_context_modification_response.pdu_session_resource_failed_list, - next_config); + update_failed_list(response_msg, next_config, bearer_context_modification_response.pdu_session_resource_failed_list); for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_modified_list) { // Modified list. @@ -298,22 +466,21 @@ bool handle_bearer_context_setup_response(cu_cp_pdu_session_resource_setup_respo srslog::basic_logger& logger) { // Traverse setup list. - if (!update_setup_list(response_msg.pdu_session_res_setup_response_items, - ue_context_mod_request.srbs_to_be_setup_mod_list, - ue_context_mod_request.drbs_to_be_setup_mod_list, - setup_msg.pdu_session_res_setup_items, - bearer_context_setup_response.pdu_session_resource_setup_list, - next_config, - up_resource_mng_, - default_security_indication, - logger)) { + if (!update_setup_list_with_bearer_ctxt_setup_mod_response( + response_msg.pdu_session_res_setup_response_items, + ue_context_mod_request.srbs_to_be_setup_mod_list, + ue_context_mod_request.drbs_to_be_setup_mod_list, + next_config, + setup_msg.pdu_session_res_setup_items, + bearer_context_setup_response.pdu_session_resource_setup_list, + up_resource_mng_, + default_security_indication, + logger)) { return false; } // Traverse failed list. - update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, - bearer_context_setup_response.pdu_session_resource_failed_list, - next_config); + update_failed_list(response_msg, next_config, bearer_context_setup_response.pdu_session_resource_failed_list); return bearer_context_setup_response.success; } @@ -348,7 +515,7 @@ bool handle_ue_context_modification_response( return false; } - if (!update_setup_list( + if (!update_setup_list_with_ue_ctxt_setup_response( bearer_ctxt_mod_request, ue_context_modification_response.drbs_setup_list, next_config, logger)) { return false; } @@ -389,7 +556,7 @@ void mark_all_sessions_as_failed(cu_cp_pdu_session_resource_setup_response& fail_item.cause = cause; failed_list.emplace(setup_item.pdu_session_id, fail_item); } - update_failed_list(response_msg.pdu_session_res_failed_to_setup_items, failed_list, next_config); + update_failed_list(response_msg, next_config, failed_list); // No PDU session setup can be successful at the same time. response_msg.pdu_session_res_setup_response_items.clear(); } diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index 5e3676d1bc..677fcda8aa 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -10,7 +10,6 @@ #include "pdu_session_routine_helpers.h" #include "srsran/asn1/rrc_nr/cell_group_config.h" -#include "srsran/ran/cause/e1ap_cause_converters.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -38,12 +37,12 @@ void srsran::srs_cu_cp::fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_it request_item.qos_flow_level_qos_params.alloc_retention_prio; } -bool srsran::srs_cu_cp::verify_and_log_cell_group_config(const byte_buffer& packed_config, +bool srsran::srs_cu_cp::verify_and_log_cell_group_config(const byte_buffer& packed_cell_group_cfg, const srslog::basic_logger& logger) { // Unpack DU to CU container. asn1::rrc_nr::cell_group_cfg_s cell_group_cfg; - asn1::cbit_ref bref_cell({packed_config.begin(), packed_config.end()}); + asn1::cbit_ref bref_cell({packed_cell_group_cfg.begin(), packed_cell_group_cfg.end()}); if (cell_group_cfg.unpack(bref_cell) != asn1::SRSASN_SUCCESS) { logger.warning("Failed to unpack cellGroupConfig"); return false; @@ -180,15 +179,16 @@ bool srsran::srs_cu_cp::fill_rrc_reconfig_args( return true; } -bool fill_f1ap_drb_setup_mod_item(f1ap_drb_to_setup& drb_setup_mod_item, // Request to setup DRB at DU. - slotted_id_vector* response_flow_list, - pdu_session_id_t psi, - drb_id_t drb_id, - up_drb_context& next_drb_config, // DRB config (info is written back). - const e1ap_drb_setup_item_ng_ran& e1ap_drb_item, // Response from CU-UP. - const slotted_id_vector& - ngap_qos_flow_setup_items, // Initial request from AMF. - const srslog::basic_logger& logger) +bool srsran::srs_cu_cp::fill_f1ap_drb_setup_mod_item( + f1ap_drb_to_setup& drb_setup_mod_item, // Request to setup DRB at DU. + slotted_id_vector* response_flow_list, + pdu_session_id_t psi, + drb_id_t drb_id, + up_drb_context& next_drb_config, // DRB config (info is written back). + const e1ap_drb_setup_item_ng_ran& e1ap_drb_item, // Response from CU-UP. + const slotted_id_vector& + ngap_qos_flow_setup_items, // Initial request from AMF. + const srslog::basic_logger& logger) { // Catch implementation limitations. if (!e1ap_drb_item.flow_failed_list.empty()) { @@ -225,7 +225,7 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drb_to_setup& drb_setup_mod_item, // Requ // QoS flows. for (const auto& e1ap_flow : e1ap_drb_item.flow_setup_list) { // Verify the QoS flow ID is present in original setup message. - if (ngap_qos_flow_setup_items.contains(e1ap_flow.qos_flow_id) == false) { + if (!ngap_qos_flow_setup_items.contains(e1ap_flow.qos_flow_id)) { logger.warning("PduSessionResourceSetupRequest doesn't include setup for {} in {}", e1ap_flow.qos_flow_id, psi); return false; } @@ -260,205 +260,6 @@ bool fill_f1ap_drb_setup_mod_item(f1ap_drb_to_setup& drb_setup_mod_item, // Requ return true; } -bool srsran::srs_cu_cp::update_setup_list( - slotted_id_vector& ngap_response_list, - std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, - const slotted_id_vector& ngap_setup_list, - const slotted_id_vector& - pdu_session_resource_setup_list, - up_config_update& next_config, - up_resource_manager& up_resource_mng, - const security_indication_t& default_security_indication, - const srslog::basic_logger& logger) -{ - // Set up SRB2 if this is the first DRB to be setup. - if (up_resource_mng.get_nof_drbs() == 0) { - f1ap_srb_to_setup srb2; - srb2.srb_id = srb_id_t::srb2; - srb_setup_mod_list.push_back(srb2); - } - - for (const auto& e1ap_item : pdu_session_resource_setup_list) { - const auto& psi = e1ap_item.pdu_session_id; - - // Sanity check - make sure this session ID is present in the original setup message. - if (ngap_setup_list.contains(psi) == false) { - logger.warning("PduSessionResourceSetupRequest doesn't include setup for {}", psi); - return false; - } - // Also check if PDU session is included in expected next configuration. - if (next_config.pdu_sessions_to_setup_list.find(psi) == next_config.pdu_sessions_to_setup_list.end()) { - logger.warning("Didn't expect setup for {}", psi); - return false; - } - - cu_cp_pdu_session_res_setup_response_item item; - item.pdu_session_id = psi; - - auto& transfer = item.pdu_session_resource_setup_response_transfer; - transfer.dlqos_flow_per_tnl_info.up_tp_layer_info = e1ap_item.ng_dl_up_tnl_info; - - // Determine security settings for this PDU session and decide whether we have to send the security_result via NGAP. - bool integrity_enabled = false; - bool ciphering_enabled = false; - - if (ngap_setup_list[psi].security_ind.has_value()) { - // TS 38.413 Sec. 8.2.1.2: - // For each PDU session for which the Security Indication IE is included in the PDU Session Resource Setup Request - // Transfer IE of the PDU SESSION RESOURCE SETUP REQUEST message, and the Integrity Protection Indication IE - // or Confidentiality Protection Indication IE is set to "preferred", then the NG-RAN node should, if supported, - // perform user plane integrity protection or ciphering, respectively, for the concerned PDU session and shall - // notify whether it performed the user plane integrity protection or ciphering by including the Integrity - // Protection Result IE or Confidentiality Protection Result IE, respectively, in the PDU Session Resource Setup - // Response Transfer IE of the PDU SESSION RESOURCE SETUP RESPONSE message. - const auto& ngap_sec_ind = ngap_setup_list[psi].security_ind.value(); - if (security_result_required(ngap_sec_ind)) { - // Apply security settings according to the decision in the CU-UP. - if (!e1ap_item.security_result.has_value()) { - logger.warning("Missing security result in E1AP response for {}", psi); - return false; - } - auto& sec_res = e1ap_item.security_result.value(); - integrity_enabled = sec_res.integrity_protection_result == integrity_protection_result_t::performed; - ciphering_enabled = sec_res.confidentiality_protection_result == confidentiality_protection_result_t::performed; - // Add result to NGAP response - transfer.security_result = sec_res; - } else { - // Apply security settings that were requested via NGAP and do not require an explicit reponse. - integrity_enabled = ngap_sec_ind.integrity_protection_ind == integrity_protection_indication_t::required; - ciphering_enabled = - ngap_sec_ind.confidentiality_protection_ind == confidentiality_protection_indication_t::required; - } - } else { - // Security settings were not signaled via NGAP, we have used the defaults of CU-CP. - const auto sec_ind = default_security_indication; - if (security_result_required(sec_ind)) { - // Apply security settings according to the decision in the CU-UP. - if (!e1ap_item.security_result.has_value()) { - logger.warning("Missing security result in E1AP response for {}", psi); - return false; - } - const auto& sec_res = e1ap_item.security_result.value(); - integrity_enabled = sec_res.integrity_protection_result == integrity_protection_result_t::performed; - ciphering_enabled = sec_res.confidentiality_protection_result == confidentiality_protection_result_t::performed; - // No result in NGAP response needed here. - } else { - // Apply default security settings that do not require an explicit response. - integrity_enabled = sec_ind.integrity_protection_ind == integrity_protection_indication_t::required; - ciphering_enabled = sec_ind.confidentiality_protection_ind == confidentiality_protection_indication_t::required; - } - } - - auto& next_cfg_pdu_session = next_config.pdu_sessions_to_setup_list.at(psi); - - for (const auto& e1ap_drb_item : e1ap_item.drb_setup_list_ng_ran) { - const auto& drb_id = e1ap_drb_item.drb_id; - if (next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.find(drb_id) == - next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.end()) { - logger.warning("DRB id {} not part of next configuration", drb_id); - return false; - } - - // Update security settings of each DRB. - next_cfg_pdu_session.drb_to_add.find(drb_id)->second.pdcp_cfg.integrity_protection_required = integrity_enabled; - next_cfg_pdu_session.drb_to_add.find(drb_id)->second.pdcp_cfg.ciphering_required = ciphering_enabled; - - // Prepare DRB item for DU. - f1ap_drb_to_setup drb_setup_mod_item; - if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, - &transfer.dlqos_flow_per_tnl_info.associated_qos_flow_list, - item.pdu_session_id, - drb_id, - next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.at(drb_id), - e1ap_drb_item, - ngap_setup_list[item.pdu_session_id].qos_flow_setup_request_items, - logger)) { - logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); - return false; - } - drb_setup_mod_list.push_back(drb_setup_mod_item); - } - - // Fail on any DRB that fails to be setup. - if (!e1ap_item.drb_failed_list_ng_ran.empty()) { - logger.warning("Non-empty DRB failed list not supported"); - return false; - } - - ngap_response_list.emplace(item.pdu_session_id, item); - } - - return true; -} - -bool srsran::srs_cu_cp::update_setup_list( - std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, - const slotted_id_vector& ngap_setup_list, - const slotted_id_vector& - pdu_session_resource_setup_list, - up_config_update& next_config, - up_resource_manager& up_resource_mng, - const srslog::basic_logger& logger) -{ - // Set up SRB1 and SRB2 (this is for inter CU handover, so no SRBs are setup yet). - // TODO: Do we need to setup SRB0 here as well? - for (unsigned srb_id = 1; srb_id < 3; ++srb_id) { - f1ap_srb_to_setup srb_item; - srb_item.srb_id = int_to_srb_id(srb_id); - srb_setup_mod_list.push_back(srb_item); - } - - for (const auto& e1ap_item : pdu_session_resource_setup_list) { - const auto& psi = e1ap_item.pdu_session_id; - - // Sanity check - make sure this session ID is present in the original setup message. - if (ngap_setup_list.contains(e1ap_item.pdu_session_id) == false) { - logger.warning("PduSessionResourceSetupRequest doesn't include setup for {}", e1ap_item.pdu_session_id); - return false; - } - // Also check if PDU session is included in expected next configuration. - if (next_config.pdu_sessions_to_setup_list.find(e1ap_item.pdu_session_id) == - next_config.pdu_sessions_to_setup_list.end()) { - logger.warning("Didn't expect setup for {}", e1ap_item.pdu_session_id); - return false; - } - - for (const auto& e1ap_drb_item : e1ap_item.drb_setup_list_ng_ran) { - const auto& drb_id = e1ap_drb_item.drb_id; - if (next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.find(drb_id) == - next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.end()) { - logger.warning("{} not part of next configuration", drb_id); - return false; - } - - // Prepare DRB item for DU. - f1ap_drb_to_setup drb_setup_mod_item; - if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, - {}, - e1ap_item.pdu_session_id, - drb_id, - next_config.pdu_sessions_to_setup_list.at(psi).drb_to_add.at(drb_id), - e1ap_drb_item, - ngap_setup_list[e1ap_item.pdu_session_id].qos_flow_setup_request_items, - logger)) { - logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); - return false; - } - drb_setup_mod_list.push_back(drb_setup_mod_item); - } - - // Fail on any DRB that fails to be setup. - if (!e1ap_item.drb_failed_list_ng_ran.empty()) { - logger.warning("Non-empty DRB failed list not supported"); - return false; - } - } - - return true; -} - void srsran::srs_cu_cp::fill_drb_to_setup_list( slotted_id_vector& e1ap_drb_to_setup_list, const slotted_id_vector& qos_flow_list, @@ -526,114 +327,6 @@ void srsran::srs_cu_cp::fill_drb_to_remove_list(std::vector& e1a } } -void srsran::srs_cu_cp::update_failed_list( - slotted_id_vector& ngap_failed_list, - const slotted_id_vector& pdu_session_resource_failed_list, - up_config_update& next_config) -{ - for (const auto& e1ap_item : pdu_session_resource_failed_list) { - // Remove from next config. - next_config.pdu_sessions_to_setup_list.erase(e1ap_item.pdu_session_id); - - // Add to list taking cause received from CU-UP. - cu_cp_pdu_session_res_setup_failed_item failed_item; - failed_item.pdu_session_id = e1ap_item.pdu_session_id; - failed_item.unsuccessful_transfer.cause = e1ap_to_ngap_cause(e1ap_item.cause); - ngap_failed_list.emplace(failed_item.pdu_session_id, failed_item); - } -} - -bool srsran::srs_cu_cp::update_modify_list( - slotted_id_vector& ngap_response_list, - f1ap_ue_context_modification_request& ue_context_mod_request, - const slotted_id_vector& ngap_modify_list, - const slotted_id_vector& - e1ap_pdu_session_resource_modify_list, - up_config_update& next_config, - const srslog::basic_logger& logger) -{ - for (const auto& e1ap_item : e1ap_pdu_session_resource_modify_list) { - const auto& psi = e1ap_item.pdu_session_id; - // Sanity check - make sure this session ID is present in the original modify message. - if (ngap_modify_list.contains(psi) == false) { - logger.warning("PduSessionResourceSetupRequest doesn't include setup for {}", psi); - return false; - } - // Also check if PDU session is included in expected next configuration. - if (next_config.pdu_sessions_to_modify_list.find(psi) == next_config.pdu_sessions_to_modify_list.end()) { - logger.warning("Didn't expect modification for {}", psi); - return false; - } - - if (ngap_response_list.contains(psi)) { - // Load existing response item from previous call. - logger.debug("Amend to existing NGAP response item for {}", psi); - } else { - // Add empty new item. - cu_cp_pdu_session_resource_modify_response_item new_item; - new_item.pdu_session_id = psi; - ngap_response_list.emplace(new_item.pdu_session_id, new_item); - logger.debug("Insert new NGAP response item for {}", psi); - } - - // Start/continue filling response item. - cu_cp_pdu_session_resource_modify_response_item& ngap_item = ngap_response_list[psi]; - for (const auto& e1ap_drb_item : e1ap_item.drb_setup_list_ng_ran) { - const auto& drb_id = e1ap_drb_item.drb_id; - if (next_config.pdu_sessions_to_modify_list.at(psi).drb_to_add.find(drb_id) == - next_config.pdu_sessions_to_modify_list.at(psi).drb_to_add.end()) { - logger.warning("{} not part of next configuration", drb_id); - return false; - } - - const auto& request_transfer = ngap_modify_list[psi].transfer; - - // Prepare DRB creation at DU. - f1ap_drb_to_setup drb_setup_mod_item; - if (!fill_f1ap_drb_setup_mod_item(drb_setup_mod_item, - nullptr, - psi, - drb_id, - next_config.pdu_sessions_to_modify_list.at(psi).drb_to_add.at(drb_id), - e1ap_drb_item, - request_transfer.qos_flow_add_or_modify_request_list, - logger)) { - logger.warning("Couldn't populate DRB setup/mod item {}", e1ap_drb_item.drb_id); - return false; - } - - // Note: this extra handling for the Modification could be optimized. - for (const auto& e1ap_flow : e1ap_drb_item.flow_setup_list) { - // Fill added flows in NGAP response transfer. - if (!ngap_item.transfer.qos_flow_add_or_modify_response_list.has_value()) { - // Add list if it's not present yet. - ngap_item.transfer.qos_flow_add_or_modify_response_list.emplace(); - } - - qos_flow_add_or_mod_response_item qos_flow; - qos_flow.qos_flow_id = e1ap_flow.qos_flow_id; - ngap_item.transfer.qos_flow_add_or_modify_response_list.value().emplace(qos_flow.qos_flow_id, qos_flow); - } - - // Finally add DRB to setup to UE context modification. - ue_context_mod_request.drbs_to_be_setup_mod_list.push_back(drb_setup_mod_item); - } - - // Add DRB to be removed to UE context modifcation. - for (const auto& drb_id : next_config.pdu_sessions_to_modify_list.at(psi).drb_to_remove) { - ue_context_mod_request.drbs_to_be_released_list.push_back(drb_id); - } - - // Fail on any DRB that fails to be setup. - if (!e1ap_item.drb_failed_list_ng_ran.empty()) { - logger.warning("Non-empty DRB failed list not supported"); - return false; - } - } - - return true; -} - void srsran::srs_cu_cp::fill_e1ap_bearer_context_list( slotted_id_vector& e1ap_list, const std::vector& drb_setup_items, @@ -704,54 +397,11 @@ void srsran::srs_cu_cp::fill_e1ap_pdu_session_res_to_setup_list( } } -bool srsran::srs_cu_cp::update_modify_list( - slotted_id_vector& ngap_response_list, - e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const slotted_id_vector& ngap_modify_list, - const f1ap_ue_context_modification_response& ue_context_modification_response, - const up_config_update& next_config, - const srslog::basic_logger& logger) -{ - // Fail procedure if (single) DRB couldn't be setup. - if (!ue_context_modification_response.drbs_failed_to_be_setup_list.empty()) { - logger.warning("Couldn't setup {} DRBs at DU", - ue_context_modification_response.drbs_failed_to_be_setup_list.size()); - return false; - } - - // Only prepare bearer context modifcation request if needed. - if (ue_context_modification_response.drbs_setup_list.empty() and - ue_context_modification_response.drbs_modified_list.empty()) { - // No DRB added or updated. - logger.debug("Skipping preparation of bearer context modification request"); - bearer_ctxt_mod_request.ng_ran_bearer_context_mod_request.reset(); - return ue_context_modification_response.success; - } - - // Start with empty message. - e1ap_ng_ran_bearer_context_mod_request& e1ap_bearer_context_mod = - bearer_ctxt_mod_request.ng_ran_bearer_context_mod_request.emplace(); - - fill_e1ap_bearer_context_list(e1ap_bearer_context_mod.pdu_session_res_to_modify_list, - ue_context_modification_response.drbs_setup_list, - next_config.pdu_sessions_to_modify_list); - -#if 0 - // Let all PDU sessions fail if response is negative. - if (ue_context_modification_response.success == false) { - fill_response_failed_list(ngap_response_list, ngap_modify_list); - } -#endif - - // TODO: traverse other fields - - return ue_context_modification_response.success; -} - -bool srsran::srs_cu_cp::update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const std::vector& drb_setup_mod_list, - const up_config_update& next_config, - const srslog::basic_logger& logger) +bool srsran::srs_cu_cp::update_setup_list_with_ue_ctxt_setup_response( + e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const std::vector& drb_setup_mod_list, + const up_config_update& next_config, + const srslog::basic_logger& logger) { // Start with empty message. e1ap_ng_ran_bearer_context_mod_request& e1ap_bearer_context_mod = diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index e297997f80..6a9063f4d6 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -22,7 +22,26 @@ namespace srsran { namespace srs_cu_cp { -bool verify_and_log_cell_group_config(const byte_buffer& cell_group_cfg, const srslog::basic_logger& logger); +bool verify_and_log_cell_group_config(const byte_buffer& packed_cell_group_cfg, const srslog::basic_logger& logger); + +/// \brief Fill thew DRB setup mod item for the DU. +/// \param[out] drb_setup_mod_item The DRB setup item to fill. +/// \param[in] response_flow_list The list of QoS flows to be added to the NGAP response. +/// \param[in] psi The PDU session ID. +/// \param[in] drb_id The DRB ID. +/// \param[in] next_drb_config The DRB config to be updated. +/// \param[in] e1ap_drb_item The DRB setup response from CU-UP. +/// \param[in] ngap_qos_flow_setup_items The initial QoS flow setup request from AMF. +/// \param[in] logger The logger. +bool fill_f1ap_drb_setup_mod_item(f1ap_drb_to_setup& drb_setup_mod_item, // Request to setup DRB at DU. + slotted_id_vector* response_flow_list, + pdu_session_id_t psi, + drb_id_t drb_id, + up_drb_context& next_drb_config, // DRB config (info is written back). + const e1ap_drb_setup_item_ng_ran& e1ap_drb_item, // Response from CU-UP. + const slotted_id_vector& + ngap_qos_flow_setup_items, // Initial request from AMF. + const srslog::basic_logger& logger); void fill_e1ap_drb_pdcp_config(e1ap_pdcp_config& e1ap_pdcp_cfg, const pdcp_config& cu_cp_pdcp_cfg); void fill_e1ap_qos_flow_param_item(e1ap_qos_flow_qos_param_item& e1ap_qos_item, @@ -76,69 +95,16 @@ bool fill_rrc_reconfig_args(rrc_reconfiguration_procedure_request& byte_buffer sib1, const srslog::basic_logger& logger); -bool update_setup_list( - slotted_id_vector& ngap_response_list, - std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, - const slotted_id_vector& ngap_setup_list, - const slotted_id_vector& - pdu_session_resource_setup_list, - up_config_update& next_config, - up_resource_manager& up_resource_mng, - const security_indication_t& default_security_indication, - const srslog::basic_logger& logger); - -bool update_setup_list(std::vector& srb_setup_mod_list, - std::vector& drb_setup_mod_list, - const slotted_id_vector& ngap_setup_list, - const slotted_id_vector& - pdu_session_resource_setup_list, - up_config_update& next_config, - up_resource_manager& up_resource_mng, - const srslog::basic_logger& logger); - -bool update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, - const std::vector& drb_setup_mod_list, - const up_config_update& next_config, - const srslog::basic_logger& logger); - -void update_failed_list( - slotted_id_vector& ngap_failed_list, - const slotted_id_vector& pdu_session_resource_failed_list, - up_config_update& next_config); - -/// \brief Processes the result of a Bearer Context Modifcation Result's PDU session modify list. -/// \param[out] ngap_response_list Reference to the final NGAP response -/// \param[out] ue_context_mod_request Reference to the next request message - a UE context modification. -/// \param[in] ngap_modify_list Const reference to the original NGAP request -/// \param[in] e1ap_pdu_session_resource_modify_list Const reference to the response of the previous subprocedure -/// \param[in]next_config Const reference to the calculated config update -/// \param[in] logger Reference to the logger. -/// \return True on success, false otherwise. -bool update_modify_list( - slotted_id_vector& ngap_response_list, - f1ap_ue_context_modification_request& ue_context_mod_request, - const slotted_id_vector& ngap_modify_list, - const slotted_id_vector& - e1ap_pdu_session_resource_modify_list, - up_config_update& next_config, - const srslog::basic_logger& logger); - -/// \brief Processes the response of a UE Context Modifcation Request. -/// \param[out] ngap_response_list Reference to the final NGAP response. -/// \param[out] ue_context_mod_request Reference to the next request message - a Bearer context modification request. -/// \param[in] ngap_modify_list Const reference to the original NGAP request -/// \param[in] ue_context_modification_response Const reference to the response of the UE context modifcation request. -/// \param[in] next_config Const reference to the calculated config update +/// \brief Processes the response of a UE Context Setup Request. +/// \param[out] bearer_ctxt_mod_request Reference to the resulting Bearer Context Modification Request response. +/// \param[out] drb_setup_mod_list Reference to the successful DRB setup list. +/// \param[out] next_config Const reference to the calculated config update. /// \param[in] logger Reference to the logger. /// \return True on success, false otherwise. -bool update_modify_list( - slotted_id_vector& ngap_response_list, - e1ap_bearer_context_modification_request& bearer_context_mod_request, - const slotted_id_vector& ngap_modify_list, - const f1ap_ue_context_modification_response& ue_context_modification_response, - const up_config_update& next_config, - const srslog::basic_logger& logger); +bool update_setup_list_with_ue_ctxt_setup_response(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, + const std::vector& drb_setup_mod_list, + const up_config_update& next_config, + const srslog::basic_logger& logger); } // namespace srs_cu_cp } // namespace srsran From d7281c49654077ee377f4f03ca0674eebb33a544 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 29 Oct 2024 14:48:00 +0100 Subject: [PATCH 20/72] cu_cp: fix typos --- lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h | 2 +- tests/unittests/cu_cp/test_helpers.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h index 3dd04fe4cd..25a477b84d 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h @@ -17,7 +17,7 @@ namespace srsran { namespace srs_cu_cp { -/// \brief Perform sanity check on incoming resource setup/modifcation/release requests. +/// \brief Perform sanity check on incoming resource setup/modification/release requests. bool is_valid(const slotted_id_vector& setup_items, const up_context& context, const up_resource_manager_cfg& cfg, diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index 0da7180c83..a2e5122589 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -458,7 +458,7 @@ struct dummy_f1ap_ue_context_manager : public f1ap_ue_context_manager { logger.info("Received a new UE context modification request"); // store request so it can be verified in the test code - make_partial_copy(ue_context_modifcation_request, request); + make_partial_copy(ue_context_modification_request, request); return launch_async([res = f1ap_ue_context_modification_response{}, this](coro_context>& ctx) mutable { @@ -495,7 +495,7 @@ struct dummy_f1ap_ue_context_manager : public f1ap_ue_context_manager { bool handle_ue_id_update(ue_index_t ue_index, ue_index_t old_ue_index) override { return true; } - const f1ap_ue_context_modification_request& get_ctxt_mod_request() { return ue_context_modifcation_request; } + const f1ap_ue_context_modification_request& get_ctxt_mod_request() { return ue_context_modification_request; } f1ap_ue_context_release_command last_release_command; @@ -512,7 +512,7 @@ struct dummy_f1ap_ue_context_manager : public f1ap_ue_context_manager { bool ue_context_setup_outcome = false; ue_context_outcome_t ue_context_modification_outcome; - f1ap_ue_context_modification_request ue_context_modifcation_request; + f1ap_ue_context_modification_request ue_context_modification_request; }; struct dummy_cu_up_processor_cu_up_management_notifier : public cu_up_processor_cu_up_management_notifier { From 545dc790c9044244aa92f8325dc5723afde51bf4 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 29 Oct 2024 14:52:47 +0100 Subject: [PATCH 21/72] cu_cp: add handling of resource modified and resource failed to modify items in pdu session setup --- .../pdu_session_resource_setup_routine.cpp | 99 +++++++++++++++++-- .../cu_cp_initial_context_setup_test.cpp | 3 +- .../cu_cp_pdu_session_resource_setup_test.cpp | 6 +- .../cu_cp/cu_cp_test_environment.cpp | 2 +- 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 96d00998b0..49950c8242 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -413,6 +413,88 @@ static void update_failed_list( } } +/// \brief Processes the response of a UE Context Modification Request. +/// \param[in] drb_setup_mod_list Reference to the DRBs originally requested to be setup. +/// \param[in] ngap_setup_list Const reference to the original NGAP request. +/// \param[in] bearer_contxt_mod_response Const reference to the response of the Bearer Context Modification Response. +/// \param[in] next_config Const reference to the calculated config update. +/// \param[in] logger Reference to the logger. +/// \return True on success, false otherwise. +static bool validate_next_config_with_bearer_ctxt_mod_response( + const std::vector& drb_setup_mod_list, + const slotted_id_vector& ngap_setup_list, + const e1ap_bearer_context_modification_response& bearer_contxt_mod_response, + const up_config_update& next_config, + const srslog::basic_logger& logger) +{ + for (const auto& e1ap_item : bearer_contxt_mod_response.pdu_session_resource_modified_list) { + const auto& psi = e1ap_item.pdu_session_id; + + // Sanity check - make sure this session ID is present in the original setup message. + if (!ngap_setup_list.contains(psi)) { + logger.warning("PduSessionResourceSetupRequest doesn't include setup for {}", psi); + return false; + } + // Also check if PDU session is included in expected next configuration. + if (next_config.pdu_sessions_to_setup_list.find(psi) == next_config.pdu_sessions_to_setup_list.end()) { + logger.warning("Didn't expect setup for {}", psi); + return false; + } + + const auto& next_cfg_pdu_session = next_config.pdu_sessions_to_setup_list.at(psi); + + for (const auto& e1ap_drb_item : e1ap_item.drb_setup_list_ng_ran) { + const auto& drb_id = e1ap_drb_item.drb_id; + if (next_cfg_pdu_session.drb_to_add.find(drb_id) == next_cfg_pdu_session.drb_to_add.end()) { + logger.warning("DRB id {} not part of next configuration", drb_id); + return false; + } + + // Check that all modified DRBs are already part of the next configuration. + for (const auto& drb_mod_item : e1ap_item.drb_modified_list_ng_ran) { + auto it = + std::find_if(drb_setup_mod_list.begin(), + drb_setup_mod_list.end(), + [&](const f1ap_drb_to_setup& setup_item) { return setup_item.drb_id == drb_mod_item.drb_id; }); + if (it == drb_setup_mod_list.end()) { + return false; + } + } + } + + // Fail on any DRB that failed modification. + if (!e1ap_item.drb_failed_to_modify_list_ng_ran.empty()) { + logger.warning("Non-empty DRB failed to modify list not supported"); + return false; + } + } + + return true; +} + +/// \brief Processes the response of a Bearer Context Modification Request. +/// \param[out] response_msg Reference to the final NGAP response. +/// \param[out] next_config Const reference to the calculated config update. +/// \param[in] bearer_context_modification_response Const reference to the response of the Bearer Context Modification +/// Request. +static void update_failed_to_modify_list_with_bearer_ctxt_mod_resp( + cu_cp_pdu_session_resource_setup_response& response_msg, + up_config_update& next_config, + const e1ap_bearer_context_modification_response& bearer_context_modification_response) +{ + for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_failed_to_modify_list) { + // Remove from next config. + next_config.pdu_sessions_to_setup_list.erase(e1ap_item.pdu_session_id); + response_msg.pdu_session_res_setup_response_items.erase(e1ap_item.pdu_session_id); + + // Add to list taking cause received from CU-UP. + cu_cp_pdu_session_res_setup_failed_item failed_item; + failed_item.pdu_session_id = e1ap_item.pdu_session_id; + failed_item.unsuccessful_transfer.cause = e1ap_to_ngap_cause(e1ap_item.cause); + response_msg.pdu_session_res_failed_to_setup_items.emplace(failed_item.pdu_session_id, failed_item); + } +} + // Free function to amend to the final procedure response message. This will take the results from the various // sub-procedures and update the succeeded/failed fields. bool handle_bearer_context_modification_response( @@ -442,15 +524,18 @@ bool handle_bearer_context_modification_response( // Traverse failed list. update_failed_list(response_msg, next_config, bearer_context_modification_response.pdu_session_resource_failed_list); - for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_modified_list) { - // Modified list. - logger.info("Implement handling of resource modified item with {}", e1ap_item.pdu_session_id); + // Traverse modified list. + if (!validate_next_config_with_bearer_ctxt_mod_response(ue_context_mod_request.drbs_to_be_setup_mod_list, + setup_msg.pdu_session_res_setup_items, + bearer_context_modification_response, + next_config, + logger)) { + return false; } - for (const auto& e1ap_item : bearer_context_modification_response.pdu_session_resource_failed_to_modify_list) { - // Failed to modify list. - logger.info("Implement handling of resource failed to modify item with {}", e1ap_item.pdu_session_id); - } + // Traverse failed to modify list. + update_failed_to_modify_list_with_bearer_ctxt_mod_resp( + response_msg, next_config, bearer_context_modification_response); return bearer_context_modification_response.success; } diff --git a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp index e2defc4a62..e7eb7f0ca5 100644 --- a/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_initial_context_setup_test.cpp @@ -200,7 +200,8 @@ class cu_cp_initial_context_setup_test : public cu_cp_test_environment, public : "Failed to receive E1AP Bearer Context Modification"); // Inject E1AP Bearer Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) - get_cu_up(0).push_tx_pdu(generate_bearer_context_modification_response(cu_cp_e1ap_id, cu_up_e1ap_id)); + get_cu_up(0).push_tx_pdu(generate_bearer_context_modification_response( + cu_cp_e1ap_id, cu_up_e1ap_id, {}, {{uint_to_pdu_session_id(1), drb_id_t::drb1}})); report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp index afca227d03..52cd0f6569 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp @@ -370,7 +370,7 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, when_setup_for_pdu_sessions_with_t // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration( {}, - {{psi, drb_id_t::drb1}, {psi2, drb_id_t::drb2}}, + {{psi, drb_id_t::drb1}}, std::vector{srb_id_t::srb2}, std::vector{drb_id_t::drb1, drb_id_t::drb2})); @@ -400,8 +400,8 @@ TEST_F( ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration - get_cu_up(cu_up_idx).push_tx_pdu( - generate_bearer_context_modification_response(ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id)); + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( + ue_ctx->cu_cp_e1ap_id.value(), cu_up_e1ap_id, {}, {{uint_to_pdu_session_id(1), drb_id_t::drb1}})); ASSERT_TRUE(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu)); ASSERT_TRUE(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu)); { diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index 69f8c03c5b..c3b4bf3f56 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -714,7 +714,7 @@ bool cu_cp_test_environment::send_bearer_context_modification_response_and_await // Inject Bearer Context Modification Response and wait for UE Context Modification Request get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( - ue_ctx.cu_cp_e1ap_id.value(), ue_ctx.cu_up_e1ap_id.value(), {{psi, drb_test_params{drb_id, qfi}}})); + ue_ctx.cu_cp_e1ap_id.value(), ue_ctx.cu_up_e1ap_id.value(), {{psi, drb_test_params{drb_id, qfi}}}, {})); bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); report_fatal_error_if_not(result, "Failed to receive UE Context Modification Request"); report_fatal_error_if_not(test_helpers::is_valid_ue_context_modification_request(f1ap_pdu), From b02fef38b5851d143c1e64f3b4d04cc3bd781a14 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 29 Oct 2024 14:53:30 +0100 Subject: [PATCH 22/72] cu_cp: add unit test for bearer ctxt mod response with failed to modify list --- .../cu_cp_pdu_session_resource_setup_test.cpp | 29 +++++++++++++++++-- .../cu_cp/cu_cp_test_environment.cpp | 10 +++++-- .../unittests/cu_cp/cu_cp_test_environment.h | 3 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 14 ++++++++- .../e1ap/common/e1ap_cu_cp_test_messages.h | 3 +- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp index 52cd0f6569..5e8cf7dfb2 100644 --- a/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_pdu_session_resource_setup_test.cpp @@ -187,7 +187,8 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub const std::map& pdu_sessions_to_add = {}, const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}, const std::optional>& expected_srbs_to_add_mod = std::nullopt, - const std::optional>& expected_drbs_to_add_mod = std::nullopt) + const std::optional>& expected_drbs_to_add_mod = std::nullopt, + const std::vector& pdu_sessions_failed_to_modify = {}) { return cu_cp_test_environment::send_bearer_context_modification_response_and_await_rrc_reconfiguration( du_idx, @@ -196,7 +197,8 @@ class cu_cp_pdu_session_resource_setup_test : public cu_cp_test_environment, pub pdu_sessions_to_add, pdu_sessions_to_modify, expected_srbs_to_add_mod, - expected_drbs_to_add_mod); + expected_drbs_to_add_mod, + pdu_sessions_failed_to_modify); } [[nodiscard]] bool timeout_rrc_reconfiguration_and_await_pdu_session_setup_response() @@ -300,6 +302,29 @@ TEST_F(cu_cp_pdu_session_resource_setup_test, when_bearer_context_modification_f ASSERT_TRUE(send_bearer_context_modification_failure_and_await_pdu_session_setup_response()); } +TEST_F(cu_cp_pdu_session_resource_setup_test, + when_bearer_context_modification_response_contains_failed_to_modify_list_then_no_pdu_session_is_setup) +{ + // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request + ASSERT_TRUE(send_pdu_session_resource_setup_request_and_await_bearer_context_setup_request( + generate_valid_pdu_session_resource_setup_request_message( + ue_ctx->amf_ue_id.value(), ue_ctx->ran_ue_id.value(), {{psi, {{qfi, 9}}}}))); + + // Inject Bearer Context Setup Response and await UE Context Modification Request + ASSERT_TRUE(send_bearer_context_setup_response_and_await_ue_context_modification_request()); + + // Inject UE Context Modification Response and await Bearer Context Modification Request + ASSERT_TRUE(send_ue_context_modification_response_and_await_bearer_context_modification_request()); + + // Inject Bearer Context Modification Response and await DL RRC Message Transfer containing RRC Reconfiguration + ASSERT_TRUE(send_bearer_context_modification_response_and_await_rrc_reconfiguration( + {}, {}, std::vector{srb_id_t::srb2}, {}, {psi})); + + // Inject RRC Reconfiguration Complete and await successful PDU Session Resource Setup Response + ASSERT_TRUE(send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( + generate_rrc_reconfiguration_complete_pdu(3, 7), {}, {psi})); +} + TEST_F(cu_cp_pdu_session_resource_setup_test, when_rrc_reconfiguration_fails_then_setup_fails) { // Inject NGAP PDU Session Resource Setup Request and await Bearer Context Setup Request diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index c3b4bf3f56..852cddb272 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -753,7 +753,8 @@ bool cu_cp_test_environment::send_bearer_context_modification_response_and_await const std::map& pdu_sessions_to_add, const std::map& pdu_sessions_to_modify, const std::optional>& expected_srbs_to_add_mod, - const std::optional>& expected_drbs_to_add_mod) + const std::optional>& expected_drbs_to_add_mod, + const std::vector& pdu_sessions_failed_to_modify) { f1ap_message f1ap_pdu; srsran_assert(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), "there are still F1AP DL messages to pop from DU"); @@ -761,8 +762,11 @@ bool cu_cp_test_environment::send_bearer_context_modification_response_and_await auto& ue_ctx = attached_ues.at(du_ue_id_to_ran_ue_id_map.at(du_idx).at(du_ue_id)); // Inject E1AP Bearer Context Modification Response and wait for DL RRC Message (containing RRC Reconfiguration) - get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response( - ue_ctx.cu_cp_e1ap_id.value(), ue_ctx.cu_up_e1ap_id.value(), pdu_sessions_to_add, pdu_sessions_to_modify)); + get_cu_up(cu_up_idx).push_tx_pdu(generate_bearer_context_modification_response(ue_ctx.cu_cp_e1ap_id.value(), + ue_ctx.cu_up_e1ap_id.value(), + pdu_sessions_to_add, + pdu_sessions_to_modify, + pdu_sessions_failed_to_modify)); bool result = this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu); report_fatal_error_if_not(result, "Failed to receive F1AP DL RRC Message (containing RRC Reconfiguration)"); report_fatal_error_if_not(test_helpers::is_valid_dl_rrc_message_transfer(f1ap_pdu), diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index 0548b7a9b7..8084852c1f 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -210,7 +210,8 @@ class cu_cp_test_environment const std::map& pdu_sessions_to_add = {}, const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}, const std::optional>& expected_srbs_to_add_mod = std::nullopt, - const std::optional>& expected_drbs_to_add_mod = std::nullopt); + const std::optional>& expected_drbs_to_add_mod = std::nullopt, + const std::vector& pdu_sessions_failed_to_modify = {}); [[nodiscard]] bool send_rrc_reconfiguration_complete_and_await_pdu_session_setup_response( unsigned du_idx, diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 8fc05c31cd..08aec1c974 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -226,7 +226,8 @@ e1ap_message srsran::srs_cu_cp::generate_bearer_context_modification_response( gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, const std::map& pdu_sessions_to_add, - const std::map& pdu_sessions_to_modify) + const std::map& pdu_sessions_to_modify, + const std::vector& pdu_sessions_failed_to_modify) { e1ap_message bearer_context_modification_response = {}; @@ -292,6 +293,17 @@ e1ap_message srsran::srs_cu_cp::generate_bearer_context_modification_response( ng_ran_bearer_context_mod_resp.pdu_session_res_modified_list.push_back(pdu_session_res_modified_item); } + ng_ran_bearer_context_mod_resp.pdu_session_res_failed_to_modify_list_present = !pdu_sessions_failed_to_modify.empty(); + for (const auto& psi : pdu_sessions_failed_to_modify) { + asn1::e1ap::pdu_session_res_failed_to_modify_item_s pdu_session_res_failed_to_modify_item = {}; + pdu_session_res_failed_to_modify_item.pdu_session_id = pdu_session_id_to_uint(psi); + pdu_session_res_failed_to_modify_item.cause.set_radio_network(); + pdu_session_res_failed_to_modify_item.cause.radio_network() = + asn1::e1ap::cause_radio_network_opts::options::unspecified; + ng_ran_bearer_context_mod_resp.pdu_session_res_failed_to_modify_list.push_back( + pdu_session_res_failed_to_modify_item); + } + return bearer_context_modification_response; } diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h index 7a42895a74..0439b42d0a 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.h @@ -75,7 +75,8 @@ e1ap_message generate_bearer_context_modification_response( gnb_cu_cp_ue_e1ap_id_t cu_cp_ue_e1ap_id, gnb_cu_up_ue_e1ap_id_t cu_up_ue_e1ap_id, const std::map& pdu_sessions_to_add = {}, - const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}); + const std::map& pdu_sessions_to_modify = {{pdu_session_id_t::min, drb_id_t::drb1}}, + const std::vector& pdu_sessions_failed_to_modify = {}); /// \brief Generate a dummy Bearer Context Modification Failure. /// \param[in] cu_cp_ue_e1ap_id The CU-CP UE E1AP ID. From 84ecf98b61bd92422c5b0aa533158f17f76437c8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 30 Oct 2024 09:46:33 +0100 Subject: [PATCH 23/72] du: complete closed loop UL-MIMO du: review UL-MIMO related --- .../o_du_high/du_high/du_high_config.h | 2 + .../du_high/du_high_config_cli11_schema.cpp | 7 ++ .../du_high/du_high_config_translators.cpp | 7 ++ .../du_high/du_high_config_yaml_writer.cpp | 1 + .../o_du_low/du_low_config_translator.cpp | 1 + include/srsran/du/du_cell_config.h | 3 + .../srsran/phy/upper/upper_phy_factories.h | 2 + include/srsran/ran/pusch/pusch_tpmi_select.h | 2 + .../du_srs_resource_manager.cpp | 3 +- .../ue_capability_manager.cpp | 74 ++++++++++++------- .../ue_capability_manager.h | 23 ++++-- lib/phy/upper/upper_phy_factories.cpp | 13 +++- .../upper/upper_phy_rx_symbol_handler_impl.h | 5 +- lib/ran/pusch/pusch_antenna_port_mapping.cpp | 23 +++--- lib/ran/pusch/pusch_tpmi_select.cpp | 3 +- .../config/serving_cell_config_factory.cpp | 2 +- lib/scheduler/config/ue_configuration.h | 30 +------- lib/scheduler/support/dci_builder.cpp | 2 +- lib/scheduler/ue_context/ue_cell.cpp | 2 +- .../ue_context/ue_channel_state_manager.cpp | 13 +++- .../ue_context/ue_channel_state_manager.h | 2 +- .../ran/pusch/pusch_tpmi_select_test.cpp | 4 +- 22 files changed, 140 insertions(+), 84 deletions(-) diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_du/o_du_high/du_high/du_high_config.h index bca06b39c2..01a8c52f5a 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config.h @@ -168,6 +168,8 @@ struct du_high_unit_pusch_config { unsigned max_consecutive_kos = 100; /// Redundancy version sequence to use. Each element can have one of the following values: {0, 1, 2, 3}. std::vector rv_sequence = {0}; + /// Maximum rank. Limits the number of layers for PUSCH transmissions. + unsigned max_rank = 4; /// MCS table to use for PUSCH pusch_mcs_table mcs_table = pusch_mcs_table::qam64; /// \c msg3-DeltaPreamble, TS 38.331. Values: {-1,...,6}. diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 1863b097ba..227315946a 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -645,6 +645,13 @@ static void configure_cli11_pusch_args(CLI::App& app, du_high_unit_pusch_config& "MCS table to use PUSCH") ->default_str("qam64") ->check(CLI::IsMember({"qam64", "qam256"}, CLI::ignore_case)); + add_option(app, + "--max_rank", + pusch_params.max_rank, + "Maximum number of PUSCH transmission layers. The actual maximum is limited by the number of receive " + "ports and UE capabilities.") + ->capture_default_str() + ->check(CLI::Range(1, 4)); add_option(app, "--msg3_delta_preamble", pusch_params.msg3_delta_preamble, diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp index 4795169e65..b4cc1d4ab1 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp @@ -16,6 +16,7 @@ #include "srsran/du/du_high/du_qos_config_helpers.h" #include "srsran/du/du_update_config_helpers.h" #include "srsran/e2/e2ap_configuration_helpers.h" +#include "srsran/phy/upper/channel_processors/pusch/pusch_processor_phy_capabilities.h" #include "srsran/ran/duplex_mode.h" #include "srsran/ran/prach/prach_configuration.h" #include "srsran/rlc/rlc_srb_config_factory.h" @@ -431,6 +432,12 @@ std::vector srsran::generate_du_cell_config(const du_hig base_cell.pusch_cfg.p0_nominal_with_grant; out_cell.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().msg3_delta_power = base_cell.pusch_cfg.msg3_delta_power; + // Determine the PUSCH transmission maximum number of layers. Selects the most limiting factor among the physical + // layer, number of antennas and configured maximum rank. + pusch_processor_phy_capabilities phy_capabilities = get_pusch_processor_phy_capabilities(); + out_cell.pusch_max_nof_layers = + std::min(cell.cell.nof_antennas_ul, std::min(phy_capabilities.max_nof_layers, cell.cell.pusch_cfg.max_rank)); + if (config.ntn_cfg.has_value()) { out_cell.ntn_cs_koffset = config.ntn_cfg.value().cell_specific_koffset; } diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_yaml_writer.cpp index 3f3d82154f..7f73fc9468 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_yaml_writer.cpp @@ -350,6 +350,7 @@ static YAML::Node build_du_high_pusch_section(const du_high_unit_pusch_config& c node["max_ue_mcs"] = config.max_ue_mcs; node["max_consecutive_kos"] = config.max_consecutive_kos; node["mcs_table"] = to_string(config.mcs_table); + node["max_rank"] = config.max_rank; node["msg3_delta_preamble"] = config.msg3_delta_preamble; node["p0_nominal_with_grant"] = config.p0_nominal_with_grant; node["max_puschs_per_slot"] = config.max_puschs_per_slot; diff --git a/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp b/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp index fc1e46a550..f4b247a6fc 100644 --- a/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp +++ b/apps/units/flexible_du/o_du_low/du_low_config_translator.cpp @@ -110,6 +110,7 @@ static void generate_du_low_config(srs_du::du_low_config& out_config } upper_phy_cell.nof_slots_request_headroom = du_low.expert_phy_cfg.nof_slots_request_headroom; + upper_phy_cell.pusch_max_nof_layers = cell.pusch_max_nof_layers; upper_phy_cell.log_level = du_low.loggers.phy_level; upper_phy_cell.enable_logging_broadcast = du_low.loggers.broadcast_enabled; upper_phy_cell.rx_symbol_printer_filename = du_low.loggers.phy_rx_symbols_filename; diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index 3e6a14d5d5..8ca199b868 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -206,6 +206,9 @@ struct du_cell_config { /// Defines the maximum allowable channel delay in slots when runnning in NTN mode. see TS38.300 section 16.14.2. unsigned ntn_cs_koffset = 0; + /// PUSCH Maximum of transmission layers. Limits the PUSCH maximum rank the UE is configrued with. + unsigned pusch_max_nof_layers = 1; + /// List of RAN slices to support in the scheduler. std::vector rrm_policy_members; }; diff --git a/include/srsran/phy/upper/upper_phy_factories.h b/include/srsran/phy/upper/upper_phy_factories.h index e93711077a..fd8d831548 100644 --- a/include/srsran/phy/upper/upper_phy_factories.h +++ b/include/srsran/phy/upper/upper_phy_factories.h @@ -314,6 +314,8 @@ struct upper_phy_config { unsigned ul_bw_rb; /// Request headroom size in slots. unsigned nof_slots_request_headroom; + /// Maximum number of layers for PUSCH transmissions. + unsigned pusch_max_nof_layers; /// List of active subcarrier spacing, indexed by numerology. std::array active_scs; /// Receive buffer pool configuration. diff --git a/include/srsran/ran/pusch/pusch_tpmi_select.h b/include/srsran/ran/pusch/pusch_tpmi_select.h index ac71bfb230..9734fc7934 100644 --- a/include/srsran/ran/pusch/pusch_tpmi_select.h +++ b/include/srsran/ran/pusch/pusch_tpmi_select.h @@ -67,10 +67,12 @@ class pusch_tpmi_select_info /// /// \param[in] channel Channel coefficient matrix. /// \param[in] noise_variance Linear noise variance. +/// \param[in] max_rank Maximum number of layers. /// \param[in] codebook_subset Transmission scheme codebook subset. /// \return The TPMI information given the channel coefficients and noise variance. pusch_tpmi_select_info get_tpmi_select_info(const srs_channel_matrix& channel, float noise_variance, + unsigned max_rank, tx_scheme_codebook_subset codebook_subset); } // namespace srsran diff --git a/lib/du/du_high/du_manager/ran_resource_management/du_srs_resource_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/du_srs_resource_manager.cpp index edc26ca8b6..a05e09175b 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/du_srs_resource_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/du_srs_resource_manager.cpp @@ -249,8 +249,7 @@ bool du_srs_policy_max_ul_rate::alloc_resources(cell_group_config& cell_grp_cfg) cells[primary_cell_index].cell_cfg.ul_carrier.nof_ant == 2 or cells[primary_cell_index].cell_cfg.ul_carrier.nof_ant == 4, "The number of UL antenna ports is not valid"); - only_ue_srs_res.nof_ports = - static_cast(cells[primary_cell_index].cell_cfg.ul_carrier.nof_ant); + only_ue_srs_res.nof_ports = srs_config::srs_resource::nof_srs_ports::port1; only_ue_srs_res.tx_comb.size = cells[primary_cell_index].cell_cfg.srs_cfg.tx_comb; only_ue_srs_res.tx_comb.tx_comb_offset = du_res.tx_comb_offset.to_uint(); only_ue_srs_res.tx_comb.tx_comb_cyclic_shift = du_res.cs; diff --git a/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.cpp index eaef34daca..8e3452a415 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.cpp @@ -97,6 +97,28 @@ static void set_pusch_mcs_table(serving_cell_config& cell_cfg, pusch_mcs_table m } } +// Configure dedicated UE configuration to set UL-MIMO related parameters. +static void set_ul_mimo(serving_cell_config& cell_cfg, + unsigned max_rank, + unsigned nof_srs_ports, + tx_scheme_codebook_subset codebook_subset) +{ + // Skip if the UL configuration is not present. + if (SRSRAN_UNLIKELY(!cell_cfg.ul_config.has_value() || !cell_cfg.ul_config->init_ul_bwp.pusch_cfg || + !cell_cfg.ul_config->init_ul_bwp.srs_cfg)) { + return; + } + + // Prepare codebook transmission parameters. + cell_cfg.ul_config->init_ul_bwp.pusch_cfg->tx_cfg = + tx_scheme_codebook{.max_rank = max_rank, .codebook_subset = codebook_subset}; + + // Force the number of ports for all SRS resources to the maximum the UE supports. + for (auto& srs_res : cell_cfg.ul_config->init_ul_bwp.srs_cfg->srs_res_list) { + srs_res.nof_ports = static_cast(nof_srs_ports); + } +} + ue_capability_manager::ue_capability_manager(span cell_cfg_list_, srslog::basic_logger& logger_) : base_cell_cfg_list(cell_cfg_list_), logger(logger_) { @@ -120,6 +142,10 @@ void ue_capability_manager::update(du_ue_resource_config& ue_res_cfg, const byte // Enable 256QAM for PUSCH, if supported. set_pusch_mcs_table(pcell_cfg, select_pusch_mcs_table(cell_idx)); + + // Setup UL MIMO parameters. + set_ul_mimo( + pcell_cfg, select_pusch_max_rank(cell_idx), select_srs_nof_ports(cell_idx), select_tx_codebook_subset(cell_idx)); } bool ue_capability_manager::decode_ue_capability_list(const byte_buffer& ue_cap_rat_list) @@ -198,41 +224,39 @@ pusch_mcs_table ue_capability_manager::select_pusch_mcs_table(du_cell_index_t ce tx_scheme_codebook_subset ue_capability_manager::select_tx_codebook_subset(du_cell_index_t cell_idx) const { - nr_band band = base_cell_cfg_list[cell_idx].ul_carrier.band; - const auto& base_ul_cfg = base_cell_cfg_list[cell_idx].ue_ded_serv_cell_cfg.ul_config; + nr_band band = base_cell_cfg_list[cell_idx].ul_carrier.band; - // Default to non-coherent, if no PUSCH config or no UE capabilities decoded yet. - if (not base_ul_cfg.has_value() or not base_ul_cfg->init_ul_bwp.pusch_cfg.has_value() or not ue_caps.has_value()) { - return tx_scheme_codebook_subset::non_coherent; + // If UE capabilities or the band are not available, return default value. + if (not ue_caps.has_value() || ue_caps->bands.count(band) == 0) { + return ue_capability_summary::default_pusch_tx_coherence; } - // If the band capability is present, select the codebook from this band. - if (ue_caps->bands.count(band)) { - return ue_caps->bands.at(band).pusch_tx_coherence; - } + return ue_caps->bands.at(band).pusch_tx_coherence; +} - // Find the band with the most limiting transmit codebook subset across all the bands. - const auto min_tx_codebook_subset = - std::min_element(ue_caps->bands.begin(), ue_caps->bands.end(), [](const auto& lhs, const auto& rhs) { - // The most limiting codebook subset has the greater integer value. - return rhs.second.pusch_tx_coherence > lhs.second.pusch_tx_coherence; - }); +unsigned ue_capability_manager::select_srs_nof_ports(du_cell_index_t cell_idx) const +{ + nr_band band = base_cell_cfg_list[cell_idx].ul_carrier.band; - // Select the most limiting transmit subset if the band list is not emtpy. - if (min_tx_codebook_subset != ue_caps->bands.end()) { - return min_tx_codebook_subset->second.pusch_tx_coherence; + // If UE capabilities or the band are not available, return default value. + if (not ue_caps.has_value() || ue_caps->bands.count(band) == 0) { + return ue_capability_summary::default_nof_srs_tx_ports; } - // Otherwise, default to non-coherent. - return tx_scheme_codebook_subset::non_coherent; + return ue_caps->bands.at(band).nof_srs_tx_ports; } -unsigned ue_capability_manager::select_srs_nof_ports() const +unsigned ue_capability_manager::select_pusch_max_rank(du_cell_index_t cell_idx) const { - // Default to one port if the UE capabilities are not present. - if (not ue_caps.has_value()) { - return 1; + nr_band band = base_cell_cfg_list[cell_idx].ul_carrier.band; + + // Configured maximum number of layers. + unsigned pusch_max_rank = base_cell_cfg_list[cell_idx].pusch_max_nof_layers; + + // If UE capabilities or the band are not available, return default value. + if (not ue_caps.has_value() || ue_caps->bands.count(band) == 0) { + return std::min(pusch_max_rank, ue_capability_summary::default_pusch_max_rank); } - return ue_caps->nof_srs_tx_ports; + return std::min(pusch_max_rank, ue_caps->bands.at(band).pusch_max_rank); } diff --git a/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.h b/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.h index d5289e1f66..164208c424 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.h +++ b/lib/du/du_high/du_manager/ran_resource_management/ue_capability_manager.h @@ -28,6 +28,16 @@ namespace srs_du { /// Flat structure summarizing the decoded ASN.1 UE capabilities. struct ue_capability_summary { + /// \defgroup default_caps Default parameters. + /// @{ + /// Default PUSCH transmit coherence. + static constexpr tx_scheme_codebook_subset default_pusch_tx_coherence = tx_scheme_codebook_subset::non_coherent; + /// Default PUSCH maximum number of layers. + static constexpr unsigned default_pusch_max_rank = 1; + /// Default SRS number of transmit ports. + static constexpr unsigned default_nof_srs_tx_ports = 1; + /// @} + /// Contains band specific parameters. struct supported_band { /// Set to true if QAM-256 is supported for PUSCH transmissions. @@ -37,14 +47,15 @@ struct ue_capability_summary { /// It is given by field \e pusch-TransCoherence in Information Element \e MIMO-ParametersPerBand. /// /// The most limiting transmit codebook subset is selected by default. - tx_scheme_codebook_subset pusch_tx_coherence = tx_scheme_codebook_subset::non_coherent; + tx_scheme_codebook_subset pusch_tx_coherence = default_pusch_tx_coherence; + /// Maximum PUSCH number of layers. + unsigned pusch_max_rank = default_pusch_max_rank; + /// Maximum number of ports that can be simultaneously used for transmiting Sounding Reference Signals. + uint8_t nof_srs_tx_ports = default_nof_srs_tx_ports; }; /// Set to true if QAM-256 MCS table are supported for PDSCH transmissions. bool pdsch_qam256_supported = false; - /// Number of Sounding Reference Signals transmit ports. It is set to the most limiting band combination of - /// transmitters. - uint8_t nof_srs_tx_ports = 1; /// Contains specific bands capabilities. std::unordered_map bands; /// Set to true if Long DRX cycle is supported. @@ -84,7 +95,9 @@ class ue_capability_manager /// Selects the PUSCH transmission codebook subset. tx_scheme_codebook_subset select_tx_codebook_subset(du_cell_index_t cell_idx) const; /// Selects the SRS transmission number of ports. - unsigned select_srs_nof_ports() const; + unsigned select_srs_nof_ports(du_cell_index_t cell_idx) const; + /// Selects the PUSCH maximum number of layers. + unsigned select_pusch_max_rank(du_cell_index_t cell_idx) const; span base_cell_cfg_list; srslog::basic_logger& logger; diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index c783620fb8..7632fdead0 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -23,6 +23,7 @@ #include "srsran/phy/upper/channel_processors/pdsch/factories.h" #include "srsran/phy/upper/channel_processors/pucch/factories.h" #include "srsran/phy/upper/channel_processors/pusch/factories.h" +#include "srsran/phy/upper/channel_processors/pusch/pusch_processor_phy_capabilities.h" #include "srsran/phy/upper/signal_processors/srs/srs_estimator_factory.h" #include "srsran/phy/upper/unique_rx_buffer.h" #include "srsran/support/error_handling.h" @@ -335,6 +336,14 @@ create_ul_resource_grid_pool(const upper_phy_config& config, std::shared_ptr create_ul_processor_factory(const upper_phy_config& config) { + // Verify the PUSCH processor capabilities. + pusch_processor_phy_capabilities pusch_capabilities = get_pusch_processor_phy_capabilities(); + report_fatal_error_if_not(pusch_capabilities.max_nof_layers >= config.pusch_max_nof_layers, + "The configured PUSCH maximum number of layers (i.e., {}) exceeds the maximum PUSCH " + "processor capable number of layers (i.e., {}).", + pusch_capabilities.max_nof_layers, + config.pusch_max_nof_layers); + std::shared_ptr sequence_factory = create_low_papr_sequence_generator_sw_factory(); report_fatal_error_if_not(sequence_factory, "Invalid sequence factory."); @@ -412,7 +421,7 @@ static std::shared_ptr create_ul_processor_factory(con decoder_config.nof_pusch_decoder_threads = config.nof_pusch_decoder_threads; decoder_config.executor = config.pusch_decoder_executor; decoder_config.nof_prb = config.ul_bw_rb; - decoder_config.nof_layers = 1; + decoder_config.nof_layers = config.pusch_max_nof_layers; pusch_config.decoder_factory = create_pusch_decoder_factory_sw(decoder_config); } else { pusch_decoder_factory_hw_configuration decoder_config; @@ -466,7 +475,7 @@ static std::shared_ptr create_ul_processor_factory(con // :TODO: check these values in the future. Extract them to more public config. pusch_config.ch_estimate_dimensions.nof_symbols = MAX_NSYMB_PER_SLOT; - pusch_config.ch_estimate_dimensions.nof_tx_layers = 1; + pusch_config.ch_estimate_dimensions.nof_tx_layers = config.pusch_max_nof_layers; pusch_config.ch_estimate_dimensions.nof_prb = config.ul_bw_rb; pusch_config.ch_estimate_dimensions.nof_rx_ports = config.nof_rx_ports; std::shared_ptr pusch_factory = create_pusch_processor_factory_sw(pusch_config); diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h index 78fcb5d625..e470745219 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_impl.h @@ -34,7 +34,7 @@ class rx_payload_buffer_pool /// Maximum number of slots to store. static constexpr size_t nof_slots = 40U; /// Maximum number of bits that could potentially be allocated in a slot. - static constexpr units::bits max_buffer_size = units::bits(MAX_RB * 156 * 8); + static constexpr units::bits max_buffer_size = units::bits(MAX_RB * 156 * 8 * 2); /// Minimum block size. It ensures that the payload offsets are selected using multiples of blocks. static constexpr unsigned min_block_size = 64; @@ -45,7 +45,8 @@ class rx_payload_buffer_pool // Convert the maximum buffer size from bits to bytes for comparison and allocation. static constexpr units::bytes max_buffer_size_bytes = max_buffer_size.truncate_to_bytes(); - srsran_assert(size <= max_buffer_size_bytes, "Buffer size (i.e., {}) exceeds maximum {}.", size, pool.size()); + srsran_assert( + size <= max_buffer_size_bytes, "Buffer size (i.e., {}) exceeds maximum {}.", size, max_buffer_size_bytes); // Round the number of consumed bytes to the next block. size_t count = divide_ceil(size.value(), min_block_size) * min_block_size; diff --git a/lib/ran/pusch/pusch_antenna_port_mapping.cpp b/lib/ran/pusch/pusch_antenna_port_mapping.cpp index 8a258793f2..b2c7b3de31 100644 --- a/lib/ran/pusch/pusch_antenna_port_mapping.cpp +++ b/lib/ran/pusch/pusch_antenna_port_mapping.cpp @@ -15,10 +15,10 @@ using namespace srsran; // Current range of supported number of layers. static constexpr interval nof_layers_range(1, 1); -unsigned srsran::get_pusch_antenna_port_mapping_row_index(unsigned nof_layers, - bool transform_precoder, - dmrs_config_type dmrs_cfg_type, - dmrs_max_length dmrs_max_len) +SRSRAN_WEAK_SYMB unsigned srsran::get_pusch_antenna_port_mapping_row_index(unsigned nof_layers, + bool transform_precoder, + dmrs_config_type dmrs_cfg_type, + dmrs_max_length dmrs_max_len) { srsran_assert(nof_layers_range.contains(nof_layers), "The number of layers (i.e., {}) is out of the range {}.", @@ -38,13 +38,14 @@ unsigned srsran::get_pusch_antenna_port_mapping_row_index(unsigned nof_l return 2; } -unsigned srsran::get_pusch_precoding_info_row_index(unsigned nof_layers, - unsigned max_rank, - srs_resource_configuration::one_two_four_enum nof_srs_ports, - bool transform_precoder, - dmrs_config_type dmrs_cfg_type, - dmrs_max_length dmrs_max_len, - unsigned tpmi) +SRSRAN_WEAK_SYMB unsigned +srsran::get_pusch_precoding_info_row_index(unsigned nof_layers, + unsigned max_rank, + srs_resource_configuration::one_two_four_enum nof_srs_ports, + bool transform_precoder, + dmrs_config_type dmrs_cfg_type, + dmrs_max_length dmrs_max_len, + unsigned tpmi) { static constexpr interval max_rank_range(1, 4); srsran_assert( diff --git a/lib/ran/pusch/pusch_tpmi_select.cpp b/lib/ran/pusch/pusch_tpmi_select.cpp index 40a9fa776d..e9b65704c5 100644 --- a/lib/ran/pusch/pusch_tpmi_select.cpp +++ b/lib/ran/pusch/pusch_tpmi_select.cpp @@ -296,11 +296,12 @@ static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_2layer(const srs_c pusch_tpmi_select_info srsran::get_tpmi_select_info(const srs_channel_matrix& channel, float noise_variance, + unsigned max_rank, tx_scheme_codebook_subset codebook_subset) { unsigned nof_tx_ports = channel.get_nof_tx_ports(); unsigned nof_rx_ports = channel.get_nof_rx_ports(); - unsigned max_nof_layers = std::min(nof_tx_ports, nof_rx_ports); + unsigned max_nof_layers = std::min(std::min(nof_tx_ports, nof_rx_ports), max_rank); static_vector info; diff --git a/lib/scheduler/config/serving_cell_config_factory.cpp b/lib/scheduler/config/serving_cell_config_factory.cpp index 4ee34ae311..b814112ca5 100644 --- a/lib/scheduler/config/serving_cell_config_factory.cpp +++ b/lib/scheduler/config/serving_cell_config_factory.cpp @@ -429,7 +429,7 @@ ssb_configuration srsran::config_helpers::make_default_ssb_config(const cell_con pusch_config srsran::config_helpers::make_default_pusch_config(const cell_config_builder_params_extended& params) { // Default PUSCH transmission scheme is codebook with at maximum one layer. It assumes the UE Capability parameter - // pusch-TransCoherence is fullCoherent. + // pusch-TransCoherence is nonCoherent. static constexpr unsigned max_rank = 1; static constexpr tx_scheme_codebook_subset codebook_subset = tx_scheme_codebook_subset::non_coherent; diff --git a/lib/scheduler/config/ue_configuration.h b/lib/scheduler/config/ue_configuration.h index e010ac8c3c..a373674248 100644 --- a/lib/scheduler/config/ue_configuration.h +++ b/lib/scheduler/config/ue_configuration.h @@ -170,12 +170,12 @@ class ue_cell_configuration return cell_cfg_ded.ul_config->init_ul_bwp.pusch_cfg->trans_precoder == pusch_config::transform_precoder::enabled; } - /// \brief Gets the PUSCH transmit scheme codebook subset. + /// \brief Gets the PUSCH transmit scheme codebook configuration. /// - /// The codebook subset is selection procedure is described in TS 38.214 Section 6.1.1.1. + /// The codebook subset selection procedure is described in TS 38.214 Section 6.1.1.1. /// /// \remark An assertion is triggered if the transmission scheme is not present or not set to codebook. - tx_scheme_codebook_subset get_pusch_codebook_subset() const + const tx_scheme_codebook& get_pusch_codebook_config() const { srsran_assert(cell_cfg_ded.ul_config.has_value(), "Missing dedicated UL configuration."); srsran_assert(cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.has_value(), @@ -185,29 +185,7 @@ class ue_cell_configuration srsran_assert(std::holds_alternative( cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.value().tx_cfg.value()), "PUSCH Transmission scheme must be set to codebook."); - const auto& tx_config = - std::get(cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.value().tx_cfg.value()); - return tx_config.codebook_subset; - } - - /// \brief Gets the PUSCH maximum number of layers. - /// - /// The maximum number of layers selection procedudre is described in TS 38.214 Section 6.1.1.1. - /// - /// \remark An assertion is triggered if the transmission scheme is not present or not set to codebook. - uint8_t get_pusch_max_rank() const - { - srsran_assert(cell_cfg_ded.ul_config.has_value(), "Missing dedicated UL configuration."); - srsran_assert(cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.has_value(), - "Missing dedicated PUSCH configuration."); - srsran_assert(cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.value().tx_cfg.has_value(), - "Missing transmit configuration."); - srsran_assert(std::holds_alternative( - cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.value().tx_cfg.value()), - "PUSCH Transmission scheme must be set to codebook."); - const auto& tx_config = - std::get(cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.value().tx_cfg.value()); - return tx_config.max_rank.to_uint(); + return std::get(cell_cfg_ded.ul_config.value().init_ul_bwp.pusch_cfg.value().tx_cfg.value()); } private: diff --git a/lib/scheduler/support/dci_builder.cpp b/lib/scheduler/support/dci_builder.cpp index 947da918c1..f711837f45 100644 --- a/lib/scheduler/support/dci_builder.cpp +++ b/lib/scheduler/support/dci_builder.cpp @@ -407,7 +407,7 @@ void srsran::build_dci_f0_1_c_rnti(dci_ul_info& dci, nof_layers, use_transform_precoder, dmrs_config_type::type1, dmrs_max_length::len1); f0_1.precoding_info_nof_layers = get_pusch_precoding_info_row_index(nof_layers, - ue_cell_cfg.get_pusch_max_rank(), + ue_cell_cfg.get_pusch_codebook_config().max_rank.value(), srs_resource_configuration::one_two_four_enum::four, use_transform_precoder, dmrs_config_type::type1, diff --git a/lib/scheduler/ue_context/ue_cell.cpp b/lib/scheduler/ue_context/ue_cell.cpp index b5f03a4408..fa43384cd1 100644 --- a/lib/scheduler/ue_context/ue_cell.cpp +++ b/lib/scheduler/ue_context/ue_cell.cpp @@ -292,7 +292,7 @@ int ue_cell::handle_crc_pdu(slot_point pusch_slot, const ul_crc_pdu_indication& void ue_cell::handle_srs_channel_matrix(const srs_channel_matrix& channel_matrix) { - channel_state.update_srs_channel_matrix(channel_matrix, ue_cfg->get_pusch_codebook_subset()); + channel_state.update_srs_channel_matrix(channel_matrix, ue_cfg->get_pusch_codebook_config()); } void ue_cell::handle_csi_report(const csi_report_data& csi_report) diff --git a/lib/scheduler/ue_context/ue_channel_state_manager.cpp b/lib/scheduler/ue_context/ue_channel_state_manager.cpp index 5c4bcb286c..9f77ca9a52 100644 --- a/lib/scheduler/ue_context/ue_channel_state_manager.cpp +++ b/lib/scheduler/ue_context/ue_channel_state_manager.cpp @@ -63,11 +63,16 @@ bool ue_channel_state_manager::handle_csi_report(const csi_report_data& csi_repo return true; } -void ue_channel_state_manager::update_srs_channel_matrix(const srsran::srs_channel_matrix& channel_matrix, - tx_scheme_codebook_subset cb_subset) +void ue_channel_state_manager::update_srs_channel_matrix(const srs_channel_matrix& channel_matrix, + tx_scheme_codebook codebook_cfg) { - float norm = channel_matrix.frobenius_norm(); - last_pusch_tpmi_select_info = get_tpmi_select_info(channel_matrix, norm * norm, cb_subset); + // [Implementation-defined] Assume noise variance is 30dB below the average received power. + float norm = channel_matrix.frobenius_norm(); + float noise_var = norm * norm / 1000; + + // Calculate TPMI information. + last_pusch_tpmi_select_info = + get_tpmi_select_info(channel_matrix, noise_var, codebook_cfg.max_rank.value(), codebook_cfg.codebook_subset); } SRSRAN_WEAK_SYMB unsigned ue_channel_state_manager::get_nof_ul_layers() const diff --git a/lib/scheduler/ue_context/ue_channel_state_manager.h b/lib/scheduler/ue_context/ue_channel_state_manager.h index 52787a6965..13b453d292 100644 --- a/lib/scheduler/ue_context/ue_channel_state_manager.h +++ b/lib/scheduler/ue_context/ue_channel_state_manager.h @@ -68,7 +68,7 @@ class ue_channel_state_manager bool handle_csi_report(const csi_report_data& csi_report); /// Update UE with the latest Sounding Reference Signal (SRS) channel matrix. - void update_srs_channel_matrix(const srs_channel_matrix& channel_matrix, tx_scheme_codebook_subset cb_subset); + void update_srs_channel_matrix(const srs_channel_matrix& channel_matrix, tx_scheme_codebook codebook_cfg); /// Update UE with the latest PHR for a given cell. void handle_phr(const cell_ph_report& phr); diff --git a/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp b/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp index 82e1f66934..8c7d5e1abd 100644 --- a/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp +++ b/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp @@ -119,8 +119,8 @@ TEST_P(PuschTpmiSelectFixture, VectorTest) } // Get UL-SCH information parameters. - pusch_tpmi_select_info info = - get_tpmi_select_info(test_case.channel_matrix, test_case.noise_variance, test_case.codebook_subset); + pusch_tpmi_select_info info = get_tpmi_select_info( + test_case.channel_matrix, test_case.noise_variance, max_nof_layers, test_case.codebook_subset); // Compare with expected. ASSERT_EQ(info, test_case.info); From 87bdabe686a784eefa794695af923427bf2f9f77 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Wed, 6 Nov 2024 15:45:59 +0100 Subject: [PATCH 24/72] ci: improve PR ci --- .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/handover.py | 2 +- tests/e2e/tests/reestablishment.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 82bbb483a5..e1e70aaecf 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.54.10 +RETINA_VERSION=0.54.11 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/tests/handover.py b/tests/e2e/tests/handover.py index 254b481b43..44e559b109 100644 --- a/tests/e2e/tests/handover.py +++ b/tests/e2e/tests/handover.py @@ -62,7 +62,7 @@ def test_smoke_sequentially( common_scs=30, bandwidth=50, noise_spd=0, - sleep_between_movement_steps=2, + sleep_between_movement_steps=1, always_download_artifacts=False, ) diff --git a/tests/e2e/tests/reestablishment.py b/tests/e2e/tests/reestablishment.py index ccee31109e..0c74036356 100644 --- a/tests/e2e/tests/reestablishment.py +++ b/tests/e2e/tests/reestablishment.py @@ -47,7 +47,7 @@ def test_smoke_sequentially( retina_manager: RetinaTestManager, retina_data: RetinaTestData, - ue_4: Tuple[UEStub, ...], + ue_2: Tuple[UEStub, ...], fivegc: FiveGCStub, gnb: GNBStub, ): @@ -57,7 +57,7 @@ def test_smoke_sequentially( _reestablishment_sequentially_ping( retina_manager=retina_manager, retina_data=retina_data, - ue_array=ue_4, + ue_array=ue_2, fivegc=fivegc, gnb=gnb, metrics_summary=None, From 0b1d71dcd53a9fc96ae03390e68ec7920dd0f395 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 5 Nov 2024 10:08:44 +0100 Subject: [PATCH 25/72] phy: pucch demodulator format 4 --- .../pucch/pucch_demodulator.h | 30 ++- .../phy/upper/pucch_orthogonal_sequence.h | 47 ++++- include/srsran/ran/pucch/pucch_constants.h | 9 + .../channel_processors/pucch/CMakeLists.txt | 3 +- .../channel_processors/pucch/factories.cpp | 9 +- .../pucch/pucch_demodulator_format4.cpp | 172 +++++++++++++++++ .../pucch/pucch_demodulator_format4.h | 89 +++++++++ .../pucch/pucch_demodulator_impl.h | 13 +- .../pucch/pucch_detector_format1.cpp | 2 +- .../dmrs_pucch_processor_format1_impl.cpp | 4 +- .../channel_processors/pucch/CMakeLists.txt | 13 ++ .../pucch/pucch_demodulator_format4_test.cpp | 177 ++++++++++++++++++ .../pucch_demodulator_format4_test_data.h | 105 +++++++++++ ...pucch_demodulator_format4_test_data.tar.gz | 3 + 14 files changed, 664 insertions(+), 12 deletions(-) create mode 100644 lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp create mode 100644 lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h create mode 100644 tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test.cpp create mode 100644 tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h create mode 100644 tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz diff --git a/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h b/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h index b8e53ef61a..14a3cf75a1 100644 --- a/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h +++ b/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h @@ -75,7 +75,35 @@ class pucch_demodulator /// Collects PUCCH Format 4 demodulation parameters. struct format4_configuration { - // Add here PUCCH demodulator parameters... + /// Port indexes used for the PUCCH reception. + static_vector rx_ports; + /// Lowest PRB index used for the PUCCH transmission within the resource grid {0, ..., 274}. + unsigned first_prb; + /// \brief Index of the first PRB after frequency hopping as per TS38.213 Section 9.2.1. + /// + /// Lowest PRB index used for the PUCCH transmission within the BWP {0, ..., 274} if intra-slot frequency hopping is + /// enabled, empty otherwise. + std::optional second_hop_prb; + /// Start symbol index within the slot {0, ..., 13}. + unsigned start_symbol_index; + /// Number of symbols for the PUCCH transmission {4, ... , 14}. + unsigned nof_symbols; + /// Radio Network Temporary Identifier, see parameter \f$n_{RNTI}\f$ in TS38.211 Section 6.3.2.5.1. + uint16_t rnti; + /// Scrambling identifier, see parameter \f$n_{ID}\f$ in TS38.211 Section 6.3.2.5.1. Range is {0, ..., 1023}. + unsigned n_id; + /// Set to higher layer parameter \e additionalDMRS described in TS38.331 Section 6.3.2, Information Element \e + /// PUCCH-FormatConfig. + bool additional_dmrs; + /// Set to higher layer parameter \e pi2BPSK described in TS38.331 Section 6.3.2, Information Element \e + /// PUCCH-FormatConfig. + bool pi2_bpsk; + /// Set to higher layer parameter \e occ-Length described in TS38.331 Section 6.3.2, Information Element \e + /// PUCCH-format4. + unsigned occ_length; + /// Set to higher layer parameter \e occ-Index described in TS38.331 Section 6.3.2, Information Element \e + /// PUCCH-format4. + unsigned occ_index; }; /// Default destructor. diff --git a/include/srsran/phy/upper/pucch_orthogonal_sequence.h b/include/srsran/phy/upper/pucch_orthogonal_sequence.h index 9735d7abdc..329ca52bc5 100644 --- a/include/srsran/phy/upper/pucch_orthogonal_sequence.h +++ b/include/srsran/phy/upper/pucch_orthogonal_sequence.h @@ -9,7 +9,7 @@ */ /// \file -/// \brief Generation of PUCCH Format 1 orthogonal sequences. +/// \brief Generation of PUCCH orthogonal sequences. #pragma once @@ -23,7 +23,7 @@ namespace srsran { /// Generator of orthogonal sequences \e w for PUCCH Format 1. -class pucch_orthogonal_sequence +class pucch_orthogonal_sequence_format1 { private: /// Alias for sequence table type. @@ -65,7 +65,7 @@ class pucch_orthogonal_sequence public: /// Constructor: builds the sequences \e w from the coefficients in \ref pucch_format1_phi. - pucch_orthogonal_sequence() + pucch_orthogonal_sequence_format1() { for (unsigned n_pucch = 0, max_n_pucch = pucch_constants::FORMAT1_N_MAX; n_pucch != max_n_pucch; ++n_pucch) { for (unsigned i_seq = 0; i_seq != pucch_constants::FORMAT1_N_MAX; ++i_seq) { @@ -118,4 +118,45 @@ class pucch_orthogonal_sequence } }; +/// Generator of orthogonal sequences \e w for PUCCH Format 4. +class pucch_orthogonal_sequence_format4 +{ +private: + static constexpr auto one = cf_t(1.0f, 0.0f); + static constexpr auto neg_one = cf_t(-1.0f, 0.0f); + static constexpr auto j = cf_t(0.0f, 1.0f); + static constexpr auto neg_j = cf_t(0.0f, -1.0f); + + static constexpr std::array, 2> pucch_format4_length2 = {{ + {one, one, one, one, one, one, one, one, one, one, one, one}, + {one, one, one, one, one, one, neg_one, neg_one, neg_one, neg_one, neg_one, neg_one}, + }}; + + static constexpr std::array, 4> pucch_format4_length4 = {{ + {one, one, one, one, one, one, one, one, one, one, one, one}, + {one, one, one, neg_j, neg_j, neg_j, neg_one, neg_one, neg_one, j, j, j}, + {one, one, one, neg_one, neg_one, neg_one, one, one, one, neg_one, neg_one, neg_one}, + {one, one, one, j, j, j, neg_one, neg_one, neg_one, neg_j, neg_j, neg_j}, + }}; + +public: + /// \brief Gets an entire PUCCH Format 4 orthogonal sequence. + /// + /// \param[in] n_pucch Length of the PUCCH Format 4 sequence + /// \f$N_{\text{SF},m'}^{\text{PUCCH},4} \in \{2, 4\}\f$. + /// \param[in] i Sequence index \f$i \in \{0, \dots, N_{\text{SF},m'}^{\text{PUCCH},4} - 1\}\f$. + /// \returns The requested sequence. + /// \warning An assertion is thrown if the inputs do not match the limits above. + static span get_sequence(unsigned n_pucch, unsigned i) + { + srsran_assert((n_pucch == 2) || (n_pucch == 4), "Invalid n_pucch {}: valid values 2 or 4.", n_pucch); + srsran_assert(i < n_pucch, "Invalid sequence index i = {}, valid values from 0 to {}.", i, n_pucch - 1); + + if (n_pucch == 2) { + return pucch_format4_length2[i]; + } + return pucch_format4_length4[i]; + } +}; + } // namespace srsran diff --git a/include/srsran/ran/pucch/pucch_constants.h b/include/srsran/ran/pucch/pucch_constants.h index ca1f02b666..8043761161 100644 --- a/include/srsran/ran/pucch/pucch_constants.h +++ b/include/srsran/ran/pucch/pucch_constants.h @@ -59,6 +59,15 @@ static constexpr unsigned FORMAT3_MAX_NSYMB = 14; /// Maximum number of PRBs allocated for PUCCH Format 3. static constexpr unsigned FORMAT3_MAX_NPRB = 16; +/// Minimum number of symbols that PUCCH Format 4 can transmit. +static constexpr unsigned FORMAT4_MIN_NSYMB = 4; + +/// Maximum number of symbols that PUCCH Format 4 can transmit. +static constexpr unsigned FORMAT4_MAX_NSYMB = 14; + +/// Maximum number of PRBs allocated for PUCCH Format 4. +static constexpr unsigned FORMAT4_MAX_NPRB = 1; + /// \brief Maximum number of resource elements used by PUCCH. /// /// It corresponds to PUCCH Format 3 with a bandwidth of 16 PRBs and a duration of 14 symbols, two of which are occupied diff --git a/lib/phy/upper/channel_processors/pucch/CMakeLists.txt b/lib/phy/upper/channel_processors/pucch/CMakeLists.txt index 34abfcfead..5a635204e4 100644 --- a/lib/phy/upper/channel_processors/pucch/CMakeLists.txt +++ b/lib/phy/upper/channel_processors/pucch/CMakeLists.txt @@ -16,4 +16,5 @@ add_library(srsran_pucch_detector STATIC add_library(srsran_pucch_demodulator STATIC factories.cpp pucch_demodulator_format2.cpp - pucch_demodulator_format3.cpp) + pucch_demodulator_format3.cpp + pucch_demodulator_format4.cpp) diff --git a/lib/phy/upper/channel_processors/pucch/factories.cpp b/lib/phy/upper/channel_processors/pucch/factories.cpp index edb94d54bf..122414735c 100644 --- a/lib/phy/upper/channel_processors/pucch/factories.cpp +++ b/lib/phy/upper/channel_processors/pucch/factories.cpp @@ -176,7 +176,14 @@ class pucch_demodulator_factory_sw : public pucch_demodulator_factory prg_factory->create(), precoder_factory->create()); - return std::make_unique(std::move(demodulator_format2), std::move(demodulator_format3)); + std::unique_ptr demodulator_format4 = + std::make_unique(equalizer_factory->create(), + demodulation_factory->create_demodulation_mapper(), + prg_factory->create(), + precoder_factory->create()); + + return std::make_unique( + std::move(demodulator_format2), std::move(demodulator_format3), std::move(demodulator_format4)); } pucch_demodulator_factory_sw(std::shared_ptr equalizer_factory_, diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp new file mode 100644 index 0000000000..b951640925 --- /dev/null +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp @@ -0,0 +1,172 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief PUCCH Format 4 demodulator definition. + +#include "pucch_demodulator_format4.h" +#include "srsran/phy/support/mask_types.h" +#include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/upper/equalization/modular_ch_est_list.h" +#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/phy/upper/pucch_orthogonal_sequence.h" + +using namespace srsran; + +void pucch_demodulator_format4::demodulate(span llr, + const resource_grid_reader& grid, + const channel_estimate& estimates, + const pucch_demodulator::format4_configuration& config) +{ + // Number of receive antenna ports. + auto nof_rx_ports = static_cast(config.rx_ports.size()); + + // Number of REs per OFDM symbol. + const unsigned nof_re_symb = NRE; + + // Index of the first symbol allocated to the second subcarrier when intra-slot frequency hopping is enabled. + const unsigned second_hop_start = (config.nof_symbols / 2) + config.start_symbol_index; + + // PUCCH Format 4 modulation scheme can be QPSK or pi/2-BPSK, as per TS38.211 Section 6.3.2.6.2. + modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; + + // Number of data Resource Elements in a slot for a single Rx port. + symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); + + const unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * NRE; + + // Assert that allocations are valid. + srsran_assert(config.first_prb * NRE <= grid.get_nof_subc(), + "PUCCH Format 4: PRB allocation outside grid (first hop). Requested {}, grid has {} PRBs.", + config.first_prb, + grid.get_nof_subc() / NRE); + + srsran_assert(!config.second_hop_prb.has_value() || (config.second_hop_prb.value() * NRE <= grid.get_nof_subc()), + "PUCCH Format 4: PRB allocation outside grid (second hop). Requested {}, grid has {} PRBs.", + config.second_hop_prb.value(), + grid.get_nof_subc() / NRE); + + interval nof_symbols_range(pucch_constants::FORMAT4_MIN_NSYMB, pucch_constants::FORMAT4_MAX_NSYMB); + srsran_assert(nof_symbols_range.contains(config.nof_symbols), + "Invalid Number of OFDM symbols allocated to PUCCH Format 4, i.e., {}. Valid range is {}.", + config.nof_symbols, + nof_symbols_range); + + // Resize equalized data and post equalization noise variance buffers. + eq_re.resize(nof_re_port); + eq_noise_vars.resize(nof_re_port); + + // Extract the Rx port noise variances from the channel estimation. + for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { + noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0); + } + + // Get a view on the equalized RE buffer. + span eq_re_view = eq_re; + span noise_vars_view = eq_noise_vars; + + // Assert that the number of RE returned by the channel equalizer matches the expected number of LLR. + srsran_assert(eq_re.size() / config.occ_length == llr.size() / get_bits_per_symbol(mod_scheme), + "Number of equalized RE (i.e. {}) does not match the expected LLR data length (i.e. {})", + eq_re.size() / config.occ_length, + llr.size() / get_bits_per_symbol(mod_scheme)); + + for (unsigned i_symbol = config.start_symbol_index, i_symbol_end = config.start_symbol_index + config.nof_symbols; + i_symbol != i_symbol_end; + ++i_symbol) { + // Skip DM-RS symbols. + if (dmrs_symb_mask.test(i_symbol - config.start_symbol_index)) { + continue; + } + + // Calculate the lowest resource element containing PUCCH Format 4 within the OFDM symbol. + unsigned first_subc = config.first_prb * NRE; + if ((i_symbol >= second_hop_start) && config.second_hop_prb.has_value()) { + // Intra-slot frequency hopping. + first_subc = config.second_hop_prb.value() * NRE; + } + + // Create modular buffers to hold the spans for this symbol. + modular_re_buffer_reader re_symb(config.rx_ports.size(), nof_re_symb); + modular_ch_est_list estimates_symb(nof_re_symb, config.rx_ports.size(), SINGLE_TX_LAYER); + + for (unsigned i_port = 0, i_port_end = nof_rx_ports; i_port != i_port_end; ++i_port) { + // Extract data RE from the resource grid. + unsigned i_port_grid = config.rx_ports[i_port]; + span re_symb_view = grid.get_view(i_port_grid, i_symbol).subspan(first_subc, nof_re_symb); + re_symb.set_slice(i_port, re_symb_view); + + // Extract estimates from the estimates buffer. + estimates_symb.set_channel( + estimates.get_symbol_ch_estimate(i_symbol, i_port).subspan(first_subc, nof_re_symb), i_port, 0); + } + + // Get a view of the equalized RE buffer for a single symbol. + span eq_re_symb = eq_re_view.first(nof_re_symb); + + // Get a view of the equalized RE buffer for a single symbol. + span eq_noise_vars_symb = noise_vars_view.first(nof_re_symb); + + // Equalize the data RE for a single symbol. + equalizer->equalize(eq_re_symb, + eq_noise_vars_symb, + re_symb, + estimates_symb, + span(noise_var_estimates).first(nof_rx_ports), + 1.0F); + + // Revert transform precoding for a single symbol. + precoder->deprecode_ofdm_symbol(eq_re_symb, eq_re_symb); + + // Advance the equalized RE and noise vars views. + eq_re_view = eq_re_view.subspan(nof_re_symb, eq_re_view.size() - nof_re_symb); + noise_vars_view = noise_vars_view.subspan(nof_re_symb, noise_vars_view.size() - nof_re_symb); + } + + // Create vectors to hold the output of the inverse blockwise spreading. + static_vector original(eq_re.size() / config.occ_length, cf_t()); + static_vector noise_vars(original.size(), 0.0f); + + // Inverse block-wise spreading, as per TS38.211 Section 6.3.2.6.3. + inverse_blockwise_spreading(original, noise_vars, eq_re, eq_noise_vars, config); + + // Apply soft symbol demodulation. + demapper->demodulate_soft(llr, original, noise_vars, mod_scheme); + + // Descramble, as per TS38.211 Section 6.3.2.6.1. + const unsigned c_init = (config.rnti * pow2(15)) + config.n_id; + descrambler->init(c_init); + descrambler->apply_xor(llr, llr); +} + +void pucch_demodulator_format4::inverse_blockwise_spreading(span original, + span noise_vars, + span eq_re, + span eq_noise_vars, + const pucch_demodulator::format4_configuration& config) +{ + const unsigned mod = 12 / config.occ_length; + const span wn = pucch_orthogonal_sequence_format4::get_sequence(config.occ_length, config.occ_index); + + for (unsigned k = 0; k != NRE; k++) { + for (unsigned l = 0, l_end = eq_re.size() / NRE; l != l_end; l++) { + const unsigned original_index = (l * mod) + (k % mod); + const unsigned spread_index = (l * 12) + k; + original[original_index] += eq_re[spread_index] / wn[k]; + noise_vars[original_index] += eq_noise_vars[spread_index]; + } + } + + // Scale according to the spreading factor. + for (cf_t& symbol : original) { + symbol /= config.occ_length; + } +} diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h new file mode 100644 index 0000000000..e7b3a9a4fc --- /dev/null +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h @@ -0,0 +1,89 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief PUCCH Format 4 demodulator declaration. + +#pragma once + +#include "srsran/adt/to_array.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoder.h" +#include "srsran/phy/upper/channel_modulation/demodulation_mapper.h" +#include "srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h" +#include "srsran/phy/upper/equalization/dynamic_ch_est_list.h" +#include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" +#include "srsran/ran/pucch/pucch_constants.h" + +namespace srsran { + +/// PUCCH Format 4 demodulator. +class pucch_demodulator_format4 +{ +public: + /// Constructor: sets up internal components and acquires their ownership. + pucch_demodulator_format4(std::unique_ptr equalizer_, + std::unique_ptr demapper_, + std::unique_ptr descrambler_, + std::unique_ptr precoder_) : + equalizer(std::move(equalizer_)), + demapper(std::move(demapper_)), + descrambler(std::move(descrambler_)), + precoder(std::move(precoder_)) + { + srsran_assert(equalizer, "Invalid pointer to channel_equalizer object."); + srsran_assert(demapper, "Invalid pointer to demodulation_mapper object."); + srsran_assert(descrambler, "Invalid pointer to pseudo_random_generator object."); + srsran_assert(precoder, "Invalid pointer to transform precoder object."); + } + + /// Demodulates a PUCCH Format 4 transmission. See \ref pucch_demodulator for more details. + void demodulate(span llr, + const resource_grid_reader& grid, + const channel_estimate& estimates, + const pucch_demodulator::format4_configuration& config); + +private: + /// PUCCH uses a single TX layer. + static constexpr unsigned SINGLE_TX_LAYER = 1; + + /// Channel equalization component, also in charge of combining contributions of all receive antenna ports. + std::unique_ptr equalizer; + /// Demodulation mapper component: transforms channel symbols into log-likelihood ratios (i.e., soft bits). + std::unique_ptr demapper; + /// Descrambler component. + std::unique_ptr descrambler; + /// Transform precoder component. + std::unique_ptr precoder; + + /// \brief Buffer used to store channel modulation resource elements at the equalizer output. + /// \remark The symbols are arranged in two dimensions, i.e., resource element and transmit layer. + static_vector eq_re; + + /// \brief Buffer used to transfer symbol noise variances at the equalizer output. + /// \remark The symbols are arranged in two dimensions, i.e., resource element and transmit layer. + static_vector eq_noise_vars; + + /// Buffer used to transfer noise variance estimates from the channel estimate to the equalizer. + std::array noise_var_estimates; + + /// \brief Reverts the block-wise spreading applied to PUCCH Format 4, as per TS38.211 Section 6.3.2.6.3. + /// \param[out] original Destination buffer for the original symbols. + /// \param[out] noise_vars Destination buffer for the noise variances. + /// \param[in] eq_re Input buffer for the spread symbols. + /// \param[in] eq_noise_vars Input buffer for the noise variances. + /// \param[in] config PUCCH Format 4 configuration parameters. + static void inverse_blockwise_spreading(span original, + span noise_vars, + span eq_re, + span eq_noise_vars, + const pucch_demodulator::format4_configuration& config); +}; + +} // namespace srsran diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_impl.h b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_impl.h index ad928761cf..66f9cef1cf 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_impl.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_impl.h @@ -15,6 +15,7 @@ #include "pucch_demodulator_format2.h" #include "pucch_demodulator_format3.h" +#include "pucch_demodulator_format4.h" #include "srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h" namespace srsran { @@ -27,11 +28,15 @@ class pucch_demodulator_impl : public pucch_demodulator /// \param[in] demodulator_format2_ PUCCH Format 2 demodulator. /// \param[in] demodulator_format3_ PUCCH Format 3 demodulator. pucch_demodulator_impl(std::unique_ptr demodulator_format2_, - std::unique_ptr demodulator_format3_) : - demodulator_format2(std::move(demodulator_format2_)), demodulator_format3(std::move(demodulator_format3_)) + std::unique_ptr demodulator_format3_, + std::unique_ptr demodulator_format4_) : + demodulator_format2(std::move(demodulator_format2_)), + demodulator_format3(std::move(demodulator_format3_)), + demodulator_format4(std::move(demodulator_format4_)) { srsran_assert(demodulator_format2, "Invalid pointer to pucch_demodulator_format2 object."); srsran_assert(demodulator_format3, "Invalid pointer to pucch_demodulator_format3 object."); + srsran_assert(demodulator_format4, "Invalid pointer to pucch_demodulator_format4 object."); } // See interface for the documentation. @@ -58,7 +63,7 @@ class pucch_demodulator_impl : public pucch_demodulator const channel_estimate& estimates, const format4_configuration& config) override { - srsran_assertion_failure("PUCCH Format 4 not supported."); + demodulator_format4->demodulate(llr, grid, estimates, config); } private: @@ -66,6 +71,8 @@ class pucch_demodulator_impl : public pucch_demodulator std::unique_ptr demodulator_format2; /// PUCCH demodulator Format 3 component. std::unique_ptr demodulator_format3; + /// PUCCH demodulator Format 4 component. + std::unique_ptr demodulator_format4; }; } // namespace srsran diff --git a/lib/phy/upper/channel_processors/pucch/pucch_detector_format1.cpp b/lib/phy/upper/channel_processors/pucch/pucch_detector_format1.cpp index cd4ec552e5..1d2574eaaf 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_detector_format1.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_detector_format1.cpp @@ -19,7 +19,7 @@ using namespace srsran; // Pre-generated orthogonal cover code. -static const pucch_orthogonal_sequence occ; +static const pucch_orthogonal_sequence_format1 occ; static void validate_config(const pucch_detector::format1_configuration& config) { diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp index 26fedd538b..82c5b5e203 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp @@ -9,14 +9,14 @@ */ #include "dmrs_pucch_processor_format1_impl.h" +#include "../../../../../include/srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/phy/upper/pucch_helper.h" -#include "srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/srsvec/sc_prod.h" using namespace srsran; // Pre-generated orthogonal cover code. -static const pucch_orthogonal_sequence occ; +static const pucch_orthogonal_sequence_format1 occ; // DM-RS symbol allocation pattern for PUCCH Format 1, as defined in TS38.211 Section 6.4.1.3.1.2. static const bounded_bitset pucch_format1_dmrs_symb_mask = diff --git a/tests/unittests/phy/upper/channel_processors/pucch/CMakeLists.txt b/tests/unittests/phy/upper/channel_processors/pucch/CMakeLists.txt index c74a2dcb2f..9ee4a88e09 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/CMakeLists.txt +++ b/tests/unittests/phy/upper/channel_processors/pucch/CMakeLists.txt @@ -65,6 +65,19 @@ if (USE_PHY_TESTVECTORS) gtest_main) add_test_vector(pucch_demodulator_format3_test pucch_demodulator_format3_test_data.tar.gz "") + add_executable(pucch_demodulator_format4_test pucch_demodulator_format4_test.cpp) + target_link_libraries(pucch_demodulator_format4_test + srsran_channel_equalizer + srsran_channel_processors + srsran_generic_funcs + srsran_phy_support + srsran_transform_precoding + srsran_upper_phy_support + srslog + gtest + gtest_main) + add_test_vector(pucch_demodulator_format4_test pucch_demodulator_format4_test_data.tar.gz "") + add_executable(pucch_detector_test pucch_detector_test.cpp) target_link_libraries(pucch_detector_test srsran_channel_processors srsran_channel_equalizer srslog gtest gtest_main) add_test_vector(pucch_detector_test pucch_detector_test_data.tar.gz "") diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test.cpp new file mode 100644 index 0000000000..6c5bb7e5e8 --- /dev/null +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test.cpp @@ -0,0 +1,177 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "pucch_demodulator_format4_test_data.h" +#include "srsran/adt/to_array.h" +#include "srsran/phy/support/support_factories.h" +#include "srsran/phy/upper/channel_processors/channel_processor_factories.h" +#include "srsran/phy/upper/channel_processors/pucch/factories.h" +#include "srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h" +#include "srsran/phy/upper/equalization/equalization_factories.h" +#include "srsran/phy/upper/pucch_formats_3_4_helpers.h" +#include "srsran/ran/pucch/pucch_constants.h" +#include "srsran/srsvec/conversion.h" +#include "srsran/support/format/fmt_optional.h" +#include "fmt/ostream.h" +#include + +using namespace srsran; + +using PucchDemodulatorParams = test_case_t; + +namespace srsran { + +// Maximum allowed error. +constexpr log_likelihood_ratio::value_type LLR_MAX_ERROR = 1; + +std::ostream& operator<<(std::ostream& os, test_case_t test_case) +{ + fmt::print(os, + "ports=[{}] first_prb={} second_hop_prb={} start_symbol_index={} nof_symbols={} rnti={} " + "n_id={} additionalDMRS={} pi2_bpsk={} spreading_factor={} occi={}", + span(test_case.context.config.rx_ports), + test_case.context.config.first_prb, + test_case.context.config.second_hop_prb, + test_case.context.config.start_symbol_index, + test_case.context.config.nof_symbols, + test_case.context.config.rnti, + test_case.context.config.n_id, + test_case.context.config.additional_dmrs, + test_case.context.config.pi2_bpsk, + test_case.context.config.occ_length, + test_case.context.config.occ_index); + return os; +} + +std::ostream& operator<<(std::ostream& os, span data) +{ + fmt::print(os, "[{}]", data); + return os; +} + +static bool operator==(span lhs, span rhs) +{ + return std::equal( + lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](log_likelihood_ratio lhs_, log_likelihood_ratio rhs_) { + return log_likelihood_ratio::abs(lhs_ - rhs_) <= LLR_MAX_ERROR; + }); +} + +} // namespace srsran + +class PucchDemodulatorFixture : public ::testing::TestWithParam +{ +protected: + pucch_demodulator::format4_configuration config; + std::vector uci_expected; + channel_estimate channel_est; + resource_grid_reader_spy rg_spy; + + // PUCCH Demodulator. + static std::unique_ptr demodulator; + + PucchDemodulatorFixture() : rg_spy(16, 14, MAX_NOF_PRBS) {} + + static void SetUpTestSuite() + { + if (!demodulator) { + // Create factories required by the PUCCH demodulator factory. + std::shared_ptr equalizer_factory = create_channel_equalizer_generic_factory(); + ASSERT_NE(equalizer_factory, nullptr) << "Cannot create equalizer factory"; + + std::shared_ptr demod_factory = create_channel_modulation_sw_factory(); + ASSERT_NE(demod_factory, nullptr) << "Cannot create channel modulation factory"; + + std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); + ASSERT_NE(prg_factory, nullptr) << "Cannot create pseudo-random generator factory"; + + std::shared_ptr dft_factory = create_dft_processor_factory_fftw_slow(); + ASSERT_NE(dft_factory, nullptr) << "Cannot create DFT processor factory"; + + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_factory, pucch_constants::FORMAT4_MAX_NPRB + 1); + ASSERT_NE(precoding_factory, nullptr) << "Cannot create transform precoder factory"; + + // Create PUCCH demodulator factory. + std::shared_ptr pucch_demod_factory = + create_pucch_demodulator_factory_sw(equalizer_factory, demod_factory, prg_factory, precoding_factory); + ASSERT_NE(pucch_demod_factory, nullptr) << "Cannot create PUCCH demodulator factory."; + + // Create PUCCH demodulator. + demodulator = pucch_demod_factory->create(); + ASSERT_NE(demodulator, nullptr) << "Cannot create PUCCH demodulator."; + } + } + + void SetUp() override + { + const test_case_t& test_case = GetParam(); + + // Assert PUCCH demodulator. + ASSERT_NE(demodulator, nullptr) << "Cannot create PUCCH demodulator."; + + // Prepare PUCCH demodulator configuration. + config = test_case.context.config; + + // Prepare expected UCI codeword. + uci_expected = test_case.uci_codeword.read(); + + // Determine resource grid dimensions. + unsigned nof_prb = test_case.context.grid_nof_prb; + unsigned nof_symbols = test_case.context.grid_nof_symbols; + unsigned nof_rx_ports = config.rx_ports.size(); + + // Prepare the resource grid. + symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( + config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); + unsigned nof_test_symbols = + test_case.context.config.rx_ports.size() * (config.nof_symbols - dmrs_symb_mask.count()) * NRE; + + std::vector grid_entries = test_case.symbols.read(); + ASSERT_EQ(grid_entries.size(), nof_test_symbols) + << "The number of grid entries and the number of PUCCH REs do not match"; + + rg_spy.write(grid_entries); + + // Prepare channel estimates. + channel_estimate::channel_estimate_dimensions ce_dims; + ce_dims.nof_prb = nof_prb; + ce_dims.nof_symbols = nof_symbols; + ce_dims.nof_rx_ports = nof_rx_ports; + ce_dims.nof_tx_layers = 1; + + channel_est.resize(ce_dims); + + // Set estimated channel. + std::vector estimates = test_case.estimates.read(); + srsvec::convert(channel_est.get_path_ch_estimate(0, 0), estimates); + + // Set noise variance. + channel_est.set_noise_variance(test_case.context.noise_var, 0); + } +}; + +std::unique_ptr PucchDemodulatorFixture::demodulator = nullptr; + +TEST_P(PucchDemodulatorFixture, PucchDemodulatorVectorTest) +{ + std::vector uci_data(uci_expected.size()); + + // Perform demodulation. + demodulator->demodulate(uci_data, rg_spy, channel_est, config); + + // Assert UCI codeword matches. + ASSERT_EQ(span(uci_expected), span(uci_data)); +} + +// Creates test suite that combines all possible parameters. +INSTANTIATE_TEST_SUITE_P(PucchDemodulatorVectorTest, + PucchDemodulatorFixture, + ::testing::ValuesIn(pucch_demodulator_format4_test_data)); diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h new file mode 100644 index 0000000000..39928ed6af --- /dev/null +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h @@ -0,0 +1,105 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +// This file was generated using the following MATLAB class on 04-11-2024 (seed 0): +// + "srsPUCCHDemodulatorFormat4Unittest.m" + +#include "../../../support/resource_grid_test_doubles.h" +#include "srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h" +#include "srsran/support/file_vector.h" + +namespace srsran { + +struct context_t { + unsigned grid_nof_prb; + unsigned grid_nof_symbols; + float noise_var; + pucch_demodulator::format4_configuration config; +}; + +struct test_case_t { + context_t context; + file_vector symbols; + file_vector estimates; + file_vector uci_codeword; +}; + +static const std::vector pucch_demodulator_format4_test_data = { + // clang-format off + {{266, 14, 0.81, {{0}, 251, {}, 0, 14, 8323, 927, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols0.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates0.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits0.dat"}}, + {{170, 14, 0.16, {{0}, 149, {}, 0, 14, 17800, 19, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols2.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates2.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits2.dat"}}, + {{151, 14, 0.01, {{0}, 132, {}, 0, 14, 6522, 814, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols4.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates4.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits4.dat"}}, + {{234, 14, 0.81, {{0}, 222, {}, 0, 14, 58321, 723, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols6.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates6.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits6.dat"}}, + {{273, 14, 0.09, {{0}, 259, {}, 0, 14, 65108, 82, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols8.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates8.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits8.dat"}}, + {{181, 14, 0.49, {{0}, 125, {}, 0, 14, 41366, 444, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols10.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates10.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits10.dat"}}, + {{233, 14, 0.64, {{0}, 69, {}, 0, 14, 64311, 341, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols12.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates12.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits12.dat"}}, + {{175, 14, 0.25, {{0}, 172, {}, 0, 14, 32009, 961, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols14.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates14.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits14.dat"}}, + {{263, 14, 0.64, {{0}, 254, 256, 0, 14, 41682, 101, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols16.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates16.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits16.dat"}}, + {{56, 14, 0.04, {{0}, 38, 51, 0, 14, 63908, 759, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols18.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates18.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits18.dat"}}, + {{163, 14, 0.04, {{0}, 105, 123, 0, 14, 34348, 992, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols20.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates20.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits20.dat"}}, + {{156, 14, 0.25, {{0}, 133, 148, 0, 14, 22469, 270, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols22.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates22.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits22.dat"}}, + {{175, 14, 0.09, {{0}, 93, 168, 0, 14, 55710, 275, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols24.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates24.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits24.dat"}}, + {{274, 14, 0.64, {{0}, 204, 240, 0, 14, 57200, 668, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols26.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates26.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits26.dat"}}, + {{143, 14, 0.16, {{0}, 104, 117, 0, 14, 58967, 519, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols28.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates28.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits28.dat"}}, + {{173, 14, 0.36, {{0}, 170, 162, 0, 14, 28669, 108, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols30.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates30.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits30.dat"}}, + {{243, 14, 0.36, {{0}, 88, {}, 1, 13, 30084, 983, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols32.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates32.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits32.dat"}}, + {{272, 14, 0.01, {{0}, 260, {}, 1, 13, 18233, 614, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols34.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates34.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits34.dat"}}, + {{23, 14, 0.04, {{0}, 12, {}, 1, 13, 11524, 987, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols36.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates36.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits36.dat"}}, + {{197, 14, 0.16, {{0}, 155, {}, 1, 13, 54686, 956, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols38.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates38.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits38.dat"}}, + {{244, 14, 0.04, {{0}, 242, {}, 1, 13, 39561, 352, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols40.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates40.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits40.dat"}}, + {{143, 14, 0.16, {{0}, 78, {}, 1, 13, 32422, 648, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols42.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates42.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits42.dat"}}, + {{271, 14, 0.49, {{0}, 269, {}, 1, 13, 9465, 594, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols44.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates44.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits44.dat"}}, + {{242, 14, 0.25, {{0}, 197, {}, 1, 13, 21870, 929, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols46.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates46.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits46.dat"}}, + {{234, 14, 0.16, {{0}, 160, 214, 1, 13, 2515, 22, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols48.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates48.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits48.dat"}}, + {{228, 14, 0.81, {{0}, 208, 216, 1, 13, 53298, 545, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols50.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates50.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits50.dat"}}, + {{145, 14, 0.04, {{0}, 141, 140, 1, 13, 45241, 1016, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols52.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates52.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits52.dat"}}, + {{268, 14, 0.09, {{0}, 263, 267, 1, 13, 47309, 662, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols54.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates54.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits54.dat"}}, + {{182, 14, 1, {{0}, 166, 131, 1, 13, 36950, 335, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols56.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates56.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits56.dat"}}, + {{224, 14, 0.09, {{0}, 123, 60, 1, 13, 19208, 713, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols58.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates58.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits58.dat"}}, + {{158, 14, 1, {{0}, 101, 95, 1, 13, 6522, 71, false, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols60.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates60.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits60.dat"}}, + {{213, 14, 0.81, {{0}, 196, 208, 1, 13, 33084, 318, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols62.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates62.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits62.dat"}}, + {{133, 14, 0.25, {{0}, 128, {}, 5, 5, 36679, 771, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols64.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates64.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits64.dat"}}, + {{202, 14, 0.49, {{0}, 199, {}, 5, 5, 40171, 77, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols66.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates66.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits66.dat"}}, + {{249, 14, 0.81, {{0}, 244, {}, 5, 5, 36556, 305, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols68.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates68.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits68.dat"}}, + {{213, 14, 0.81, {{0}, 133, {}, 5, 5, 15363, 373, true, true, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols70.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates70.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits70.dat"}}, + {{233, 14, 0.09, {{0}, 163, {}, 5, 5, 64895, 711, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols72.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates72.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits72.dat"}}, + {{234, 14, 1, {{0}, 199, {}, 5, 5, 22665, 919, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols74.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates74.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits74.dat"}}, + {{256, 14, 0.16, {{0}, 201, {}, 5, 5, 47693, 996, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols76.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates76.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits76.dat"}}, + {{91, 14, 1, {{0}, 37, {}, 5, 5, 56802, 799, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols78.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates78.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits78.dat"}}, + {{130, 14, 0.04, {{0}, 71, 82, 5, 5, 54938, 399, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols80.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates80.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits80.dat"}}, + {{252, 14, 0.16, {{0}, 200, 209, 5, 5, 20453, 722, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols82.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates82.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits82.dat"}}, + {{153, 14, 0.49, {{0}, 121, 118, 5, 5, 1198, 389, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols84.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates84.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits84.dat"}}, + {{251, 14, 0.49, {{0}, 218, 114, 5, 5, 46355, 329, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols86.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates86.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits86.dat"}}, + {{154, 14, 0.64, {{0}, 153, 148, 5, 5, 7574, 990, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols88.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates88.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits88.dat"}}, + {{207, 14, 0.04, {{0}, 206, 202, 5, 5, 259, 82, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols90.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates90.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits90.dat"}}, + {{202, 14, 0.36, {{0}, 170, 183, 5, 5, 22927, 430, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols92.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates92.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits92.dat"}}, + {{131, 14, 0.36, {{0}, 120, 130, 5, 5, 62760, 373, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols94.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates94.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits94.dat"}}, + {{64, 14, 0.04, {{0}, 49, {}, 10, 4, 1421, 152, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols96.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates96.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits96.dat"}}, + {{168, 14, 0.36, {{0}, 138, {}, 10, 4, 34828, 303, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols98.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates98.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits98.dat"}}, + {{267, 14, 0.09, {{0}, 240, {}, 10, 4, 33192, 647, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols100.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates100.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits100.dat"}}, + {{274, 14, 0.09, {{0}, 240, {}, 10, 4, 37965, 730, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols102.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates102.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits102.dat"}}, + {{237, 14, 0.36, {{0}, 231, {}, 10, 4, 62814, 1015, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols104.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates104.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits104.dat"}}, + {{126, 14, 0.16, {{0}, 99, {}, 10, 4, 19802, 285, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols106.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates106.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits106.dat"}}, + {{239, 14, 0.25, {{0}, 237, {}, 10, 4, 10629, 895, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols108.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates108.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits108.dat"}}, + {{187, 14, 0.49, {{0}, 123, {}, 10, 4, 34631, 791, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols110.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates110.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits110.dat"}}, + {{198, 14, 0.04, {{0}, 160, 170, 10, 4, 57520, 488, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols112.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates112.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits112.dat"}}, + {{205, 14, 0.81, {{0}, 149, 169, 10, 4, 12721, 295, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols114.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates114.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits114.dat"}}, + {{171, 14, 0.64, {{0}, 123, 135, 10, 4, 22780, 668, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols116.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates116.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits116.dat"}}, + {{131, 14, 0.81, {{0}, 126, 128, 10, 4, 51378, 645, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols118.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates118.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits118.dat"}}, + {{43, 14, 0.36, {{0}, 21, 26, 10, 4, 22335, 1012, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols120.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates120.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits120.dat"}}, + {{243, 14, 0.01, {{0}, 242, 237, 10, 4, 48633, 17, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols122.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates122.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits122.dat"}}, + {{246, 14, 0.25, {{0}, 208, 154, 10, 4, 60173, 295, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols124.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates124.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits124.dat"}}, + {{213, 14, 0.04, {{0}, 131, 111, 10, 4, 58214, 792, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols126.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates126.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits126.dat"}}, + // clang-format on +}; + +} // namespace srsran diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz new file mode 100644 index 0000000000..5b9e42d85b --- /dev/null +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c15d956679c5eaf78cd9530c5d8350bef1d4b15b5ed1949d129d341e07ee4751 +size 14998095 From 04cbf5286bdf20f205d3a335becb363653dc5e72 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 5 Nov 2024 12:09:15 +0100 Subject: [PATCH 26/72] phy: extract common logic in pucch demodulators 3 and 4 to helper --- .../phy/upper/pucch_formats_3_4_helpers.h | 104 ++++++++++++++++++ .../pucch/pucch_demodulator_format2.cpp | 2 +- .../pucch/pucch_demodulator_format2.h | 3 - .../pucch/pucch_demodulator_format3.cpp | 83 +++----------- .../pucch/pucch_demodulator_format3.h | 6 - .../pucch/pucch_demodulator_format4.cpp | 83 +++----------- .../pucch/pucch_demodulator_format4.h | 6 - 7 files changed, 131 insertions(+), 156 deletions(-) diff --git a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h index a76dde922a..26a8922c18 100644 --- a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h +++ b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h @@ -15,6 +15,7 @@ #include "srsran/adt/bounded_integer.h" #include "srsran/phy/support/mask_types.h" +#include "srsran/phy/upper/equalization/modular_ch_est_list.h" #include "srsran/ran/pucch/pucch_constants.h" namespace srsran { @@ -119,4 +120,107 @@ inline symbol_slot_mask get_pucch_formats_3_4_dmrs_symbol_mask( return mask; } +/// \brief Gets REs and channel estimates given a PUCCH Format 3/4 resource, performs equalization and transform +/// deprecoding. +/// +/// Extracts and loads the inner buffers with the PUCCH control data RE from the provided \c resource_grid, and their +/// corresponding channel estimates from \c channel_ests. The DM-RS RE are skipped. Equalization and transform +/// deprecoding is done symbol by symbol. +/// +/// \param[out] eq_re Destination buffer for resource elements at the equalizer output. +/// \param[out] eq_noise_vars Destination buffer for noise variances at the equalizer output. +/// \param[out] equalizer Channel equalizer. +/// \param[out] precoder Transform precoder. +/// \param[in] grid Input resource grid. +/// \param[in] estimates Channel estimates. +/// \param[in] dmrs_symb_mask The symbol mask for symbols containing DM-RS for the PUCCH configuration. +/// \param[in] start_symbol_index Start symbol index within the slot {0, ..., 13}. +/// \param[in] nof_symbols Number of symbols assigned to PUCCH resource. +/// \param[in] nof_prb Number of PRB assigned to PUCCH resource. +/// \param[in] first_prb Lowest PRB index used for the PUCCH transmission within the resource grid. +/// \param[in] second_hop_prb Lowest PRB index used for the PUCCH transmission within the BWP {0, ..., 274} +/// if intra-slot frequency hopping is enabled, empty otherwise. +/// \param[in] rx_ports Port indexes used for the PUCCH reception. +inline void pucch_3_4_extract_and_equalize(span eq_re, + span eq_noise_vars, + channel_equalizer& equalizer, + transform_precoder& precoder, + const resource_grid_reader& grid, + const channel_estimate& estimates, + const symbol_slot_mask& dmrs_symb_mask, + const unsigned start_symbol_index, + const unsigned nof_symbols, + const unsigned nof_prb, + const unsigned first_prb, + const std::optional second_hop_prb, + span rx_ports) +{ + // Number of receive antenna ports. + auto nof_rx_ports = static_cast(rx_ports.size()); + + // Number of REs per OFDM symbol. + const unsigned nof_re_symb = nof_prb * NRE; + + // Index of the first symbol allocated to the second subcarrier when intra-slot frequency hopping is enabled. + const unsigned second_hop_start = (nof_symbols / 2) + start_symbol_index; + + // Extract the Rx port noise variances from the channel estimation. + std::array noise_var_estimates; + for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { + noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0); + } + + for (unsigned i_symbol = start_symbol_index, i_symbol_end = start_symbol_index + nof_symbols; + i_symbol != i_symbol_end; + ++i_symbol) { + // Skip DM-RS symbols. + if (dmrs_symb_mask.test(i_symbol - start_symbol_index)) { + continue; + } + + // Calculate the lowest resource element containing PUCCH Format 3 within the OFDM symbol. + unsigned first_subc = first_prb * NRE; + if ((i_symbol >= second_hop_start) && second_hop_prb.has_value()) { + // Intra-slot frequency hopping. + first_subc = second_hop_prb.value() * NRE; + } + + // Create modular buffers to hold the spans for this symbol. + modular_re_buffer_reader re_symb(nof_rx_ports, nof_re_symb); + modular_ch_est_list estimates_symb(nof_re_symb, nof_rx_ports, pucch_constants::MAX_LAYERS); + + for (unsigned i_port = 0, i_port_end = nof_rx_ports; i_port != i_port_end; ++i_port) { + // Extract data RE from the resource grid. + unsigned i_port_grid = rx_ports[i_port]; + span re_symb_view = grid.get_view(i_port_grid, i_symbol).subspan(first_subc, nof_re_symb); + re_symb.set_slice(i_port, re_symb_view); + + // Extract estimates from the estimates buffer. + estimates_symb.set_channel( + estimates.get_symbol_ch_estimate(i_symbol, i_port).subspan(first_subc, nof_re_symb), i_port, 0); + } + + // Get a view of the equalized RE buffer for a single symbol. + span eq_re_symb = eq_re.first(nof_re_symb); + + // Get a view of the equalized RE buffer for a single symbol. + span eq_noise_vars_symb = eq_noise_vars.first(nof_re_symb); + + // Equalize the data RE for a single symbol. + equalizer.equalize(eq_re_symb, + eq_noise_vars_symb, + re_symb, + estimates_symb, + span(noise_var_estimates).first(nof_rx_ports), + 1.0F); + + // Revert transform precoding for a single symbol. + precoder.deprecode_ofdm_symbol(eq_re_symb, eq_re_symb); + + // Advance the equalized RE and noise vars views. + eq_re = eq_re.subspan(nof_re_symb, eq_re.size() - nof_re_symb); + eq_noise_vars = eq_noise_vars.subspan(nof_re_symb, eq_noise_vars.size() - nof_re_symb); + } +} + } // namespace srsran diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.cpp index 04895d9736..4a8213206b 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.cpp @@ -60,7 +60,7 @@ void pucch_demodulator_format2::demodulate(span // Resize data and channel estimation buffers. ch_re.resize(nof_rx_ports, nof_re_port); - ch_estimates.resize(nof_re_port, nof_rx_ports, SINGLE_TX_LAYER); + ch_estimates.resize(nof_re_port, nof_rx_ports, pucch_constants::MAX_LAYERS); // Resize equalized data and post equalization noise variance buffers. eq_re.resize(nof_re_port); diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.h b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.h index 4bb33f74e1..99c7e1251b 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format2.h @@ -47,9 +47,6 @@ class pucch_demodulator_format2 const pucch_demodulator::format2_configuration& config); private: - /// PUCCH uses a single TX layer. - static constexpr unsigned SINGLE_TX_LAYER = 1; - /// \brief Gets PUCCH Resource Elements and channel estimation coefficients given a PUCCH Format 2 allocation. /// /// Extracts and loads the inner buffers with the PUCCH control data RE from the provided \c resource_grid, and their diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp index e0e0a3abe6..386948598d 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp @@ -14,7 +14,6 @@ #include "pucch_demodulator_format3.h" #include "srsran/phy/support/mask_types.h" #include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/phy/upper/equalization/modular_ch_est_list.h" #include "srsran/phy/upper/pucch_formats_3_4_helpers.h" using namespace srsran; @@ -24,15 +23,6 @@ void pucch_demodulator_format3::demodulate(span const channel_estimate& estimates, const pucch_demodulator::format3_configuration& config) { - // Number of receive antenna ports. - auto nof_rx_ports = static_cast(config.rx_ports.size()); - - // Number of REs per OFDM symbol. - const unsigned nof_re_symb = config.nof_prb * NRE; - - // Index of the first symbol allocated to the second subcarrier when intra-slot frequency hopping is enabled. - const unsigned second_hop_start = (config.nof_symbols / 2) + config.start_symbol_index; - // PUCCH Format 3 modulation scheme can be QPSK or pi/2-BPSK, as per TS38.211 Section 6.3.2.6.2. modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; @@ -71,72 +61,25 @@ void pucch_demodulator_format3::demodulate(span eq_re.resize(nof_re_port); eq_noise_vars.resize(nof_re_port); - // Extract the Rx port noise variances from the channel estimation. - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { - noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0); - } - - // Get a view on the equalized RE buffer. - span eq_re_view = eq_re; - span noise_vars_view = eq_noise_vars; - // Assert that the number of RE returned by the channel equalizer matches the expected number of LLR. srsran_assert(eq_re.size() == llr.size() / get_bits_per_symbol(mod_scheme), "Number of equalized RE (i.e. {}) does not match the expected LLR data length (i.e. {})", eq_re.size(), llr.size() / get_bits_per_symbol(mod_scheme)); - for (unsigned i_symbol = config.start_symbol_index, i_symbol_end = config.start_symbol_index + config.nof_symbols; - i_symbol != i_symbol_end; - ++i_symbol) { - // Skip DM-RS symbols. - if (dmrs_symb_mask.test(i_symbol - config.start_symbol_index)) { - continue; - } - - // Calculate the lowest resource element containing PUCCH Format 3 within the OFDM symbol. - unsigned first_subc = config.first_prb * NRE; - if ((i_symbol >= second_hop_start) && config.second_hop_prb.has_value()) { - // Intra-slot frequency hopping. - first_subc = config.second_hop_prb.value() * NRE; - } - - // Create modular buffers to hold the spans for this symbol. - modular_re_buffer_reader re_symb(config.rx_ports.size(), nof_re_symb); - modular_ch_est_list estimates_symb(nof_re_symb, config.rx_ports.size(), SINGLE_TX_LAYER); - - for (unsigned i_port = 0, i_port_end = nof_rx_ports; i_port != i_port_end; ++i_port) { - // Extract data RE from the resource grid. - unsigned i_port_grid = config.rx_ports[i_port]; - span re_symb_view = grid.get_view(i_port_grid, i_symbol).subspan(first_subc, nof_re_symb); - re_symb.set_slice(i_port, re_symb_view); - - // Extract estimates from the estimates buffer. - estimates_symb.set_channel( - estimates.get_symbol_ch_estimate(i_symbol, i_port).subspan(first_subc, nof_re_symb), i_port, 0); - } - - // Get a view of the equalized RE buffer for a single symbol. - span eq_re_symb = eq_re_view.first(nof_re_symb); - - // Get a view of the equalized RE buffer for a single symbol. - span eq_noise_vars_symb = noise_vars_view.first(nof_re_symb); - - // Equalize the data RE for a single symbol. - equalizer->equalize(eq_re_symb, - eq_noise_vars_symb, - re_symb, - estimates_symb, - span(noise_var_estimates).first(nof_rx_ports), - 1.0F); - - // Revert transform precoding for a single symbol. - precoder->deprecode_ofdm_symbol(eq_re_symb, eq_re_symb); - - // Advance the equalized RE and noise vars views. - eq_re_view = eq_re_view.subspan(nof_re_symb, eq_re_view.size() - nof_re_symb); - noise_vars_view = noise_vars_view.subspan(nof_re_symb, noise_vars_view.size() - nof_re_symb); - } + pucch_3_4_extract_and_equalize(eq_re, + eq_noise_vars, + *equalizer, + *precoder, + grid, + estimates, + dmrs_symb_mask, + config.start_symbol_index, + config.nof_symbols, + config.nof_prb, + config.first_prb, + config.second_hop_prb, + config.rx_ports); // Apply soft symbol demodulation. demapper->demodulate_soft(llr, eq_re, eq_noise_vars, mod_scheme); diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.h b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.h index 7a74990576..a1710901d9 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.h @@ -50,9 +50,6 @@ class pucch_demodulator_format3 const pucch_demodulator::format3_configuration& config); private: - /// PUCCH uses a single TX layer. - static constexpr unsigned SINGLE_TX_LAYER = 1; - /// Channel equalization component, also in charge of combining contributions of all receive antenna ports. std::unique_ptr equalizer; /// Demodulation mapper component: transforms channel symbols into log-likelihood ratios (i.e., soft bits). @@ -69,9 +66,6 @@ class pucch_demodulator_format3 /// \brief Buffer used to transfer symbol noise variances at the equalizer output. /// \remark The symbols are arranged in two dimensions, i.e., resource element and transmit layer. static_vector eq_noise_vars; - - /// Buffer used to transfer noise variance estimates from the channel estimate to the equalizer. - std::array noise_var_estimates; }; } // namespace srsran diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp index b951640925..b1727cbe99 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp @@ -14,7 +14,6 @@ #include "pucch_demodulator_format4.h" #include "srsran/phy/support/mask_types.h" #include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/phy/upper/equalization/modular_ch_est_list.h" #include "srsran/phy/upper/pucch_formats_3_4_helpers.h" #include "srsran/phy/upper/pucch_orthogonal_sequence.h" @@ -25,15 +24,6 @@ void pucch_demodulator_format4::demodulate(span const channel_estimate& estimates, const pucch_demodulator::format4_configuration& config) { - // Number of receive antenna ports. - auto nof_rx_ports = static_cast(config.rx_ports.size()); - - // Number of REs per OFDM symbol. - const unsigned nof_re_symb = NRE; - - // Index of the first symbol allocated to the second subcarrier when intra-slot frequency hopping is enabled. - const unsigned second_hop_start = (config.nof_symbols / 2) + config.start_symbol_index; - // PUCCH Format 4 modulation scheme can be QPSK or pi/2-BPSK, as per TS38.211 Section 6.3.2.6.2. modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; @@ -64,72 +54,25 @@ void pucch_demodulator_format4::demodulate(span eq_re.resize(nof_re_port); eq_noise_vars.resize(nof_re_port); - // Extract the Rx port noise variances from the channel estimation. - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { - noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0); - } - - // Get a view on the equalized RE buffer. - span eq_re_view = eq_re; - span noise_vars_view = eq_noise_vars; - // Assert that the number of RE returned by the channel equalizer matches the expected number of LLR. srsran_assert(eq_re.size() / config.occ_length == llr.size() / get_bits_per_symbol(mod_scheme), "Number of equalized RE (i.e. {}) does not match the expected LLR data length (i.e. {})", eq_re.size() / config.occ_length, llr.size() / get_bits_per_symbol(mod_scheme)); - for (unsigned i_symbol = config.start_symbol_index, i_symbol_end = config.start_symbol_index + config.nof_symbols; - i_symbol != i_symbol_end; - ++i_symbol) { - // Skip DM-RS symbols. - if (dmrs_symb_mask.test(i_symbol - config.start_symbol_index)) { - continue; - } - - // Calculate the lowest resource element containing PUCCH Format 4 within the OFDM symbol. - unsigned first_subc = config.first_prb * NRE; - if ((i_symbol >= second_hop_start) && config.second_hop_prb.has_value()) { - // Intra-slot frequency hopping. - first_subc = config.second_hop_prb.value() * NRE; - } - - // Create modular buffers to hold the spans for this symbol. - modular_re_buffer_reader re_symb(config.rx_ports.size(), nof_re_symb); - modular_ch_est_list estimates_symb(nof_re_symb, config.rx_ports.size(), SINGLE_TX_LAYER); - - for (unsigned i_port = 0, i_port_end = nof_rx_ports; i_port != i_port_end; ++i_port) { - // Extract data RE from the resource grid. - unsigned i_port_grid = config.rx_ports[i_port]; - span re_symb_view = grid.get_view(i_port_grid, i_symbol).subspan(first_subc, nof_re_symb); - re_symb.set_slice(i_port, re_symb_view); - - // Extract estimates from the estimates buffer. - estimates_symb.set_channel( - estimates.get_symbol_ch_estimate(i_symbol, i_port).subspan(first_subc, nof_re_symb), i_port, 0); - } - - // Get a view of the equalized RE buffer for a single symbol. - span eq_re_symb = eq_re_view.first(nof_re_symb); - - // Get a view of the equalized RE buffer for a single symbol. - span eq_noise_vars_symb = noise_vars_view.first(nof_re_symb); - - // Equalize the data RE for a single symbol. - equalizer->equalize(eq_re_symb, - eq_noise_vars_symb, - re_symb, - estimates_symb, - span(noise_var_estimates).first(nof_rx_ports), - 1.0F); - - // Revert transform precoding for a single symbol. - precoder->deprecode_ofdm_symbol(eq_re_symb, eq_re_symb); - - // Advance the equalized RE and noise vars views. - eq_re_view = eq_re_view.subspan(nof_re_symb, eq_re_view.size() - nof_re_symb); - noise_vars_view = noise_vars_view.subspan(nof_re_symb, noise_vars_view.size() - nof_re_symb); - } + pucch_3_4_extract_and_equalize(eq_re, + eq_noise_vars, + *equalizer, + *precoder, + grid, + estimates, + dmrs_symb_mask, + config.start_symbol_index, + config.nof_symbols, + 1, + config.first_prb, + config.second_hop_prb, + config.rx_ports); // Create vectors to hold the output of the inverse blockwise spreading. static_vector original(eq_re.size() / config.occ_length, cf_t()); diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h index e7b3a9a4fc..701feb8a0b 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h @@ -50,9 +50,6 @@ class pucch_demodulator_format4 const pucch_demodulator::format4_configuration& config); private: - /// PUCCH uses a single TX layer. - static constexpr unsigned SINGLE_TX_LAYER = 1; - /// Channel equalization component, also in charge of combining contributions of all receive antenna ports. std::unique_ptr equalizer; /// Demodulation mapper component: transforms channel symbols into log-likelihood ratios (i.e., soft bits). @@ -70,9 +67,6 @@ class pucch_demodulator_format4 /// \remark The symbols are arranged in two dimensions, i.e., resource element and transmit layer. static_vector eq_noise_vars; - /// Buffer used to transfer noise variance estimates from the channel estimate to the equalizer. - std::array noise_var_estimates; - /// \brief Reverts the block-wise spreading applied to PUCCH Format 4, as per TS38.211 Section 6.3.2.6.3. /// \param[out] original Destination buffer for the original symbols. /// \param[out] noise_vars Destination buffer for the noise variances. From b457f3d9965516d7a62b3a3b8296589081d6be9a Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 5 Nov 2024 16:49:43 +0100 Subject: [PATCH 27/72] phy: review pucch demodulator format 4 --- .../pucch/pucch_demodulator.h | 10 +- .../phy/upper/pucch_formats_3_4_helpers.h | 8 +- .../phy/upper/pucch_orthogonal_sequence.h | 112 +++++++-------- include/srsran/ran/pucch/pucch_constants.h | 2 +- .../pucch/pucch_demodulator_format3.cpp | 8 +- .../pucch/pucch_demodulator_format4.cpp | 21 +-- .../pucch/pucch_demodulator_format4.h | 8 +- .../pucch_demodulator_format4_test_data.h | 130 +++++++++--------- ...pucch_demodulator_format4_test_data.tar.gz | 4 +- 9 files changed, 157 insertions(+), 146 deletions(-) diff --git a/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h b/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h index 14a3cf75a1..3e38736758 100644 --- a/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h +++ b/include/srsran/phy/upper/channel_processors/pucch/pucch_demodulator.h @@ -23,7 +23,7 @@ class pucch_demodulator public: /// Collects PUCCH Format 2 demodulation parameters. struct format2_configuration { - /// Port indexes used for the PUCCH reception. + /// Port indices used for the PUCCH reception. static_vector rx_ports; /// Lowest PRB index used for the PUCCH transmission within the resource grid {0, ..., 274}. unsigned first_prb; @@ -46,7 +46,7 @@ class pucch_demodulator /// Collects PUCCH Format 3 demodulation parameters. struct format3_configuration { - /// Port indexes used for the PUCCH reception. + /// Port indices used for the PUCCH reception. static_vector rx_ports; /// Lowest PRB index used for the PUCCH transmission within the resource grid {0, ..., 274}. unsigned first_prb; @@ -59,7 +59,7 @@ class pucch_demodulator unsigned nof_prb; /// Start symbol index within the slot {0, ..., 13}. unsigned start_symbol_index; - /// Number of symbols for the PUCCH transmission {4, ... , 14}. + /// Number of symbols for the PUCCH transmission {4, ..., 14}. unsigned nof_symbols; /// Radio Network Temporary Identifier, see parameter \f$n_{RNTI}\f$ in TS38.211 Section 6.3.2.5.1. uint16_t rnti; @@ -75,7 +75,7 @@ class pucch_demodulator /// Collects PUCCH Format 4 demodulation parameters. struct format4_configuration { - /// Port indexes used for the PUCCH reception. + /// Port indices used for the PUCCH reception. static_vector rx_ports; /// Lowest PRB index used for the PUCCH transmission within the resource grid {0, ..., 274}. unsigned first_prb; @@ -86,7 +86,7 @@ class pucch_demodulator std::optional second_hop_prb; /// Start symbol index within the slot {0, ..., 13}. unsigned start_symbol_index; - /// Number of symbols for the PUCCH transmission {4, ... , 14}. + /// Number of symbols for the PUCCH transmission {4, ..., 14}. unsigned nof_symbols; /// Radio Network Temporary Identifier, see parameter \f$n_{RNTI}\f$ in TS38.211 Section 6.3.2.5.1. uint16_t rnti; diff --git a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h index 26a8922c18..07e02225e0 100644 --- a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h +++ b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h @@ -161,7 +161,7 @@ inline void pucch_3_4_extract_and_equalize(span eq_re, // Number of REs per OFDM symbol. const unsigned nof_re_symb = nof_prb * NRE; - // Index of the first symbol allocated to the second subcarrier when intra-slot frequency hopping is enabled. + // Index of the first symbol allocated to the second hop, when intra-slot frequency hopping is enabled. const unsigned second_hop_start = (nof_symbols / 2) + start_symbol_index; // Extract the Rx port noise variances from the channel estimation. @@ -180,7 +180,7 @@ inline void pucch_3_4_extract_and_equalize(span eq_re, // Calculate the lowest resource element containing PUCCH Format 3 within the OFDM symbol. unsigned first_subc = first_prb * NRE; - if ((i_symbol >= second_hop_start) && second_hop_prb.has_value()) { + if (second_hop_prb.has_value() && (i_symbol >= second_hop_start)) { // Intra-slot frequency hopping. first_subc = second_hop_prb.value() * NRE; } @@ -218,8 +218,8 @@ inline void pucch_3_4_extract_and_equalize(span eq_re, precoder.deprecode_ofdm_symbol(eq_re_symb, eq_re_symb); // Advance the equalized RE and noise vars views. - eq_re = eq_re.subspan(nof_re_symb, eq_re.size() - nof_re_symb); - eq_noise_vars = eq_noise_vars.subspan(nof_re_symb, eq_noise_vars.size() - nof_re_symb); + eq_re = eq_re.last(eq_re.size() - nof_re_symb); + eq_noise_vars = eq_noise_vars.last(eq_noise_vars.size() - nof_re_symb); } } diff --git a/include/srsran/phy/upper/pucch_orthogonal_sequence.h b/include/srsran/phy/upper/pucch_orthogonal_sequence.h index 329ca52bc5..022f84e0a5 100644 --- a/include/srsran/phy/upper/pucch_orthogonal_sequence.h +++ b/include/srsran/phy/upper/pucch_orthogonal_sequence.h @@ -25,44 +25,6 @@ namespace srsran { /// Generator of orthogonal sequences \e w for PUCCH Format 1. class pucch_orthogonal_sequence_format1 { -private: - /// Alias for sequence table type. - using w_array = - std::array, pucch_constants::FORMAT1_N_MAX>, - pucch_constants::FORMAT1_N_MAX>; - - /// \brief Coefficients \f$\phi(m)\f$ for sequence generation. - /// - /// See TS38.211 Table 6.3.2.4.1-2: Orthogonal sequences for PUCCH Format 1. - static constexpr std::array< - std::array, pucch_constants::FORMAT1_N_MAX>, - pucch_constants::FORMAT1_N_MAX> - pucch_format1_phi = { - {{{{0}, {}, {}, {}, {}, {}, {}}}, - {{{0, 0}, {0, 1}, {}, {}, {}, {}, {}}}, - {{{0, 0, 0}, {0, 1, 2}, {0, 2, 1}, {}, {}, {}, {}}}, - {{{0, 0, 0, 0}, {0, 2, 0, 2}, {0, 0, 2, 2}, {0, 2, 2, 0}, {}, {}, {}}}, - {{{0, 0, 0, 0, 0}, {0, 1, 2, 3, 4}, {0, 2, 4, 1, 3}, {0, 3, 1, 4, 2}, {0, 4, 3, 2, 1}, {}, {}}}, - {{{0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5}, - {0, 2, 4, 0, 2, 4}, - {0, 3, 0, 3, 0, 3}, - {0, 4, 2, 0, 4, 2}, - {0, 5, 4, 3, 2, 1}, - {}}}, - {{{0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6}, - {0, 2, 4, 6, 1, 3, 5}, - {0, 3, 6, 2, 5, 1, 4}, - {0, 4, 1, 5, 2, 6, 3}, - {0, 5, 3, 1, 6, 4, 2}, - {0, 6, 5, 4, 3, 2, 1}}}}}; - - /// Table with the actual sequences \e w. - w_array orthogonal_sequence; - /// Table with the conjugated sequences \e w. - w_array orthogonal_sequence_conj; - public: /// Constructor: builds the sequences \e w from the coefficients in \ref pucch_format1_phi. pucch_orthogonal_sequence_format1() @@ -116,29 +78,49 @@ class pucch_orthogonal_sequence_format1 return span(orthogonal_sequence_conj[n_pucch - 1][i]).first(n_pucch); } -}; -/// Generator of orthogonal sequences \e w for PUCCH Format 4. -class pucch_orthogonal_sequence_format4 -{ private: - static constexpr auto one = cf_t(1.0f, 0.0f); - static constexpr auto neg_one = cf_t(-1.0f, 0.0f); - static constexpr auto j = cf_t(0.0f, 1.0f); - static constexpr auto neg_j = cf_t(0.0f, -1.0f); + /// Alias for sequence table type. + using w_array = + std::array, pucch_constants::FORMAT1_N_MAX>, + pucch_constants::FORMAT1_N_MAX>; - static constexpr std::array, 2> pucch_format4_length2 = {{ - {one, one, one, one, one, one, one, one, one, one, one, one}, - {one, one, one, one, one, one, neg_one, neg_one, neg_one, neg_one, neg_one, neg_one}, - }}; + /// \brief Coefficients \f$\phi(m)\f$ for sequence generation. + /// + /// See TS38.211 Table 6.3.2.4.1-2: Orthogonal sequences for PUCCH Format 1. + static constexpr std::array< + std::array, pucch_constants::FORMAT1_N_MAX>, + pucch_constants::FORMAT1_N_MAX> + pucch_format1_phi = { + {{{{0}, {}, {}, {}, {}, {}, {}}}, + {{{0, 0}, {0, 1}, {}, {}, {}, {}, {}}}, + {{{0, 0, 0}, {0, 1, 2}, {0, 2, 1}, {}, {}, {}, {}}}, + {{{0, 0, 0, 0}, {0, 2, 0, 2}, {0, 0, 2, 2}, {0, 2, 2, 0}, {}, {}, {}}}, + {{{0, 0, 0, 0, 0}, {0, 1, 2, 3, 4}, {0, 2, 4, 1, 3}, {0, 3, 1, 4, 2}, {0, 4, 3, 2, 1}, {}, {}}}, + {{{0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5}, + {0, 2, 4, 0, 2, 4}, + {0, 3, 0, 3, 0, 3}, + {0, 4, 2, 0, 4, 2}, + {0, 5, 4, 3, 2, 1}, + {}}}, + {{{0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6}, + {0, 2, 4, 6, 1, 3, 5}, + {0, 3, 6, 2, 5, 1, 4}, + {0, 4, 1, 5, 2, 6, 3}, + {0, 5, 3, 1, 6, 4, 2}, + {0, 6, 5, 4, 3, 2, 1}}}}}; - static constexpr std::array, 4> pucch_format4_length4 = {{ - {one, one, one, one, one, one, one, one, one, one, one, one}, - {one, one, one, neg_j, neg_j, neg_j, neg_one, neg_one, neg_one, j, j, j}, - {one, one, one, neg_one, neg_one, neg_one, one, one, one, neg_one, neg_one, neg_one}, - {one, one, one, j, j, j, neg_one, neg_one, neg_one, neg_j, neg_j, neg_j}, - }}; + /// Table with the actual sequences \e w. + w_array orthogonal_sequence; + /// Table with the conjugated sequences \e w. + w_array orthogonal_sequence_conj; +}; +/// Generator of orthogonal sequences \e w for PUCCH Format 4. +class pucch_orthogonal_sequence_format4 +{ public: /// \brief Gets an entire PUCCH Format 4 orthogonal sequence. /// @@ -157,6 +139,24 @@ class pucch_orthogonal_sequence_format4 } return pucch_format4_length4[i]; } + +private: + static constexpr auto one = cf_t(1.0f, 0.0f); + static constexpr auto neg_one = cf_t(-1.0f, 0.0f); + static constexpr auto j = cf_t(0.0f, 1.0f); + static constexpr auto neg_j = cf_t(0.0f, -1.0f); + + static constexpr std::array, 2> pucch_format4_length2 = {{ + {one, one, one, one, one, one, one, one, one, one, one, one}, + {one, one, one, one, one, one, neg_one, neg_one, neg_one, neg_one, neg_one, neg_one}, + }}; + + static constexpr std::array, 4> pucch_format4_length4 = {{ + {one, one, one, one, one, one, one, one, one, one, one, one}, + {one, one, one, neg_j, neg_j, neg_j, neg_one, neg_one, neg_one, j, j, j}, + {one, one, one, neg_one, neg_one, neg_one, one, one, one, neg_one, neg_one, neg_one}, + {one, one, one, j, j, j, neg_one, neg_one, neg_one, neg_j, neg_j, neg_j}, + }}; }; } // namespace srsran diff --git a/include/srsran/ran/pucch/pucch_constants.h b/include/srsran/ran/pucch/pucch_constants.h index 8043761161..4ba5809995 100644 --- a/include/srsran/ran/pucch/pucch_constants.h +++ b/include/srsran/ran/pucch/pucch_constants.h @@ -59,7 +59,7 @@ static constexpr unsigned FORMAT3_MAX_NSYMB = 14; /// Maximum number of PRBs allocated for PUCCH Format 3. static constexpr unsigned FORMAT3_MAX_NPRB = 16; -/// Minimum number of symbols that PUCCH Format 4 can transmit. +/// Minimum number of OFDM symbols allocated to a PUCCH Format 4 transmission. static constexpr unsigned FORMAT4_MIN_NSYMB = 4; /// Maximum number of symbols that PUCCH Format 4 can transmit. diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp index 386948598d..9a80b57696 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format3.cpp @@ -26,11 +26,15 @@ void pucch_demodulator_format3::demodulate(span // PUCCH Format 3 modulation scheme can be QPSK or pi/2-BPSK, as per TS38.211 Section 6.3.2.6.2. modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; - // Number of data Resource Elements in a slot for a single Rx port. + // Get a boolean mask of the OFDM symbols carrying DM-RS. symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); - const unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * config.nof_prb * NRE; + // Number of REs per OFDM symbol. + const unsigned nof_re_symb = config.nof_prb * NRE; + + // Number of data Resource Elements in a slot for a single Rx port. + const unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * nof_re_symb; // Assert that allocations are valid. srsran_assert(config.nof_prb && config.nof_prb <= pucch_constants::FORMAT3_MAX_NPRB, diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp index b1727cbe99..79eea21f49 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp @@ -16,6 +16,7 @@ #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/upper/pucch_formats_3_4_helpers.h" #include "srsran/phy/upper/pucch_orthogonal_sequence.h" +#include "srsran/srsvec/sc_prod.h" using namespace srsran; @@ -27,11 +28,15 @@ void pucch_demodulator_format4::demodulate(span // PUCCH Format 4 modulation scheme can be QPSK or pi/2-BPSK, as per TS38.211 Section 6.3.2.6.2. modulation_scheme mod_scheme = config.pi2_bpsk ? modulation_scheme::PI_2_BPSK : modulation_scheme::QPSK; - // Number of data Resource Elements in a slot for a single Rx port. + // Get a boolean mask of the OFDM symbols carrying DM-RS. symbol_slot_mask dmrs_symb_mask = get_pucch_formats_3_4_dmrs_symbol_mask( config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); - const unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * NRE; + // Number of REs per OFDM symbol. PUCCH Format 4 only gets a PRB. + const unsigned nof_re_symb = NRE; + + // Number of data Resource Elements in a slot for a single Rx port. + const unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * nof_re_symb; // Assert that allocations are valid. srsran_assert(config.first_prb * NRE <= grid.get_nof_subc(), @@ -96,11 +101,11 @@ void pucch_demodulator_format4::inverse_blockwise_spreading(span or span eq_noise_vars, const pucch_demodulator::format4_configuration& config) { - const unsigned mod = 12 / config.occ_length; - const span wn = pucch_orthogonal_sequence_format4::get_sequence(config.occ_length, config.occ_index); + unsigned mod = 12 / config.occ_length; + span wn = pucch_orthogonal_sequence_format4::get_sequence(config.occ_length, config.occ_index); - for (unsigned k = 0; k != NRE; k++) { - for (unsigned l = 0, l_end = eq_re.size() / NRE; l != l_end; l++) { + for (unsigned k = 0; k != NRE; ++k) { + for (unsigned l = 0, l_end = eq_re.size() / NRE; l != l_end; ++l) { const unsigned original_index = (l * mod) + (k % mod); const unsigned spread_index = (l * 12) + k; original[original_index] += eq_re[spread_index] / wn[k]; @@ -109,7 +114,5 @@ void pucch_demodulator_format4::inverse_blockwise_spreading(span or } // Scale according to the spreading factor. - for (cf_t& symbol : original) { - symbol /= config.occ_length; - } + srsvec::sc_prod(original, 1.0F / config.occ_length, original); } diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h index 701feb8a0b..e9371e4e78 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.h @@ -50,9 +50,13 @@ class pucch_demodulator_format4 const pucch_demodulator::format4_configuration& config); private: - /// Channel equalization component, also in charge of combining contributions of all receive antenna ports. + /// \brief Channel equalizer. + /// + /// Combines the contributions of all receive antenna ports, equalizing the channels. std::unique_ptr equalizer; - /// Demodulation mapper component: transforms channel symbols into log-likelihood ratios (i.e., soft bits). + /// \brief Demodulation mapper. + /// + /// Transforms channel symbols into log-likelihood ratios (i.e., soft bits). std::unique_ptr demapper; /// Descrambler component. std::unique_ptr descrambler; diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h index 39928ed6af..ada198b939 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 04-11-2024 (seed 0): +// This file was generated using the following MATLAB class on 05-11-2024 (seed 0): // + "srsPUCCHDemodulatorFormat4Unittest.m" #include "../../../support/resource_grid_test_doubles.h" @@ -35,70 +35,70 @@ struct test_case_t { static const std::vector pucch_demodulator_format4_test_data = { // clang-format off - {{266, 14, 0.81, {{0}, 251, {}, 0, 14, 8323, 927, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols0.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates0.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits0.dat"}}, - {{170, 14, 0.16, {{0}, 149, {}, 0, 14, 17800, 19, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols2.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates2.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits2.dat"}}, - {{151, 14, 0.01, {{0}, 132, {}, 0, 14, 6522, 814, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols4.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates4.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits4.dat"}}, - {{234, 14, 0.81, {{0}, 222, {}, 0, 14, 58321, 723, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols6.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates6.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits6.dat"}}, - {{273, 14, 0.09, {{0}, 259, {}, 0, 14, 65108, 82, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols8.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates8.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits8.dat"}}, - {{181, 14, 0.49, {{0}, 125, {}, 0, 14, 41366, 444, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols10.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates10.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits10.dat"}}, - {{233, 14, 0.64, {{0}, 69, {}, 0, 14, 64311, 341, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols12.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates12.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits12.dat"}}, - {{175, 14, 0.25, {{0}, 172, {}, 0, 14, 32009, 961, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols14.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates14.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits14.dat"}}, - {{263, 14, 0.64, {{0}, 254, 256, 0, 14, 41682, 101, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols16.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates16.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits16.dat"}}, - {{56, 14, 0.04, {{0}, 38, 51, 0, 14, 63908, 759, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols18.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates18.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits18.dat"}}, - {{163, 14, 0.04, {{0}, 105, 123, 0, 14, 34348, 992, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols20.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates20.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits20.dat"}}, - {{156, 14, 0.25, {{0}, 133, 148, 0, 14, 22469, 270, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols22.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates22.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits22.dat"}}, - {{175, 14, 0.09, {{0}, 93, 168, 0, 14, 55710, 275, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols24.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates24.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits24.dat"}}, - {{274, 14, 0.64, {{0}, 204, 240, 0, 14, 57200, 668, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols26.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates26.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits26.dat"}}, - {{143, 14, 0.16, {{0}, 104, 117, 0, 14, 58967, 519, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols28.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates28.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits28.dat"}}, - {{173, 14, 0.36, {{0}, 170, 162, 0, 14, 28669, 108, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols30.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates30.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits30.dat"}}, - {{243, 14, 0.36, {{0}, 88, {}, 1, 13, 30084, 983, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols32.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates32.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits32.dat"}}, - {{272, 14, 0.01, {{0}, 260, {}, 1, 13, 18233, 614, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols34.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates34.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits34.dat"}}, - {{23, 14, 0.04, {{0}, 12, {}, 1, 13, 11524, 987, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols36.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates36.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits36.dat"}}, - {{197, 14, 0.16, {{0}, 155, {}, 1, 13, 54686, 956, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols38.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates38.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits38.dat"}}, - {{244, 14, 0.04, {{0}, 242, {}, 1, 13, 39561, 352, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols40.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates40.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits40.dat"}}, - {{143, 14, 0.16, {{0}, 78, {}, 1, 13, 32422, 648, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols42.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates42.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits42.dat"}}, - {{271, 14, 0.49, {{0}, 269, {}, 1, 13, 9465, 594, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols44.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates44.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits44.dat"}}, - {{242, 14, 0.25, {{0}, 197, {}, 1, 13, 21870, 929, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols46.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates46.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits46.dat"}}, - {{234, 14, 0.16, {{0}, 160, 214, 1, 13, 2515, 22, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols48.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates48.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits48.dat"}}, - {{228, 14, 0.81, {{0}, 208, 216, 1, 13, 53298, 545, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols50.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates50.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits50.dat"}}, - {{145, 14, 0.04, {{0}, 141, 140, 1, 13, 45241, 1016, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols52.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates52.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits52.dat"}}, - {{268, 14, 0.09, {{0}, 263, 267, 1, 13, 47309, 662, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols54.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates54.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits54.dat"}}, - {{182, 14, 1, {{0}, 166, 131, 1, 13, 36950, 335, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols56.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates56.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits56.dat"}}, - {{224, 14, 0.09, {{0}, 123, 60, 1, 13, 19208, 713, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols58.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates58.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits58.dat"}}, - {{158, 14, 1, {{0}, 101, 95, 1, 13, 6522, 71, false, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols60.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates60.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits60.dat"}}, - {{213, 14, 0.81, {{0}, 196, 208, 1, 13, 33084, 318, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols62.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates62.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits62.dat"}}, - {{133, 14, 0.25, {{0}, 128, {}, 5, 5, 36679, 771, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols64.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates64.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits64.dat"}}, - {{202, 14, 0.49, {{0}, 199, {}, 5, 5, 40171, 77, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols66.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates66.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits66.dat"}}, - {{249, 14, 0.81, {{0}, 244, {}, 5, 5, 36556, 305, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols68.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates68.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits68.dat"}}, - {{213, 14, 0.81, {{0}, 133, {}, 5, 5, 15363, 373, true, true, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols70.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates70.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits70.dat"}}, - {{233, 14, 0.09, {{0}, 163, {}, 5, 5, 64895, 711, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols72.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates72.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits72.dat"}}, - {{234, 14, 1, {{0}, 199, {}, 5, 5, 22665, 919, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols74.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates74.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits74.dat"}}, - {{256, 14, 0.16, {{0}, 201, {}, 5, 5, 47693, 996, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols76.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates76.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits76.dat"}}, - {{91, 14, 1, {{0}, 37, {}, 5, 5, 56802, 799, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols78.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates78.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits78.dat"}}, - {{130, 14, 0.04, {{0}, 71, 82, 5, 5, 54938, 399, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols80.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates80.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits80.dat"}}, - {{252, 14, 0.16, {{0}, 200, 209, 5, 5, 20453, 722, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols82.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates82.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits82.dat"}}, - {{153, 14, 0.49, {{0}, 121, 118, 5, 5, 1198, 389, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols84.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates84.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits84.dat"}}, - {{251, 14, 0.49, {{0}, 218, 114, 5, 5, 46355, 329, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols86.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates86.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits86.dat"}}, - {{154, 14, 0.64, {{0}, 153, 148, 5, 5, 7574, 990, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols88.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates88.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits88.dat"}}, - {{207, 14, 0.04, {{0}, 206, 202, 5, 5, 259, 82, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols90.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates90.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits90.dat"}}, - {{202, 14, 0.36, {{0}, 170, 183, 5, 5, 22927, 430, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols92.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates92.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits92.dat"}}, - {{131, 14, 0.36, {{0}, 120, 130, 5, 5, 62760, 373, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols94.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates94.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits94.dat"}}, - {{64, 14, 0.04, {{0}, 49, {}, 10, 4, 1421, 152, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols96.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates96.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits96.dat"}}, - {{168, 14, 0.36, {{0}, 138, {}, 10, 4, 34828, 303, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols98.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates98.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits98.dat"}}, - {{267, 14, 0.09, {{0}, 240, {}, 10, 4, 33192, 647, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols100.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates100.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits100.dat"}}, - {{274, 14, 0.09, {{0}, 240, {}, 10, 4, 37965, 730, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols102.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates102.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits102.dat"}}, - {{237, 14, 0.36, {{0}, 231, {}, 10, 4, 62814, 1015, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols104.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates104.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits104.dat"}}, - {{126, 14, 0.16, {{0}, 99, {}, 10, 4, 19802, 285, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols106.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates106.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits106.dat"}}, - {{239, 14, 0.25, {{0}, 237, {}, 10, 4, 10629, 895, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols108.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates108.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits108.dat"}}, - {{187, 14, 0.49, {{0}, 123, {}, 10, 4, 34631, 791, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols110.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates110.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits110.dat"}}, - {{198, 14, 0.04, {{0}, 160, 170, 10, 4, 57520, 488, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols112.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates112.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits112.dat"}}, - {{205, 14, 0.81, {{0}, 149, 169, 10, 4, 12721, 295, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols114.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates114.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits114.dat"}}, - {{171, 14, 0.64, {{0}, 123, 135, 10, 4, 22780, 668, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols116.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates116.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits116.dat"}}, - {{131, 14, 0.81, {{0}, 126, 128, 10, 4, 51378, 645, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols118.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates118.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits118.dat"}}, - {{43, 14, 0.36, {{0}, 21, 26, 10, 4, 22335, 1012, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols120.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates120.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits120.dat"}}, - {{243, 14, 0.01, {{0}, 242, 237, 10, 4, 48633, 17, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols122.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates122.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits122.dat"}}, - {{246, 14, 0.25, {{0}, 208, 154, 10, 4, 60173, 295, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols124.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates124.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits124.dat"}}, - {{213, 14, 0.04, {{0}, 131, 111, 10, 4, 58214, 792, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols126.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates126.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits126.dat"}}, + {{266, 14, 0.75685, {{0}, 251, {}, 0, 14, 8323, 927, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols0.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates0.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits0.dat"}}, + {{170, 14, 0.17513, {{0}, 149, {}, 0, 14, 17800, 19, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols2.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates2.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits2.dat"}}, + {{151, 14, 0.010895, {{0}, 132, {}, 0, 14, 6522, 814, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols4.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates4.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits4.dat"}}, + {{234, 14, 0.77012, {{0}, 222, {}, 0, 14, 58321, 723, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols6.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates6.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits6.dat"}}, + {{273, 14, 0.11072, {{0}, 259, {}, 0, 14, 65108, 82, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols8.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates8.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits8.dat"}}, + {{181, 14, 0.49083, {{0}, 125, {}, 0, 14, 41366, 444, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols10.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates10.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits10.dat"}}, + {{233, 14, 0.62485, {{0}, 69, {}, 0, 14, 64311, 341, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols12.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates12.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits12.dat"}}, + {{175, 14, 0.29696, {{0}, 172, {}, 0, 14, 32009, 961, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols14.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates14.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits14.dat"}}, + {{263, 14, 0.62025, {{0}, 254, 256, 0, 14, 41682, 101, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols16.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates16.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits16.dat"}}, + {{56, 14, 0.041944, {{0}, 38, 51, 0, 14, 63908, 759, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols18.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates18.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits18.dat"}}, + {{163, 14, 0.028753, {{0}, 105, 123, 0, 14, 34348, 992, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols20.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates20.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits20.dat"}}, + {{156, 14, 0.29394, {{0}, 133, 148, 0, 14, 22469, 270, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols22.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates22.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits22.dat"}}, + {{175, 14, 0.069573, {{0}, 93, 168, 0, 14, 55710, 275, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols24.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates24.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits24.dat"}}, + {{274, 14, 0.7039, {{0}, 204, 240, 0, 14, 57200, 668, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols26.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates26.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits26.dat"}}, + {{143, 14, 0.1547, {{0}, 104, 117, 0, 14, 58967, 519, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols28.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates28.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits28.dat"}}, + {{173, 14, 0.37082, {{0}, 170, 162, 0, 14, 28669, 108, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols30.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates30.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits30.dat"}}, + {{243, 14, 0.3734, {{0}, 88, {}, 1, 13, 30084, 983, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols32.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates32.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits32.dat"}}, + {{272, 14, 0.01231, {{0}, 260, {}, 1, 13, 18233, 614, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols34.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates34.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits34.dat"}}, + {{23, 14, 0.040276, {{0}, 12, {}, 1, 13, 11524, 987, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols36.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates36.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits36.dat"}}, + {{197, 14, 0.14625, {{0}, 155, {}, 1, 13, 54686, 956, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols38.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates38.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits38.dat"}}, + {{244, 14, 0.035718, {{0}, 242, {}, 1, 13, 39561, 352, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols40.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates40.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits40.dat"}}, + {{143, 14, 0.18268, {{0}, 78, {}, 1, 13, 32422, 648, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols42.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates42.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits42.dat"}}, + {{271, 14, 0.55914, {{0}, 269, {}, 1, 13, 9465, 594, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols44.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates44.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits44.dat"}}, + {{242, 14, 0.22491, {{0}, 197, {}, 1, 13, 21870, 929, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols46.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates46.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits46.dat"}}, + {{234, 14, 0.18304, {{0}, 160, 214, 1, 13, 2515, 22, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols48.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates48.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits48.dat"}}, + {{228, 14, 0.87837, {{0}, 208, 216, 1, 13, 53298, 545, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols50.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates50.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits50.dat"}}, + {{145, 14, 0.047493, {{0}, 141, 140, 1, 13, 45241, 1016, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols52.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates52.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits52.dat"}}, + {{268, 14, 0.090909, {{0}, 263, 267, 1, 13, 47309, 662, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols54.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates54.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits54.dat"}}, + {{182, 14, 0.91595, {{0}, 166, 131, 1, 13, 36950, 335, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols56.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates56.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits56.dat"}}, + {{224, 14, 0.087317, {{0}, 123, 60, 1, 13, 19208, 713, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols58.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates58.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits58.dat"}}, + {{158, 14, 0.94204, {{0}, 101, 95, 1, 13, 6522, 71, false, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols60.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates60.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits60.dat"}}, + {{213, 14, 0.72643, {{0}, 196, 208, 1, 13, 33084, 318, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols62.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates62.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits62.dat"}}, + {{133, 14, 0.23744, {{0}, 128, {}, 5, 5, 36679, 771, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols64.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates64.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits64.dat"}}, + {{202, 14, 0.5062, {{0}, 199, {}, 5, 5, 40171, 77, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols66.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates66.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits66.dat"}}, + {{249, 14, 0.8086, {{0}, 244, {}, 5, 5, 36556, 305, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols68.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates68.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits68.dat"}}, + {{213, 14, 0.75856, {{0}, 133, {}, 5, 5, 15363, 373, true, true, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols70.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates70.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits70.dat"}}, + {{233, 14, 0.096132, {{0}, 163, {}, 5, 5, 64895, 711, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols72.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates72.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits72.dat"}}, + {{234, 14, 0.95965, {{0}, 199, {}, 5, 5, 22665, 919, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols74.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates74.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits74.dat"}}, + {{256, 14, 0.18407, {{0}, 201, {}, 5, 5, 47693, 996, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols76.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates76.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits76.dat"}}, + {{91, 14, 0.97904, {{0}, 37, {}, 5, 5, 56802, 799, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols78.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates78.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits78.dat"}}, + {{130, 14, 0.029736, {{0}, 71, 82, 5, 5, 54938, 399, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols80.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates80.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits80.dat"}}, + {{252, 14, 0.16121, {{0}, 200, 209, 5, 5, 20453, 722, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols82.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates82.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits82.dat"}}, + {{153, 14, 0.43581, {{0}, 121, 118, 5, 5, 1198, 389, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols84.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates84.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits84.dat"}}, + {{251, 14, 0.48932, {{0}, 218, 114, 5, 5, 46355, 329, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols86.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates86.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits86.dat"}}, + {{154, 14, 0.6621, {{0}, 153, 148, 5, 5, 7574, 990, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols88.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates88.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits88.dat"}}, + {{207, 14, 0.04597, {{0}, 206, 202, 5, 5, 259, 82, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols90.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates90.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits90.dat"}}, + {{202, 14, 0.41321, {{0}, 170, 183, 5, 5, 22927, 430, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols92.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates92.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits92.dat"}}, + {{131, 14, 0.41589, {{0}, 120, 130, 5, 5, 62760, 373, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols94.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates94.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits94.dat"}}, + {{64, 14, 0.036407, {{0}, 49, {}, 10, 4, 1421, 152, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols96.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates96.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits96.dat"}}, + {{168, 14, 0.40486, {{0}, 138, {}, 10, 4, 34828, 303, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols98.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates98.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits98.dat"}}, + {{267, 14, 0.099265, {{0}, 240, {}, 10, 4, 33192, 647, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols100.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates100.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits100.dat"}}, + {{274, 14, 0.065521, {{0}, 240, {}, 10, 4, 37965, 730, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols102.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates102.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits102.dat"}}, + {{237, 14, 0.35219, {{0}, 231, {}, 10, 4, 62814, 1015, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols104.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates104.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits104.dat"}}, + {{126, 14, 0.19109, {{0}, 99, {}, 10, 4, 19802, 285, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols106.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates106.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits106.dat"}}, + {{239, 14, 0.24898, {{0}, 237, {}, 10, 4, 10629, 895, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols108.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates108.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits108.dat"}}, + {{187, 14, 0.47986, {{0}, 123, {}, 10, 4, 34631, 791, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols110.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates110.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits110.dat"}}, + {{198, 14, 0.060298, {{0}, 160, 170, 10, 4, 57520, 488, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols112.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates112.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits112.dat"}}, + {{205, 14, 0.77811, {{0}, 149, 169, 10, 4, 12721, 295, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols114.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates114.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits114.dat"}}, + {{171, 14, 0.60999, {{0}, 123, 135, 10, 4, 22780, 668, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols116.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates116.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits116.dat"}}, + {{131, 14, 0.82374, {{0}, 126, 128, 10, 4, 51378, 645, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols118.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates118.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits118.dat"}}, + {{43, 14, 0.40984, {{0}, 21, 26, 10, 4, 22335, 1012, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols120.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates120.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits120.dat"}}, + {{243, 14, 0.011791, {{0}, 242, 237, 10, 4, 48633, 17, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols122.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates122.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits122.dat"}}, + {{246, 14, 0.24291, {{0}, 208, 154, 10, 4, 60173, 295, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols124.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates124.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits124.dat"}}, + {{213, 14, 0.058896, {{0}, 131, 111, 10, 4, 58214, 792, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols126.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates126.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits126.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz index 5b9e42d85b..d2d32efdf5 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c15d956679c5eaf78cd9530c5d8350bef1d4b15b5ed1949d129d341e07ee4751 -size 14998095 +oid sha256:bd8e2d6d083d3ecf7bba3c797c7729d66e01fbf7ca3e7848df7745924274968a +size 14998167 From 77b205f74f77bf610b260fdb95f727aeea6392d1 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 5 Nov 2024 17:01:34 +0100 Subject: [PATCH 28/72] phy: update pucch demodulator formats 2/3/4 test data --- .../pucch_demodulator_format2_test_data.h | 2 +- ...pucch_demodulator_format2_test_data.tar.gz | 4 +- .../pucch_demodulator_format3_test_data.h | 2 +- ...pucch_demodulator_format3_test_data.tar.gz | 4 +- .../pucch_demodulator_format4_test_data.h | 128 +++++++++--------- ...pucch_demodulator_format4_test_data.tar.gz | 4 +- 6 files changed, 72 insertions(+), 72 deletions(-) diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.h b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.h index 5f4dd3f4a4..b18d7b228b 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 23-10-2024 (seed 0): +// This file was generated using the following MATLAB class on 05-11-2024 (seed 0): // + "srsPUCCHDemodulatorFormat2Unittest.m" #include "../../../support/resource_grid_test_doubles.h" diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.tar.gz index 7d6a05ef6b..f85555201c 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format2_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aa305d3eaf3ea705a4ff62fb679efc4ec52025362c200d4bf7bccd76913c925b -size 20289236 +oid sha256:082e9dca64149f32b2bd14d38801744ccf34fcbc5be8f749b8d437661a1d220e +size 20289239 diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.h b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.h index 33c7ddbe0a..1ce4d67046 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 28-10-2024 (seed 0): +// This file was generated using the following MATLAB class on 05-11-2024 (seed 0): // + "srsPUCCHDemodulatorFormat3Unittest.m" #include "../../../support/resource_grid_test_doubles.h" diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.tar.gz index a56dbca97d..0c8b85129c 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format3_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:739e994ad63ded0fe623434e1d8e2597f95941694aa6e35672eabf65ccec068a -size 100967425 +oid sha256:9fee4bf20d0710fa674b689021ba2385b38bdd9f2f9e73b4056ab67c591a07e5 +size 100967264 diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h index ada198b939..ae9dc61c9d 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.h @@ -35,70 +35,70 @@ struct test_case_t { static const std::vector pucch_demodulator_format4_test_data = { // clang-format off - {{266, 14, 0.75685, {{0}, 251, {}, 0, 14, 8323, 927, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols0.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates0.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits0.dat"}}, - {{170, 14, 0.17513, {{0}, 149, {}, 0, 14, 17800, 19, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols2.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates2.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits2.dat"}}, - {{151, 14, 0.010895, {{0}, 132, {}, 0, 14, 6522, 814, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols4.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates4.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits4.dat"}}, - {{234, 14, 0.77012, {{0}, 222, {}, 0, 14, 58321, 723, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols6.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates6.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits6.dat"}}, - {{273, 14, 0.11072, {{0}, 259, {}, 0, 14, 65108, 82, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols8.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates8.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits8.dat"}}, - {{181, 14, 0.49083, {{0}, 125, {}, 0, 14, 41366, 444, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols10.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates10.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits10.dat"}}, - {{233, 14, 0.62485, {{0}, 69, {}, 0, 14, 64311, 341, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols12.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates12.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits12.dat"}}, - {{175, 14, 0.29696, {{0}, 172, {}, 0, 14, 32009, 961, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols14.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates14.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits14.dat"}}, - {{263, 14, 0.62025, {{0}, 254, 256, 0, 14, 41682, 101, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols16.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates16.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits16.dat"}}, - {{56, 14, 0.041944, {{0}, 38, 51, 0, 14, 63908, 759, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols18.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates18.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits18.dat"}}, - {{163, 14, 0.028753, {{0}, 105, 123, 0, 14, 34348, 992, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols20.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates20.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits20.dat"}}, - {{156, 14, 0.29394, {{0}, 133, 148, 0, 14, 22469, 270, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols22.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates22.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits22.dat"}}, - {{175, 14, 0.069573, {{0}, 93, 168, 0, 14, 55710, 275, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols24.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates24.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits24.dat"}}, - {{274, 14, 0.7039, {{0}, 204, 240, 0, 14, 57200, 668, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols26.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates26.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits26.dat"}}, - {{143, 14, 0.1547, {{0}, 104, 117, 0, 14, 58967, 519, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols28.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates28.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits28.dat"}}, - {{173, 14, 0.37082, {{0}, 170, 162, 0, 14, 28669, 108, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols30.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates30.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits30.dat"}}, - {{243, 14, 0.3734, {{0}, 88, {}, 1, 13, 30084, 983, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols32.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates32.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits32.dat"}}, - {{272, 14, 0.01231, {{0}, 260, {}, 1, 13, 18233, 614, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols34.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates34.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits34.dat"}}, - {{23, 14, 0.040276, {{0}, 12, {}, 1, 13, 11524, 987, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols36.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates36.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits36.dat"}}, - {{197, 14, 0.14625, {{0}, 155, {}, 1, 13, 54686, 956, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols38.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates38.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits38.dat"}}, - {{244, 14, 0.035718, {{0}, 242, {}, 1, 13, 39561, 352, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols40.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates40.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits40.dat"}}, - {{143, 14, 0.18268, {{0}, 78, {}, 1, 13, 32422, 648, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols42.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates42.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits42.dat"}}, - {{271, 14, 0.55914, {{0}, 269, {}, 1, 13, 9465, 594, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols44.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates44.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits44.dat"}}, - {{242, 14, 0.22491, {{0}, 197, {}, 1, 13, 21870, 929, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols46.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates46.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits46.dat"}}, - {{234, 14, 0.18304, {{0}, 160, 214, 1, 13, 2515, 22, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols48.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates48.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits48.dat"}}, - {{228, 14, 0.87837, {{0}, 208, 216, 1, 13, 53298, 545, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols50.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates50.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits50.dat"}}, - {{145, 14, 0.047493, {{0}, 141, 140, 1, 13, 45241, 1016, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols52.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates52.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits52.dat"}}, - {{268, 14, 0.090909, {{0}, 263, 267, 1, 13, 47309, 662, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols54.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates54.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits54.dat"}}, - {{182, 14, 0.91595, {{0}, 166, 131, 1, 13, 36950, 335, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols56.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates56.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits56.dat"}}, - {{224, 14, 0.087317, {{0}, 123, 60, 1, 13, 19208, 713, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols58.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates58.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits58.dat"}}, - {{158, 14, 0.94204, {{0}, 101, 95, 1, 13, 6522, 71, false, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols60.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates60.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits60.dat"}}, - {{213, 14, 0.72643, {{0}, 196, 208, 1, 13, 33084, 318, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols62.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates62.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits62.dat"}}, - {{133, 14, 0.23744, {{0}, 128, {}, 5, 5, 36679, 771, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols64.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates64.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits64.dat"}}, - {{202, 14, 0.5062, {{0}, 199, {}, 5, 5, 40171, 77, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols66.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates66.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits66.dat"}}, - {{249, 14, 0.8086, {{0}, 244, {}, 5, 5, 36556, 305, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols68.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates68.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits68.dat"}}, - {{213, 14, 0.75856, {{0}, 133, {}, 5, 5, 15363, 373, true, true, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols70.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates70.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits70.dat"}}, - {{233, 14, 0.096132, {{0}, 163, {}, 5, 5, 64895, 711, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols72.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates72.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits72.dat"}}, - {{234, 14, 0.95965, {{0}, 199, {}, 5, 5, 22665, 919, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols74.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates74.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits74.dat"}}, - {{256, 14, 0.18407, {{0}, 201, {}, 5, 5, 47693, 996, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols76.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates76.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits76.dat"}}, - {{91, 14, 0.97904, {{0}, 37, {}, 5, 5, 56802, 799, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols78.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates78.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits78.dat"}}, - {{130, 14, 0.029736, {{0}, 71, 82, 5, 5, 54938, 399, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols80.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates80.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits80.dat"}}, - {{252, 14, 0.16121, {{0}, 200, 209, 5, 5, 20453, 722, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols82.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates82.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits82.dat"}}, - {{153, 14, 0.43581, {{0}, 121, 118, 5, 5, 1198, 389, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols84.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates84.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits84.dat"}}, - {{251, 14, 0.48932, {{0}, 218, 114, 5, 5, 46355, 329, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols86.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates86.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits86.dat"}}, - {{154, 14, 0.6621, {{0}, 153, 148, 5, 5, 7574, 990, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols88.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates88.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits88.dat"}}, - {{207, 14, 0.04597, {{0}, 206, 202, 5, 5, 259, 82, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols90.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates90.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits90.dat"}}, - {{202, 14, 0.41321, {{0}, 170, 183, 5, 5, 22927, 430, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols92.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates92.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits92.dat"}}, - {{131, 14, 0.41589, {{0}, 120, 130, 5, 5, 62760, 373, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols94.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates94.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits94.dat"}}, - {{64, 14, 0.036407, {{0}, 49, {}, 10, 4, 1421, 152, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols96.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates96.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits96.dat"}}, - {{168, 14, 0.40486, {{0}, 138, {}, 10, 4, 34828, 303, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols98.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates98.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits98.dat"}}, - {{267, 14, 0.099265, {{0}, 240, {}, 10, 4, 33192, 647, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols100.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates100.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits100.dat"}}, - {{274, 14, 0.065521, {{0}, 240, {}, 10, 4, 37965, 730, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols102.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates102.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits102.dat"}}, - {{237, 14, 0.35219, {{0}, 231, {}, 10, 4, 62814, 1015, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols104.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates104.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits104.dat"}}, - {{126, 14, 0.19109, {{0}, 99, {}, 10, 4, 19802, 285, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols106.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates106.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits106.dat"}}, - {{239, 14, 0.24898, {{0}, 237, {}, 10, 4, 10629, 895, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols108.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates108.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits108.dat"}}, - {{187, 14, 0.47986, {{0}, 123, {}, 10, 4, 34631, 791, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols110.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates110.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits110.dat"}}, - {{198, 14, 0.060298, {{0}, 160, 170, 10, 4, 57520, 488, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols112.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates112.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits112.dat"}}, - {{205, 14, 0.77811, {{0}, 149, 169, 10, 4, 12721, 295, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols114.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates114.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits114.dat"}}, - {{171, 14, 0.60999, {{0}, 123, 135, 10, 4, 22780, 668, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols116.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates116.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits116.dat"}}, - {{131, 14, 0.82374, {{0}, 126, 128, 10, 4, 51378, 645, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols118.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates118.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits118.dat"}}, - {{43, 14, 0.40984, {{0}, 21, 26, 10, 4, 22335, 1012, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols120.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates120.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits120.dat"}}, - {{243, 14, 0.011791, {{0}, 242, 237, 10, 4, 48633, 17, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols122.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates122.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits122.dat"}}, - {{246, 14, 0.24291, {{0}, 208, 154, 10, 4, 60173, 295, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols124.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates124.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits124.dat"}}, - {{213, 14, 0.058896, {{0}, 131, 111, 10, 4, 58214, 792, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols126.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates126.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits126.dat"}}, + {{266, 14, 0.81, {{0}, 251, {}, 0, 14, 8323, 927, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols0.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates0.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits0.dat"}}, + {{170, 14, 0.16, {{0}, 149, {}, 0, 14, 17800, 19, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols2.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates2.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits2.dat"}}, + {{151, 14, 0.01, {{0}, 132, {}, 0, 14, 6522, 814, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols4.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates4.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits4.dat"}}, + {{234, 14, 0.81, {{0}, 222, {}, 0, 14, 58321, 723, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols6.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates6.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits6.dat"}}, + {{273, 14, 0.09, {{0}, 259, {}, 0, 14, 65108, 82, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols8.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates8.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits8.dat"}}, + {{181, 14, 0.49, {{0}, 125, {}, 0, 14, 41366, 444, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols10.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates10.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits10.dat"}}, + {{233, 14, 0.64, {{0}, 69, {}, 0, 14, 64311, 341, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols12.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates12.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits12.dat"}}, + {{175, 14, 0.25, {{0}, 172, {}, 0, 14, 32009, 961, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols14.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates14.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits14.dat"}}, + {{263, 14, 0.64, {{0}, 254, 256, 0, 14, 41682, 101, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols16.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates16.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits16.dat"}}, + {{56, 14, 0.04, {{0}, 38, 51, 0, 14, 63908, 759, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols18.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates18.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits18.dat"}}, + {{163, 14, 0.04, {{0}, 105, 123, 0, 14, 34348, 992, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols20.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates20.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits20.dat"}}, + {{156, 14, 0.25, {{0}, 133, 148, 0, 14, 22469, 270, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols22.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates22.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits22.dat"}}, + {{175, 14, 0.09, {{0}, 93, 168, 0, 14, 55710, 275, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols24.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates24.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits24.dat"}}, + {{274, 14, 0.64, {{0}, 204, 240, 0, 14, 57200, 668, false, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols26.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates26.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits26.dat"}}, + {{143, 14, 0.16, {{0}, 104, 117, 0, 14, 58967, 519, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols28.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates28.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits28.dat"}}, + {{173, 14, 0.36, {{0}, 170, 162, 0, 14, 28669, 108, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols30.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates30.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits30.dat"}}, + {{243, 14, 0.36, {{0}, 88, {}, 1, 13, 30084, 983, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols32.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates32.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits32.dat"}}, + {{272, 14, 0.01, {{0}, 260, {}, 1, 13, 18233, 614, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols34.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates34.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits34.dat"}}, + {{23, 14, 0.04, {{0}, 12, {}, 1, 13, 11524, 987, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols36.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates36.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits36.dat"}}, + {{197, 14, 0.16, {{0}, 155, {}, 1, 13, 54686, 956, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols38.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates38.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits38.dat"}}, + {{244, 14, 0.04, {{0}, 242, {}, 1, 13, 39561, 352, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols40.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates40.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits40.dat"}}, + {{143, 14, 0.16, {{0}, 78, {}, 1, 13, 32422, 648, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols42.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates42.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits42.dat"}}, + {{271, 14, 0.49, {{0}, 269, {}, 1, 13, 9465, 594, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols44.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates44.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits44.dat"}}, + {{242, 14, 0.25, {{0}, 197, {}, 1, 13, 21870, 929, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols46.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates46.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits46.dat"}}, + {{234, 14, 0.16, {{0}, 160, 214, 1, 13, 2515, 22, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols48.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates48.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits48.dat"}}, + {{228, 14, 0.81, {{0}, 208, 216, 1, 13, 53298, 545, true, false, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols50.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates50.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits50.dat"}}, + {{145, 14, 0.04, {{0}, 141, 140, 1, 13, 45241, 1016, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols52.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates52.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits52.dat"}}, + {{268, 14, 0.09, {{0}, 263, 267, 1, 13, 47309, 662, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols54.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates54.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits54.dat"}}, + {{182, 14, 1, {{0}, 166, 131, 1, 13, 36950, 335, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols56.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates56.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits56.dat"}}, + {{224, 14, 0.09, {{0}, 123, 60, 1, 13, 19208, 713, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols58.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates58.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits58.dat"}}, + {{158, 14, 1, {{0}, 101, 95, 1, 13, 6522, 71, false, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols60.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates60.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits60.dat"}}, + {{213, 14, 0.81, {{0}, 196, 208, 1, 13, 33084, 318, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols62.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates62.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits62.dat"}}, + {{133, 14, 0.25, {{0}, 128, {}, 5, 5, 36679, 771, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols64.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates64.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits64.dat"}}, + {{202, 14, 0.49, {{0}, 199, {}, 5, 5, 40171, 77, true, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols66.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates66.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits66.dat"}}, + {{249, 14, 0.81, {{0}, 244, {}, 5, 5, 36556, 305, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols68.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates68.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits68.dat"}}, + {{213, 14, 0.81, {{0}, 133, {}, 5, 5, 15363, 373, true, true, 4, 2}}, {"test_data/pucch_demodulator_format4_test_input_symbols70.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates70.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits70.dat"}}, + {{233, 14, 0.09, {{0}, 163, {}, 5, 5, 64895, 711, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols72.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates72.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits72.dat"}}, + {{234, 14, 1, {{0}, 199, {}, 5, 5, 22665, 919, false, false, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols74.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates74.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits74.dat"}}, + {{256, 14, 0.16, {{0}, 201, {}, 5, 5, 47693, 996, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols76.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates76.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits76.dat"}}, + {{91, 14, 1, {{0}, 37, {}, 5, 5, 56802, 799, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols78.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates78.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits78.dat"}}, + {{130, 14, 0.04, {{0}, 71, 82, 5, 5, 54938, 399, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols80.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates80.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits80.dat"}}, + {{252, 14, 0.16, {{0}, 200, 209, 5, 5, 20453, 722, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols82.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates82.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits82.dat"}}, + {{153, 14, 0.49, {{0}, 121, 118, 5, 5, 1198, 389, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols84.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates84.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits84.dat"}}, + {{251, 14, 0.49, {{0}, 218, 114, 5, 5, 46355, 329, true, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols86.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates86.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits86.dat"}}, + {{154, 14, 0.64, {{0}, 153, 148, 5, 5, 7574, 990, false, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols88.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates88.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits88.dat"}}, + {{207, 14, 0.04, {{0}, 206, 202, 5, 5, 259, 82, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols90.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates90.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits90.dat"}}, + {{202, 14, 0.36, {{0}, 170, 183, 5, 5, 22927, 430, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols92.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates92.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits92.dat"}}, + {{131, 14, 0.36, {{0}, 120, 130, 5, 5, 62760, 373, false, true, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols94.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates94.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits94.dat"}}, + {{64, 14, 0.04, {{0}, 49, {}, 10, 4, 1421, 152, true, false, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols96.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates96.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits96.dat"}}, + {{168, 14, 0.36, {{0}, 138, {}, 10, 4, 34828, 303, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols98.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates98.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits98.dat"}}, + {{267, 14, 0.09, {{0}, 240, {}, 10, 4, 33192, 647, true, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols100.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates100.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits100.dat"}}, + {{274, 14, 0.09, {{0}, 240, {}, 10, 4, 37965, 730, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols102.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates102.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits102.dat"}}, + {{237, 14, 0.36, {{0}, 231, {}, 10, 4, 62814, 1015, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols104.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates104.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits104.dat"}}, + {{126, 14, 0.16, {{0}, 99, {}, 10, 4, 19802, 285, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols106.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates106.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits106.dat"}}, + {{239, 14, 0.25, {{0}, 237, {}, 10, 4, 10629, 895, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols108.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates108.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits108.dat"}}, + {{187, 14, 0.49, {{0}, 123, {}, 10, 4, 34631, 791, false, true, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols110.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates110.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits110.dat"}}, + {{198, 14, 0.04, {{0}, 160, 170, 10, 4, 57520, 488, true, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols112.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates112.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits112.dat"}}, + {{205, 14, 0.81, {{0}, 149, 169, 10, 4, 12721, 295, true, false, 4, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols114.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates114.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits114.dat"}}, + {{171, 14, 0.64, {{0}, 123, 135, 10, 4, 22780, 668, true, true, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols116.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates116.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits116.dat"}}, + {{131, 14, 0.81, {{0}, 126, 128, 10, 4, 51378, 645, true, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols118.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates118.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits118.dat"}}, + {{43, 14, 0.36, {{0}, 21, 26, 10, 4, 22335, 1012, false, false, 2, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols120.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates120.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits120.dat"}}, + {{243, 14, 0.01, {{0}, 242, 237, 10, 4, 48633, 17, false, false, 4, 1}}, {"test_data/pucch_demodulator_format4_test_input_symbols122.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates122.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits122.dat"}}, + {{246, 14, 0.25, {{0}, 208, 154, 10, 4, 60173, 295, false, true, 2, 0}}, {"test_data/pucch_demodulator_format4_test_input_symbols124.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates124.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits124.dat"}}, + {{213, 14, 0.04, {{0}, 131, 111, 10, 4, 58214, 792, false, true, 4, 3}}, {"test_data/pucch_demodulator_format4_test_input_symbols126.dat"}, {"test_data/pucch_demodulator_format4_test_input_estimates126.dat"}, {"test_data/pucch_demodulator_format4_test_output_sch_soft_bits126.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz index d2d32efdf5..c476581679 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pucch/pucch_demodulator_format4_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd8e2d6d083d3ecf7bba3c797c7729d66e01fbf7ca3e7848df7745924274968a -size 14998167 +oid sha256:56fa6f51c2a0a53015733b0e7983b09c41ec822c0bb998adf1eab97ee61d32a4 +size 14998090 From 00f419931038daa70eeca43b355332c290fdd7df Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Wed, 6 Nov 2024 14:36:13 +0100 Subject: [PATCH 29/72] phy: review pucch demodulator format 4 --- .../phy/upper/pucch_formats_3_4_helpers.h | 38 +++++++++---------- .../phy/upper/pucch_orthogonal_sequence.h | 8 ++-- .../pucch/pucch_demodulator_format4.cpp | 12 +++--- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h index 07e02225e0..f6360be26f 100644 --- a/include/srsran/phy/upper/pucch_formats_3_4_helpers.h +++ b/include/srsran/phy/upper/pucch_formats_3_4_helpers.h @@ -120,12 +120,12 @@ inline symbol_slot_mask get_pucch_formats_3_4_dmrs_symbol_mask( return mask; } -/// \brief Gets REs and channel estimates given a PUCCH Format 3/4 resource, performs equalization and transform -/// deprecoding. +/// \brief Gets REs and channel estimates given a PUCCH Format 3/4 resource, performs equalization and reverts +/// transform precoding. /// /// Extracts and loads the inner buffers with the PUCCH control data RE from the provided \c resource_grid, and their /// corresponding channel estimates from \c channel_ests. The DM-RS RE are skipped. Equalization and transform -/// deprecoding is done symbol by symbol. +/// precoding reversion is done symbol by symbol. /// /// \param[out] eq_re Destination buffer for resource elements at the equalizer output. /// \param[out] eq_noise_vars Destination buffer for noise variances at the equalizer output. @@ -141,28 +141,28 @@ inline symbol_slot_mask get_pucch_formats_3_4_dmrs_symbol_mask( /// \param[in] second_hop_prb Lowest PRB index used for the PUCCH transmission within the BWP {0, ..., 274} /// if intra-slot frequency hopping is enabled, empty otherwise. /// \param[in] rx_ports Port indexes used for the PUCCH reception. -inline void pucch_3_4_extract_and_equalize(span eq_re, - span eq_noise_vars, - channel_equalizer& equalizer, - transform_precoder& precoder, - const resource_grid_reader& grid, - const channel_estimate& estimates, - const symbol_slot_mask& dmrs_symb_mask, - const unsigned start_symbol_index, - const unsigned nof_symbols, - const unsigned nof_prb, - const unsigned first_prb, - const std::optional second_hop_prb, - span rx_ports) +inline void pucch_3_4_extract_and_equalize(span eq_re, + span eq_noise_vars, + channel_equalizer& equalizer, + transform_precoder& precoder, + const resource_grid_reader& grid, + const channel_estimate& estimates, + const symbol_slot_mask& dmrs_symb_mask, + unsigned start_symbol_index, + unsigned nof_symbols, + unsigned nof_prb, + unsigned first_prb, + std::optional second_hop_prb, + span rx_ports) { // Number of receive antenna ports. auto nof_rx_ports = static_cast(rx_ports.size()); // Number of REs per OFDM symbol. - const unsigned nof_re_symb = nof_prb * NRE; + unsigned nof_re_symb = nof_prb * NRE; // Index of the first symbol allocated to the second hop, when intra-slot frequency hopping is enabled. - const unsigned second_hop_start = (nof_symbols / 2) + start_symbol_index; + unsigned second_hop_start = (nof_symbols / 2) + start_symbol_index; // Extract the Rx port noise variances from the channel estimation. std::array noise_var_estimates; @@ -178,7 +178,7 @@ inline void pucch_3_4_extract_and_equalize(span eq_re, continue; } - // Calculate the lowest resource element containing PUCCH Format 3 within the OFDM symbol. + // Calculate the lowest resource element containing the PUCCH resource within the OFDM symbol. unsigned first_subc = first_prb * NRE; if (second_hop_prb.has_value() && (i_symbol >= second_hop_start)) { // Intra-slot frequency hopping. diff --git a/include/srsran/phy/upper/pucch_orthogonal_sequence.h b/include/srsran/phy/upper/pucch_orthogonal_sequence.h index 022f84e0a5..3905343616 100644 --- a/include/srsran/phy/upper/pucch_orthogonal_sequence.h +++ b/include/srsran/phy/upper/pucch_orthogonal_sequence.h @@ -141,10 +141,10 @@ class pucch_orthogonal_sequence_format4 } private: - static constexpr auto one = cf_t(1.0f, 0.0f); - static constexpr auto neg_one = cf_t(-1.0f, 0.0f); - static constexpr auto j = cf_t(0.0f, 1.0f); - static constexpr auto neg_j = cf_t(0.0f, -1.0f); + static constexpr auto one = cf_t(1.0F, 0.0F); + static constexpr auto neg_one = cf_t(-1.0F, 0.0F); + static constexpr auto j = cf_t(0.0F, 1.0F); + static constexpr auto neg_j = cf_t(0.0F, -1.0F); static constexpr std::array, 2> pucch_format4_length2 = {{ {one, one, one, one, one, one, one, one, one, one, one, one}, diff --git a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp index 79eea21f49..5094ebd538 100644 --- a/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp +++ b/lib/phy/upper/channel_processors/pucch/pucch_demodulator_format4.cpp @@ -33,10 +33,10 @@ void pucch_demodulator_format4::demodulate(span config.nof_symbols, config.second_hop_prb.has_value(), config.additional_dmrs); // Number of REs per OFDM symbol. PUCCH Format 4 only gets a PRB. - const unsigned nof_re_symb = NRE; + unsigned nof_re_symb = NRE; // Number of data Resource Elements in a slot for a single Rx port. - const unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * nof_re_symb; + unsigned nof_re_port = (config.nof_symbols - dmrs_symb_mask.count()) * nof_re_symb; // Assert that allocations are valid. srsran_assert(config.first_prb * NRE <= grid.get_nof_subc(), @@ -61,7 +61,7 @@ void pucch_demodulator_format4::demodulate(span // Assert that the number of RE returned by the channel equalizer matches the expected number of LLR. srsran_assert(eq_re.size() / config.occ_length == llr.size() / get_bits_per_symbol(mod_scheme), - "Number of equalized RE (i.e. {}) does not match the expected LLR data length (i.e. {})", + "Number of equalized REs (i.e. {}) does not match the expected LLR data length (i.e. {})", eq_re.size() / config.occ_length, llr.size() / get_bits_per_symbol(mod_scheme)); @@ -90,7 +90,7 @@ void pucch_demodulator_format4::demodulate(span demapper->demodulate_soft(llr, original, noise_vars, mod_scheme); // Descramble, as per TS38.211 Section 6.3.2.6.1. - const unsigned c_init = (config.rnti * pow2(15)) + config.n_id; + unsigned c_init = (config.rnti * pow2(15)) + config.n_id; descrambler->init(c_init); descrambler->apply_xor(llr, llr); } @@ -106,8 +106,8 @@ void pucch_demodulator_format4::inverse_blockwise_spreading(span or for (unsigned k = 0; k != NRE; ++k) { for (unsigned l = 0, l_end = eq_re.size() / NRE; l != l_end; ++l) { - const unsigned original_index = (l * mod) + (k % mod); - const unsigned spread_index = (l * 12) + k; + unsigned original_index = (l * mod) + (k % mod); + unsigned spread_index = (l * 12) + k; original[original_index] += eq_re[spread_index] / wn[k]; noise_vars[original_index] += eq_noise_vars[spread_index]; } From 8b1037d56421658c33c5f8aa70b8d731537e0db3 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 5 Nov 2024 05:01:38 +0100 Subject: [PATCH 30/72] support: relax test criterion... ...because involuntarily context switch may happen (instead) --- tests/unittests/support/tracing/resource_usage_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unittests/support/tracing/resource_usage_test.cpp b/tests/unittests/support/tracing/resource_usage_test.cpp index e220eea217..c53f9c1471 100644 --- a/tests/unittests/support/tracing/resource_usage_test.cpp +++ b/tests/unittests/support/tracing/resource_usage_test.cpp @@ -29,7 +29,7 @@ TEST(resource_usage_test, resource_usage_diff_detects_sleep) usleep(10); resource_usage::snapshot point2 = resource_usage::now().value(); resource_usage::diff d = point2 - point1; - ASSERT_GE(d.vol_ctxt_switch_count, 1); + ASSERT_GE(d.vol_ctxt_switch_count + d.invol_ctxt_switch_count, 1); } TEST(resource_usage_test, format_resource_usage_diff) @@ -42,4 +42,4 @@ TEST(resource_usage_test, format_resource_usage_diff) std::string str = fmt::format("{}", d); ASSERT_GT(str.size(), 0); fmt::print("> result: {}\n", str); -} \ No newline at end of file +} From bea881bb8efe6a3e5b2bfbbd48881886aa27fa5c Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 23 Oct 2024 17:52:00 +0200 Subject: [PATCH 31/72] e2,kpm: fix DRB.AirIfDelayUl metric --- .../e2sm_kpm_du_meas_provider_impl.cpp | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index 54b7cb5c22..d8a76a4828 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -585,16 +585,43 @@ bool e2sm_kpm_du_meas_provider_impl::get_delay_ul(const asn1::e2sm::label_info_l if (last_ue_metrics.empty()) { return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); } - scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; + if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { logger.debug("Metric: DRB.AirIfDelayUl supports only NO_LABEL label."); return meas_collected; } - meas_record_item_c meas_record_item; - meas_record_item.set_real().value = ue_metrics.ul_delay_ms; - items.push_back(meas_record_item); - meas_collected = true; + + if (ues.empty()) { + double mean_ul_delay_ms = + std::accumulate(last_ue_metrics.begin(), + last_ue_metrics.end(), + 0, + [](size_t sum, const scheduler_ue_metrics& metric) { return sum + metric.ul_delay_ms; }) / + last_ue_metrics.size(); + meas_record_item_c meas_record_item; + if (mean_ul_delay_ms) { + meas_record_item.set_real().value = static_cast(mean_ul_delay_ms); + } else { + meas_record_item.set_no_value(); + } + items.push_back(meas_record_item); + meas_collected = true; + } + + for (auto& ue : ues) { + gnb_cu_ue_f1ap_id_t gnb_cu_ue_f1ap_id = int_to_gnb_cu_ue_f1ap_id(ue.gnb_du_ue_id().gnb_cu_ue_f1ap_id); + uint32_t ue_idx = f1ap_ue_id_provider.get_ue_index(gnb_cu_ue_f1ap_id); + meas_record_item_c meas_record_item; + if (last_ue_metrics[ue_idx].ul_delay_ms) { + meas_record_item.set_real().value = static_cast(last_ue_metrics[ue_idx].ul_delay_ms); + } else { + meas_record_item.set_no_value(); + } + items.push_back(meas_record_item); + meas_collected = true; + } + return meas_collected; } From a600b97a1fe077259319ee43d2ce3dcca0bdbbd3 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 31 Oct 2024 11:42:34 +0100 Subject: [PATCH 32/72] e2sm_kpm: set no value if delays are zero --- .../e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index d8a76a4828..7e93b636a9 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -1096,7 +1096,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm items.push_back(meas_record_item); meas_collected = true; } else { - logger.warning("Invalid RLC SDU latency value."); + meas_record_item.set_no_value(); + items.push_back(meas_record_item); + meas_collected = true; return meas_collected; } } else { @@ -1126,7 +1128,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm items.push_back(meas_record_item); meas_collected = true; } else { - logger.warning("Invalid RLC SDU latency value."); + meas_record_item.set_no_value(); + items.push_back(meas_record_item); + meas_collected = true; } } } @@ -1171,7 +1175,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm items.push_back(meas_record_item); meas_collected = true; } else { - logger.warning("Invalid RLC SDU latency value."); + meas_record_item.set_no_value(); + items.push_back(meas_record_item); + meas_collected = true; return meas_collected; } } else { @@ -1201,7 +1207,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm items.push_back(meas_record_item); meas_collected = true; } else { - logger.warning("Invalid RLC SDU latency value."); + meas_record_item.set_no_value(); + items.push_back(meas_record_item); + meas_collected = true; } } } From bea170600746d0a63b119ec51da409739445b04a Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 31 Oct 2024 12:29:26 +0100 Subject: [PATCH 33/72] e2sm_kpm: fix DRB.RlcDelayUl and DRB.RlcSduDelayDl measurement record units --- .../e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index 7e93b636a9..cdb3db0887 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -1091,8 +1091,10 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm } } if (av_ue_sdu_latency_us) { + float av_ue_sdu_latency_ms = (av_ue_sdu_latency_us / ue_aggr_rlc_metrics.size()) / 1e3; // Unit is 0.1 ms. + av_ue_sdu_latency_ms = std::round(av_ue_sdu_latency_ms * 10.0f) / 10.0f; meas_record_item.set_real(); - meas_record_item.real().value = av_ue_sdu_latency_us / ue_aggr_rlc_metrics.size(); + meas_record_item.real().value = av_ue_sdu_latency_ms; items.push_back(meas_record_item); meas_collected = true; } else { @@ -1123,8 +1125,10 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm 0, [](size_t sum, const rlc_metrics& metric) { return sum + metric.tx.tx_high.num_sdus; }); if (tot_sdu_latency_us) { + float av_ue_sdu_latency_ms = (tot_sdu_latency_us / tot_num_sdus) / 1e3; // Unit is 0.1 ms. + av_ue_sdu_latency_ms = std::round(av_ue_sdu_latency_ms * 10.0f) / 10.0f; meas_record_item.set_real(); - meas_record_item.real().value = tot_sdu_latency_us / tot_num_sdus; + meas_record_item.real().value = av_ue_sdu_latency_ms; items.push_back(meas_record_item); meas_collected = true; } else { @@ -1171,7 +1175,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm } if (av_ue_sdu_latency_us) { meas_record_item.set_real(); - meas_record_item.real().value = (float)av_ue_sdu_latency_us / ue_aggr_rlc_metrics.size(); + meas_record_item.real().value = (av_ue_sdu_latency_us / ue_aggr_rlc_metrics.size()) / 1e3; // Unit is ms. items.push_back(meas_record_item); meas_collected = true; } else { @@ -1203,7 +1207,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm [](size_t sum, const rlc_metrics& metric) { return sum + metric.rx.num_sdus; }); if (tot_sdu_latency) { meas_record_item.set_real(); - meas_record_item.real().value = tot_sdu_latency / tot_num_sdus; + meas_record_item.real().value = (tot_sdu_latency / tot_num_sdus) / 1e3; // Unit is ms. items.push_back(meas_record_item); meas_collected = true; } else { From bbfde25fb30ec34194830f4824929f502aa49f9f Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Fri, 1 Nov 2024 18:31:44 +0100 Subject: [PATCH 34/72] e2sm_kpm: test du_meas_provider metrics, for E2-NODE level a measurement record has to be always returned, check returned type with TS metric definition --- .../e2sm_kpm_du_meas_provider_impl.cpp | 22 +- tests/unittests/e2/CMakeLists.txt | 5 + .../e2sm_kpm_meas_provider_metrics_test.cpp | 313 ++++++++++++++++++ .../e2/e2sm_kpm_meas_provider_test.cpp | 8 +- 4 files changed, 333 insertions(+), 15 deletions(-) create mode 100644 tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index cdb3db0887..d2388d3a71 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -583,7 +583,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_delay_ul(const asn1::e2sm::label_info_l { bool meas_collected = false; if (last_ue_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::no_value); } if ((label_info_list.size() > 1 or @@ -660,7 +660,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_mean_throughput(const asn1::e2sm { bool meas_collected = false; if (ue_aggr_rlc_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -706,7 +706,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_mean_throughput(const asn1::e2sm for (auto& ue : ue_throughput) { total_throughput += ue.second; } - meas_record_item.set_integer() = total_throughput; + meas_record_item.set_real().value = total_throughput; items.push_back(meas_record_item); meas_collected = true; } @@ -721,7 +721,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_mean_throughput(const asn1::e2sm meas_collected = true; continue; } - meas_record_item.set_integer() = ue_throughput[ue_idx]; + meas_record_item.set_real().value = ue_throughput[ue_idx]; items.push_back(meas_record_item); meas_collected = true; } @@ -735,7 +735,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_mean_throughput(const asn1::e2sm { bool meas_collected = false; if (ue_aggr_rlc_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -761,7 +761,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_mean_throughput(const asn1::e2sm for (auto& ue : ue_throughput) { total_throughput += ue.second; } - meas_record_item.set_integer() = total_throughput; + meas_record_item.set_real().value = total_throughput; items.push_back(meas_record_item); meas_collected = true; } @@ -776,7 +776,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_mean_throughput(const asn1::e2sm meas_collected = true; continue; } - meas_record_item.set_integer() = ue_throughput[ue_idx]; + meas_record_item.set_real().value = ue_throughput[ue_idx]; items.push_back(meas_record_item); meas_collected = true; } @@ -790,7 +790,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_success_rate(const asn1::e2sm::l { bool meas_collected = false; if (ue_aggr_rlc_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::no_value); } if ((label_info_list.size() > 1 or (label_info_list.size() == 1 and not label_info_list[0].meas_label.no_label_present))) { @@ -867,7 +867,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_packet_drop_rate_dl( { bool meas_collected = false; if (ue_aggr_rlc_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::integer); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::no_value); } if ((label_info_list.size() > 1 or @@ -1065,7 +1065,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm { bool meas_collected = false; if (ue_aggr_rlc_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::no_value); } if ((label_info_list.size() > 1 or @@ -1148,7 +1148,7 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm { bool meas_collected = false; if (ue_aggr_rlc_metrics.empty()) { - return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::real); + return handle_no_meas_data_available(ues, items, asn1::e2sm::meas_record_item_c::types::options::no_value); } if ((label_info_list.size() > 1 or diff --git a/tests/unittests/e2/CMakeLists.txt b/tests/unittests/e2/CMakeLists.txt index d5dd938327..84fa5659e8 100644 --- a/tests/unittests/e2/CMakeLists.txt +++ b/tests/unittests/e2/CMakeLists.txt @@ -44,6 +44,11 @@ target_link_libraries(e2sm_kpm_meas_provider_test srslog srsran_network srsran_e target_include_directories(e2sm_kpm_meas_provider_test PRIVATE ${CMAKE_SOURCE_DIR}) gtest_discover_tests(e2sm_kpm_meas_provider_test) +add_executable(e2sm_kpm_meas_provider_metrics_test e2sm_kpm_meas_provider_metrics_test.cpp) +target_link_libraries(e2sm_kpm_meas_provider_metrics_test srslog srsran_network srsran_e2 e2ap_asn1 srsran_pcap srsran_gateway srsran_support gtest gtest_main) +target_include_directories(e2sm_kpm_meas_provider_metrics_test PRIVATE ${CMAKE_SOURCE_DIR}) +gtest_discover_tests(e2sm_kpm_meas_provider_metrics_test) + add_executable(e2sm_kpm_test e2sm_kpm_test.cpp) target_link_libraries(e2sm_kpm_test srslog srsran_network srsran_e2 e2ap_asn1 srsran_pcap srsran_gateway srsran_support gtest gtest_main) target_include_directories(e2sm_kpm_test PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp b/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp new file mode 100644 index 0000000000..2e0ba4560a --- /dev/null +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp @@ -0,0 +1,313 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "lib/e2/e2sm/e2sm_kpm/e2sm_kpm_cu_meas_provider_impl.h" +#include "lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h" +#include "tests/unittests/e2/common/e2_test_helpers.h" +#include "srsran/support/srsran_test.h" +#include + +using namespace srsran; +using namespace asn1::e2sm; + +span e2sm_kpm_28_552_metrics = get_e2sm_kpm_28_552_metrics(); +span e2sm_kpm_oran_metrics = get_e2sm_kpm_oran_metrics(); + +bool get_metric_definition(std::string metric_name, e2sm_kpm_metric_t& e2sm_kpm_metric_def) +{ + auto name_matches = [&metric_name](const e2sm_kpm_metric_t& x) { + return (x.name == metric_name.c_str() or x.name == metric_name); + }; + + auto it = std::find_if(e2sm_kpm_28_552_metrics.begin(), e2sm_kpm_28_552_metrics.end(), name_matches); + if (it != e2sm_kpm_28_552_metrics.end()) { + e2sm_kpm_metric_def = *it; + return true; + } + + it = std::find_if(e2sm_kpm_oran_metrics.begin(), e2sm_kpm_oran_metrics.end(), name_matches); + if (it != e2sm_kpm_oran_metrics.end()) { + e2sm_kpm_metric_def = *it; + return true; + } + + return false; +} + +rlc_metrics generate_non_zero_rlc_metrics(uint32_t ue_idx, uint32_t bearer_id) +{ + rlc_metrics rlc_metric; + rlc_metric.metrics_period = std::chrono::milliseconds(1000); + rlc_metric.ue_index = static_cast(ue_idx); + rlc_metric.rb_id = rb_id_t(drb_id_t(bearer_id)); + rlc_metric.rx.mode = rlc_mode::am; + rlc_metric.rx.num_pdus = 5; + rlc_metric.rx.num_pdu_bytes = rlc_metric.rx.num_pdus * 1000; + rlc_metric.rx.num_sdus = 5; + rlc_metric.rx.num_sdu_bytes = rlc_metric.rx.num_sdus * 1000; + rlc_metric.rx.num_lost_pdus = 1; + rlc_metric.rx.num_malformed_pdus = 1; + rlc_metric.rx.sdu_latency_us = 1000; + + rlc_metric.tx.tx_low.mode = rlc_mode::am; + rlc_metric.tx.tx_high.num_sdus = 10; + rlc_metric.tx.tx_high.num_sdu_bytes = rlc_metric.tx.tx_high.num_sdus * 1000; + rlc_metric.tx.tx_high.num_dropped_sdus = 1; + rlc_metric.tx.tx_high.num_discarded_sdus = 1; + rlc_metric.tx.tx_high.num_discard_failures = 1; + rlc_metric.tx.tx_low.sum_sdu_latency_us = 1000; + rlc_metric.tx.tx_low.num_of_pulled_sdus = 1; + rlc_metric.tx.tx_low.num_pdus_no_segmentation = 10; + rlc_metric.tx.tx_low.num_pdu_bytes_no_segmentation = rlc_metric.tx.tx_low.num_pdus_no_segmentation * 1000; + rlc_metric.tx.tx_low.mode_specific.am.num_pdus_with_segmentation = 2; + rlc_metric.tx.tx_low.mode_specific.am.num_pdu_bytes_with_segmentation = + rlc_metric.tx.tx_low.mode_specific.am.num_pdus_with_segmentation * 1000; + return rlc_metric; +} + +scheduler_cell_metrics generate_non_zero_sched_metrics() +{ + scheduler_cell_metrics sched_metric; + sched_metric.nof_prbs = 52; + sched_metric.nof_dl_slots = 14; + sched_metric.nof_ul_slots = 14; + sched_metric.nof_prach_preambles = 10; + + scheduler_ue_metrics ue_metrics = {0}; + ue_metrics.pci = 1; + ue_metrics.rnti = static_cast(0x1000 + 1); + ue_metrics.tot_dl_prbs_used = 1200; + ue_metrics.mean_dl_prbs_used = 12; + ue_metrics.tot_ul_prbs_used = 1200; + ue_metrics.mean_ul_prbs_used = 12; + ue_metrics.ul_delay_ms = 100; + ue_metrics.pusch_snr_db = 10; + for (auto i = 0; i < 10; i++) { + ue_metrics.cqi_stats.update(i); + } + sched_metric.ue_metrics.push_back(ue_metrics); + + return sched_metric; +} + +class dummy_e2_du_metrics_notifier : public e2_du_metrics_notifier, public e2_du_metrics_interface +{ +public: + void report_metrics(const scheduler_cell_metrics& metrics) override + { + if (e2_meas_provider) { + e2_meas_provider->report_metrics(metrics); + } + } + + void report_metrics(const rlc_metrics& metrics) override + { + if (e2_meas_provider) { + e2_meas_provider->report_metrics(metrics); + } + } + + void connect_e2_du_meas_provider(std::unique_ptr meas_provider) override {} + + void connect_e2_du_meas_provider(e2_du_metrics_notifier* meas_provider) { e2_meas_provider = meas_provider; } + +private: + e2_du_metrics_notifier* e2_meas_provider; +}; + +class e2sm_kpm_meas_provider_metrics_test : public ::testing::Test +{ +protected: + void SetUp() override + { + srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); + srslog::init(); + f1ap_ue_id_mapper = std::make_unique(); + du_meas_provider = std::make_unique(*f1ap_ue_id_mapper); + metrics = std::make_unique(); + metrics->connect_e2_du_meas_provider(du_meas_provider.get()); + } + + void TearDown() override + { + // Flush logger after each test. + srslog::flush(); + } + + std::unique_ptr metrics; + std::unique_ptr f1ap_ue_id_mapper; + std::unique_ptr du_meas_provider; + srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); +}; + +TEST_F(e2sm_kpm_meas_provider_metrics_test, e2sm_kpm_supported_metrics_are_supported) +{ + e2sm_kpm_metric_level_enum metric_level; + meas_type_c meas_type; + meas_label_s meas_label; + meas_label.no_label_present = true; + meas_label.no_label = meas_label_s::no_label_e_::true_value; + bool cell_scope = false; + std::vector supported_metrics; + bool metric_supported = false; + + // E2-NODE-LEVEL metrics + metric_level = E2_NODE_LEVEL; + supported_metrics = du_meas_provider->get_supported_metric_names(metric_level); + for (auto& metric : supported_metrics) { + meas_type.set_meas_name().from_string(metric); + metric_supported = du_meas_provider->is_metric_supported(meas_type, meas_label, metric_level, cell_scope); + ASSERT_TRUE(metric_supported) << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " returned as supported but not supported "; + } + + // UE-LEVEL metrics + metric_level = UE_LEVEL; + supported_metrics = du_meas_provider->get_supported_metric_names(metric_level); + for (auto& metric : supported_metrics) { + meas_type.set_meas_name().from_string(metric); + metric_supported = du_meas_provider->is_metric_supported(meas_type, meas_label, metric_level, cell_scope); + ASSERT_TRUE(metric_supported) << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " returned as supported but not supported "; + } +} + +TEST_F(e2sm_kpm_meas_provider_metrics_test, e2sm_kpm_return_e2_level_metric_with_no_measurements) +{ + // metrics that return no_value when no measurements are present. Specifically, they should not return 0 + std::vector no_value_metrics = {"DRB.AirIfDelayUl", + "DRB.PacketSuccessRateUlgNBUu", + "DRB.RlcDelayUl", + "DRB.RlcPacketDropRateDl", + "DRB.RlcSduDelayDl"}; + + // E2-NODE-LEVEL metrics have to be always returned, even if 0 or NAN + e2sm_kpm_metric_level_enum metric_level = E2_NODE_LEVEL; + meas_type_c meas_type; + std::optional cell_global_id = {}; + e2sm_kpm_metric_t e2sm_kpm_metric_definition; + + label_info_list_l label_info_list; + label_info_item_s label_info_item = {}; + label_info_item.meas_label.no_label_present = true; + label_info_item.meas_label.no_label = meas_label_s::no_label_e_::true_value; + label_info_list.push_back(label_info_item); + std::vector meas_records_items; + + std::vector supported_metrics = du_meas_provider->get_supported_metric_names(metric_level); + for (auto& metric : supported_metrics) { + meas_type.set_meas_name().from_string(metric); + + meas_records_items.clear(); + du_meas_provider->get_meas_data(meas_type, label_info_list, {}, cell_global_id, meas_records_items); + + ASSERT_TRUE(meas_records_items.size() == 1) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " returned no measurements (size=" << meas_records_items.size() << ")"; + + // Check if metric should return no_value when no measurements are present + bool found = std::any_of( + no_value_metrics.begin(), no_value_metrics.end(), [&metric](const std::string& s) { return s == metric; }); + if (found) { + ASSERT_EQ(meas_records_items[0].type(), meas_record_item_c::types::no_value) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " expected to return no_value when no measurements available."; + continue; + } + if (get_metric_definition(metric, e2sm_kpm_metric_definition)) { + if (e2sm_kpm_metric_definition.data_type == e2sm_kpm_metric_dtype_t::INTEGER) { + ASSERT_EQ(meas_records_items[0].type().value, meas_record_item_c::types::integer) + << "Metric: " << e2sm_kpm_metric_definition.name.c_str() << " should return record of the integer type."; + } else { + // e2sm_kpm_metric_dtype_t::REAL + ASSERT_EQ(meas_records_items[0].type().value, meas_record_item_c::types::real) + << "Metric: " << e2sm_kpm_metric_definition.name.c_str() << " should return record of the real type."; + } + } + + switch (meas_records_items[0].type()) { + case meas_record_item_c::types::integer: + ASSERT_EQ(meas_records_items[0].integer(), 0) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level); + break; + case meas_record_item_c::types::real: + ASSERT_FLOAT_EQ(meas_records_items[0].real().value, 0.0) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level); + break; + default: + printf("%s type: %i\n", metric.c_str(), meas_records_items[0].type().value); + ASSERT_TRUE(false) << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " returned a record with wrong type."; + break; + } + } +} + +TEST_F(e2sm_kpm_meas_provider_metrics_test, e2sm_kpm_return_e2_level_metric_with_with_measurements) +{ + // E2-NODE-LEVEL metrics have to be always returned, even if 0 or NAN + e2sm_kpm_metric_level_enum metric_level = E2_NODE_LEVEL; + meas_type_c meas_type; + std::optional cell_global_id = {}; + e2sm_kpm_metric_t e2sm_kpm_metric_definition; + + label_info_list_l label_info_list; + label_info_item_s label_info_item = {}; + label_info_item.meas_label.no_label_present = true; + label_info_item.meas_label.no_label = meas_label_s::no_label_e_::true_value; + label_info_list.push_back(label_info_item); + std::vector meas_records_items; + + // Fill e2sm-kpm measurements provider with RLC and SCHED metrics. + // Generate dummy metrics that will generate non-zero e2sm-kpm metric records. + rlc_metrics rlc_metric = generate_non_zero_rlc_metrics(0, 1); + metrics->report_metrics(rlc_metric); + scheduler_cell_metrics sched_metrics = generate_non_zero_sched_metrics(); + metrics->report_metrics(sched_metrics); + + std::vector supported_metrics = du_meas_provider->get_supported_metric_names(metric_level); + for (auto& metric : supported_metrics) { + meas_type.set_meas_name().from_string(metric); + + meas_records_items.clear(); + du_meas_provider->get_meas_data(meas_type, label_info_list, {}, cell_global_id, meas_records_items); + + ASSERT_TRUE(meas_records_items.size() == 1) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " returned no measurements (size=" << meas_records_items.size() << ")"; + + if (get_metric_definition(metric, e2sm_kpm_metric_definition)) { + if (e2sm_kpm_metric_definition.data_type == e2sm_kpm_metric_dtype_t::INTEGER) { + ASSERT_EQ(meas_records_items[0].type().value, meas_record_item_c::types::integer) + << "Metric: " << e2sm_kpm_metric_definition.name.c_str() << " should return record of the integer type."; + } else { + // e2sm_kpm_metric_dtype_t::REAL + ASSERT_EQ(meas_records_items[0].type().value, meas_record_item_c::types::real) + << "Metric: " << e2sm_kpm_metric_definition.name.c_str() << " should return record of the real type."; + } + } + + switch (meas_records_items[0].type()) { + case meas_record_item_c::types::integer: + ASSERT_NE(meas_records_items[0].integer(), 0) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level); + break; + case meas_record_item_c::types::real: + ASSERT_NE(meas_records_items[0].real().value, 0.0) + << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level); + break; + default: + printf("%s type: %i\n", metric.c_str(), meas_records_items[0].type().value); + ASSERT_TRUE(false) << "Metric: " << metric << " Level: " << e2sm_kpm_scope_2_str(metric_level) + << " returned a record with wrong type."; + break; + } + } +} \ No newline at end of file diff --git a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp index 8f1473ad05..c983dc6ddd 100644 --- a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp @@ -292,8 +292,8 @@ TEST_P(e2sm_kpm_du_meas_provider_test, e2sm_kpm_ind_three_drb_rlc_metrics) uint32_t expected_drop_rate = 10; uint32_t expected_ul_success_rate = 80; - uint32_t expected_dl_throughput = 10000 / 1e3 * 8; - uint32_t expected_ul_throughput = 5000 / 1e3 * 8; + float expected_dl_throughput = 10000 / 1e3 * 8; + float expected_ul_throughput = 5000 / 1e3 * 8; std::vector expected_dl_vol; std::vector expected_ul_vol; @@ -398,10 +398,10 @@ TEST_P(e2sm_kpm_du_meas_provider_test, e2sm_kpm_ind_three_drb_rlc_metrics) TESTASSERT_EQ(expected_ul_success_rate, meas_record[3].integer()); } if (nof_records >= 5) { - TESTASSERT_EQ(expected_dl_throughput, meas_record[4].integer()); + TESTASSERT_EQ(expected_dl_throughput, meas_record[4].real().value); } if (nof_records >= 6) { - TESTASSERT_EQ(expected_ul_throughput, meas_record[5].integer()); + TESTASSERT_EQ(expected_ul_throughput, meas_record[5].real().value); } } } From 37b9f18348f944c7c65b5dd1f752c9d99be58645 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Wed, 30 Oct 2024 12:19:22 +0100 Subject: [PATCH 35/72] phy: retire aligned_vec --- include/srsran/srsvec/aligned_vec.h | 53 ------------ .../dft_processor_fftw_impl.h | 5 +- .../dft_processor_generic_impl.h | 5 +- .../lower/modulation/ofdm_demodulator_impl.h | 5 +- .../lower/modulation/ofdm_modulator_impl.h | 1 - .../uplink/prach/prach_processor_worker.h | 1 - .../polar/polar_decoder_impl.cpp | 14 ++-- .../channel_coding/polar/polar_decoder_impl.h | 15 ++-- .../channel_coding/polar/polar_encoder_impl.h | 1 - .../evm_calculator_generic_impl.cpp | 2 +- .../evm_calculator_generic_impl.h | 3 +- .../prach_generator_impl.cpp | 4 +- .../channel_processors/prach_generator_impl.h | 3 +- ..._phy_rx_symbol_handler_printer_decorator.h | 7 +- lib/srsvec/CMakeLists.txt | 1 - lib/srsvec/aligned_vec.cpp | 27 ------ .../phy/support/resource_grid_test.cpp | 13 ++- .../channel_coding/polar/polar_chain_test.cpp | 17 ++-- .../modulation_mapper_test.cpp | 7 +- .../pseudo_random_generator_test.cpp | 11 ++- tests/unittests/srsvec/CMakeLists.txt | 4 - tests/unittests/srsvec/srsvec_add_test.cpp | 25 +++--- .../unittests/srsvec/srsvec_aligned_test.cpp | 84 ------------------- tests/unittests/srsvec/srsvec_binary_test.cpp | 19 ++--- tests/unittests/srsvec/srsvec_bit_test.cpp | 23 +++-- .../unittests/srsvec/srsvec_clipping_test.cpp | 7 +- .../unittests/srsvec/srsvec_compare_test.cpp | 15 ++-- .../unittests/srsvec/srsvec_convert_test.cpp | 49 ++++++----- .../unittests/srsvec/srsvec_division_test.cpp | 7 +- .../unittests/srsvec/srsvec_dot_prod_test.cpp | 9 +- .../srsvec/srsvec_modulus_square_test.cpp | 5 +- tests/unittests/srsvec/srsvec_prod_test.cpp | 13 ++- .../unittests/srsvec/srsvec_sc_prod_test.cpp | 19 ++--- 33 files changed, 140 insertions(+), 334 deletions(-) delete mode 100644 include/srsran/srsvec/aligned_vec.h delete mode 100644 lib/srsvec/aligned_vec.cpp delete mode 100644 tests/unittests/srsvec/srsvec_aligned_test.cpp diff --git a/include/srsran/srsvec/aligned_vec.h b/include/srsran/srsvec/aligned_vec.h deleted file mode 100644 index 7c6fd7bcd8..0000000000 --- a/include/srsran/srsvec/aligned_vec.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/span.h" - -namespace srsran { -namespace srsvec { - -namespace detail { -void* mem_alloc(std::size_t size); -void mem_free(void* ptr); -} // namespace detail - -/// Type to store a dynamic amount of aligned contiguous elements. -template -class aligned_vec : public span -{ - void dealloc() { detail::mem_free(this->data()); } - -public: - aligned_vec& operator=(aligned_vec&& other) = delete; - aligned_vec& operator=(const aligned_vec& other) = delete; - aligned_vec(const aligned_vec& other) = delete; - aligned_vec(aligned_vec&& other) noexcept = delete; - - aligned_vec() = default; - explicit aligned_vec(std::size_t size) { resize(size); } - ~aligned_vec() { dealloc(); } - - void resize(std::size_t new_size) - { - if (new_size == this->size()) { - return; - } - - dealloc(); - - T* p = reinterpret_cast(detail::mem_alloc(sizeof(T) * new_size)); - span::operator=(span(p, new_size)); - } -}; - -} // namespace srsvec -} // namespace srsran diff --git a/lib/phy/generic_functions/dft_processor_fftw_impl.h b/lib/phy/generic_functions/dft_processor_fftw_impl.h index a56b079489..db2f95a987 100644 --- a/lib/phy/generic_functions/dft_processor_fftw_impl.h +++ b/lib/phy/generic_functions/dft_processor_fftw_impl.h @@ -11,7 +11,6 @@ #pragma once #include "srsran/phy/generic_functions/dft_processor.h" -#include "srsran/srsvec/aligned_vec.h" #include #include #include @@ -89,9 +88,9 @@ class dft_processor_fftw_impl : public dft_processor /// Stores the DFT direction. direction dir; /// DFT input buffer ownership. - srsvec::aligned_vec input; + std::vector input; /// DFT output buffer ownership. - srsvec::aligned_vec output; + std::vector output; /// FFTW actual plan. fftwf_plan plan; diff --git a/lib/phy/generic_functions/dft_processor_generic_impl.h b/lib/phy/generic_functions/dft_processor_generic_impl.h index 20f7ef8a64..3f501c2bfa 100644 --- a/lib/phy/generic_functions/dft_processor_generic_impl.h +++ b/lib/phy/generic_functions/dft_processor_generic_impl.h @@ -11,7 +11,6 @@ #pragma once #include "srsran/phy/generic_functions/dft_processor.h" -#include "srsran/srsvec/aligned_vec.h" namespace srsran { @@ -31,9 +30,9 @@ class dft_processor_generic_impl : public dft_processor /// Stores the DFT direction. direction dir; /// DFT input buffer ownership. - srsvec::aligned_vec input; + std::vector input; /// DFT output buffer ownership. - srsvec::aligned_vec output; + std::vector output; /// Generic FFT. std::unique_ptr generic_dft; diff --git a/lib/phy/lower/modulation/ofdm_demodulator_impl.h b/lib/phy/lower/modulation/ofdm_demodulator_impl.h index b34c776971..7197d1e746 100644 --- a/lib/phy/lower/modulation/ofdm_demodulator_impl.h +++ b/lib/phy/lower/modulation/ofdm_demodulator_impl.h @@ -13,7 +13,6 @@ #include "phase_compensation_lut.h" #include "srsran/phy/generic_functions/dft_processor.h" #include "srsran/phy/lower/modulation/ofdm_demodulator.h" -#include "srsran/srsvec/aligned_vec.h" #include namespace srsran { @@ -47,9 +46,9 @@ class ofdm_symbol_demodulator_impl : public ofdm_symbol_demodulator /// Phase compensation table. phase_compensation_lut phase_compensation_table; /// Internal buffer aimed at storing the phase compensated DFT outputs. - srsvec::aligned_vec compensated_output; + std::vector compensated_output; /// DFT window offset phase compensation. - srsvec::aligned_vec window_phase_compensation; + std::vector window_phase_compensation; public: /// \brief Constructs an OFDM symbol demodulator. diff --git a/lib/phy/lower/modulation/ofdm_modulator_impl.h b/lib/phy/lower/modulation/ofdm_modulator_impl.h index b6acd5dde1..3407201702 100644 --- a/lib/phy/lower/modulation/ofdm_modulator_impl.h +++ b/lib/phy/lower/modulation/ofdm_modulator_impl.h @@ -14,7 +14,6 @@ #include "srsran/phy/generic_functions/dft_processor.h" #include "srsran/phy/lower/modulation/ofdm_modulator.h" #include "srsran/ran/cyclic_prefix.h" -#include "srsran/srsvec/aligned_vec.h" namespace srsran { diff --git a/lib/phy/lower/processors/uplink/prach/prach_processor_worker.h b/lib/phy/lower/processors/uplink/prach/prach_processor_worker.h index 9dcd8cbf91..277eb21d0c 100644 --- a/lib/phy/lower/processors/uplink/prach/prach_processor_worker.h +++ b/lib/phy/lower/processors/uplink/prach/prach_processor_worker.h @@ -21,7 +21,6 @@ #include "srsran/ran/phy_time_unit.h" #include "srsran/ran/prach/prach_constants.h" #include "srsran/srslog/srslog.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/support/executors/task_executor.h" namespace srsran { diff --git a/lib/phy/upper/channel_coding/polar/polar_decoder_impl.cpp b/lib/phy/upper/channel_coding/polar/polar_decoder_impl.cpp index b64588af3b..faa40a087c 100644 --- a/lib/phy/upper/channel_coding/polar/polar_decoder_impl.cpp +++ b/lib/phy/upper/channel_coding/polar/polar_decoder_impl.cpp @@ -81,8 +81,8 @@ void polar_decoder_impl::tmp_node_s::compute(std::vector& node_type, uint8_t code_size_log_1 = code_size_log - 1; uint16_t code_half_size = (1U << code_size_log_1); - srsvec::zero(i_even.first(code_half_size)); - srsvec::zero(i_odd.first(code_half_size)); + srsvec::zero(span(i_even).first(code_half_size)); + srsvec::zero(span(i_odd).first(code_half_size)); for (uint16_t i = 0; i != code_half_size; ++i) { i_even[i] = 2 * i; i_odd[i] = 2 * i + 1; @@ -145,12 +145,12 @@ polar_decoder_impl::polar_decoder_impl(std::unique_ptr enc_, uint llr_alloc.resize(llr_all_stages); // Assign a valid view for the first stage llr0 and an invalid view for llr1. - llr0[0] = llr_alloc.first(1); + llr0[0] = span(llr_alloc).first(1); llr1[0] = span(); // Assign a valid view for the rest of stages llr0 and llr1. for (uint8_t s = 1; s != n_llr_all_stages; ++s) { - llr0[s] = llr_alloc.subspan(param.code_stage_size[s] - 1, param.code_stage_size[s]); + llr0[s] = span(llr_alloc).subspan(param.code_stage_size[s] - 1, param.code_stage_size[s]); llr1[s] = llr0[s].last(param.code_stage_size[s - 1]); } @@ -177,7 +177,7 @@ void polar_decoder_impl::init(span data_decoded, srsvec::zero(data_decoded.first(code_size)); // Initialize est_bit vector to all zeros. - srsvec::zero(est_bit.first(code_size)); + srsvec::zero(span(est_bit).first(code_size)); // Initializes LLR buffer for the last stage/level with the input LLRs values. for (uint16_t i = 0; i != code_half_size; ++i) { @@ -187,7 +187,7 @@ void polar_decoder_impl::init(span data_decoded, // Initializes the state of the decoding tree: start from the only one node at the last stage + 1. state.stage = code_size_log + 1; - srsvec::zero(state.active_node_per_stage.first(code_size_log + 1)); + srsvec::zero(span(state.active_node_per_stage).first(code_size_log + 1)); state.flag_finished = false; // Computes the node types for the decoding tree. @@ -221,7 +221,7 @@ void polar_decoder_impl::rate_1_node(span message) uint16_t code_size = param.code_stage_size[param.code_size_log]; uint16_t code_stage_size = param.code_stage_size[stage]; - span codeword = est_bit.subspan(bit_pos, code_stage_size); + span codeword = span(est_bit).subspan(bit_pos, code_stage_size); srsran_assert(llr0[stage].size() == code_stage_size, "Invalid size ({} != {})", llr0[stage].size(), code_stage_size); vec_hard_bit(llr0[stage], codeword); diff --git a/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h b/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h index 1b1f5454e0..14302d32bd 100644 --- a/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_decoder_impl.h @@ -15,7 +15,6 @@ #include "srsran/phy/upper/channel_coding/polar/polar_decoder.h" #include "srsran/phy/upper/channel_coding/polar/polar_encoder.h" -#include "srsran/srsvec/aligned_vec.h" namespace srsran { @@ -40,7 +39,7 @@ class polar_decoder_impl : public polar_decoder /// \f$log_2\f$ of the code size. uint8_t code_size_log; /// Number of bits of the encoder input/output vector, for all stages. - srsvec::aligned_vec code_stage_size; + std::vector code_stage_size; /// Stores the type of all nodes in stage 0. std::vector node_type_alloc; /// Stores the type of all nodes, stage by stage (e.g., node_type[0] is the same as \c node_type_alloc). @@ -54,21 +53,21 @@ class polar_decoder_impl : public polar_decoder /// True if the last bit is decoded. False otherwise. bool flag_finished; /// Indicates the active node at each stage of the algorithm at a given moment. - srsvec::aligned_vec active_node_per_stage; + std::vector active_node_per_stage; }; /// Structure with pointers needed to obtain the node_type. struct tmp_node_s { /// \brief Denotes whether a node is of type [RATE_0](#polar_decoder_impl::node_rate) (value 0) or of another /// type (value 1). - srsvec::aligned_vec is_not_rate_0; + std::vector is_not_rate_0; /// \brief Denotes whether a node is of type [RATE_1](#polar_decoder_impl::node_rate) (value 1) or of another type /// (value 0). span is_rate_1; /// List of even-valued node indices. - srsvec::aligned_vec i_even; + std::vector i_even; /// List of odd-valued node indices. - srsvec::aligned_vec i_odd; + std::vector i_odd; /// \brief Allocates memory resources for the computation of the node_type. /// \param[in] nMax \f$log_2\f$ of the maximum number of bits in the codeword. @@ -82,13 +81,13 @@ class polar_decoder_impl : public polar_decoder }; /// LLR values for stage 0 (i.e., received LLRs). - srsvec::aligned_vec llr_alloc; + std::vector llr_alloc; /// Pointers to the upper half of the LLR values for all stages. std::vector> llr0; /// Pointers to the lower half of LLR values for all stages. std::vector> llr1; /// Temporary estimated bits. - srsvec::aligned_vec est_bit; + std::vector est_bit; /// Decoder inner parameters. params_s param; /// Decoder state. diff --git a/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h b/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h index de61663341..a35b996bbc 100644 --- a/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h +++ b/lib/phy/upper/channel_coding/polar/polar_encoder_impl.h @@ -13,7 +13,6 @@ #pragma once #include "srsran/phy/upper/channel_coding/polar/polar_encoder.h" -#include "srsran/srsvec/aligned_vec.h" namespace srsran { diff --git a/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.cpp b/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.cpp index ab3ba306d2..4502a008a2 100644 --- a/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.cpp +++ b/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.cpp @@ -43,7 +43,7 @@ float evm_calculator_generic_impl::calculate(span so hard_decision(hard_bits, soft_bits.first(block_nof_bits)); // Modulate. - span modulated = temp_modulated.first(block_nof_symbols); + span modulated = span(temp_modulated).first(block_nof_symbols); modulator->modulate(modulated, hard_bits, modulation); // Calculate EVM. diff --git a/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.h b/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.h index 595b84e7ce..10f02ec468 100644 --- a/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.h +++ b/lib/phy/upper/channel_modulation/evm_calculator_generic_impl.h @@ -12,7 +12,6 @@ #include "srsran/phy/upper/channel_modulation/evm_calculator.h" #include "srsran/phy/upper/channel_modulation/modulation_mapper.h" -#include "srsran/srsvec/aligned_vec.h" namespace srsran { @@ -42,7 +41,7 @@ class evm_calculator_generic_impl : public evm_calculator /// Data after hard-decision. dynamic_bit_buffer temp_hard_bits; /// Modulated data. - srsvec::aligned_vec temp_modulated; + std::vector temp_modulated; }; } // namespace srsran diff --git a/lib/phy/upper/channel_processors/prach_generator_impl.cpp b/lib/phy/upper/channel_processors/prach_generator_impl.cpp index 7da078dfb7..f81e26419b 100644 --- a/lib/phy/upper/channel_processors/prach_generator_impl.cpp +++ b/lib/phy/upper/channel_processors/prach_generator_impl.cpp @@ -173,7 +173,7 @@ span prach_generator_impl::generate_y_u_v_long(unsigned sequence_num 2935, 3355, 419}; // Create view of the sequence. - span y_u_v = sequence.first(LONG); + span y_u_v = span(sequence).first(LONG); // Sequence compression factor and offset. uint64_t factor = static_cast(compression_factor_table[sequence_number]); @@ -219,7 +219,7 @@ span prach_generator_impl::generate_y_u_v_short(unsigned sequence_nu 199, 547, 339, 409, 479, 271, 341, 411, 481, 551, 65, 135, 205, 553, 345, 137, 207, 555, 69}; // Create view of the sequence. - span y_u_v = sequence.first(SHORT); + span y_u_v = span(sequence).first(SHORT); // Sequence compression factor and offset. uint64_t factor = static_cast(compression_factor_table[sequence_number]); diff --git a/lib/phy/upper/channel_processors/prach_generator_impl.h b/lib/phy/upper/channel_processors/prach_generator_impl.h index b7904e3ffb..3c697f124b 100644 --- a/lib/phy/upper/channel_processors/prach_generator_impl.h +++ b/lib/phy/upper/channel_processors/prach_generator_impl.h @@ -12,7 +12,6 @@ #include "srsran/phy/upper/channel_processors/prach_generator.h" #include "srsran/ran/prach/prach_constants.h" -#include "srsran/srsvec/aligned_vec.h" namespace srsran { @@ -33,7 +32,7 @@ class prach_generator_impl : public prach_generator static constexpr unsigned SHORT = prach_constants::SHORT_SEQUENCE_LENGTH; /// Temporary sequence. - srsvec::aligned_vec sequence; + std::vector sequence; /// Calculates sequence number \f$u\f$ as per TS38.211 Table 6.3.3.1-3. static unsigned get_sequence_number_long(unsigned root_sequence_index); diff --git a/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h b/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h index 01b717ccc2..4708e3fd69 100644 --- a/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h +++ b/lib/phy/upper/upper_phy_rx_symbol_handler_printer_decorator.h @@ -12,7 +12,6 @@ #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/support/shared_resource_grid.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/conversion.h" #include "srsran/support/error_handling.h" #include "srsran/support/executors/task_worker.h" @@ -110,7 +109,7 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol span samples = buffer.get_symbol(i_port, 0, 0, i_replica); // Convert samples to complex float. - span samples_cf = temp_prach_buffer.first(samples.size()); + span samples_cf = span(temp_prach_buffer).first(samples.size()); srsvec::convert(samples_cf, samples); // Write file. @@ -142,8 +141,8 @@ class upper_phy_rx_symbol_handler_printer_decorator : public upper_phy_rx_symbol srslog::basic_logger& logger; std::ofstream file; task_worker worker; - srsvec::aligned_vec temp_buffer; - srsvec::aligned_vec temp_prach_buffer; + std::vector temp_buffer; + std::vector temp_prach_buffer; unsigned nof_symbols; unsigned start_port; unsigned end_port; diff --git a/lib/srsvec/CMakeLists.txt b/lib/srsvec/CMakeLists.txt index d9344db894..ff086624c7 100644 --- a/lib/srsvec/CMakeLists.txt +++ b/lib/srsvec/CMakeLists.txt @@ -9,7 +9,6 @@ set(SOURCES accumulate.cpp add.cpp - aligned_vec.cpp bit.cpp clip.cpp compare.cpp diff --git a/lib/srsvec/aligned_vec.cpp b/lib/srsvec/aligned_vec.cpp deleted file mode 100644 index cdf42c26e8..0000000000 --- a/lib/srsvec/aligned_vec.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "srsran/srsvec/aligned_vec.h" -#include "srsran/srsvec/simd.h" -#include "srsran/support/error_handling.h" -#include - -void* srsran::srsvec::detail::mem_alloc(std::size_t size) -{ - void* ptr = nullptr; - int ret = ::posix_memalign(&ptr, SIMD_BYTE_ALIGN * 8, size); - report_fatal_error_if_not(ret == 0 && ptr, "Failed posix_memalign."); - return ptr; -} - -void srsran::srsvec::detail::mem_free(void* ptr) -{ - ::free(ptr); -} diff --git a/tests/unittests/phy/support/resource_grid_test.cpp b/tests/unittests/phy/support/resource_grid_test.cpp index 25ad2fbea7..f6d5698c51 100644 --- a/tests/unittests/phy/support/resource_grid_test.cpp +++ b/tests/unittests/phy/support/resource_grid_test.cpp @@ -11,7 +11,6 @@ #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/support/resource_grid_writer.h" #include "srsran/phy/support/support_factories.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/zero.h" #include "srsran/support/srsran_test.h" #include @@ -78,7 +77,7 @@ void test_mask_bitset(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub // Put elements in grid. unsigned symbol_idx = symbol_dist(rgen); - srsvec::aligned_vec symbols_gold(nof_elements); + std::vector symbols_gold(nof_elements); bounded_bitset mask(nof_subc); // Fill mask and generate symbols. @@ -129,8 +128,8 @@ void test_mask_bitset(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub } // Get elements using the same mask. - srsvec::aligned_vec symbols(nof_elements); - span symbol_buffer_get = grid->get_reader().get(symbols, port_gold, symbol_idx, 0, mask); + std::vector symbols(nof_elements); + span symbol_buffer_get = grid->get_reader().get(symbols, port_gold, symbol_idx, 0, mask); // Make sure all symbols are used. TESTASSERT(symbol_buffer_get.empty(), "Symbol buffer - not empty."); @@ -160,8 +159,8 @@ void test_consecutive(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub unsigned port_gold = port_dist(rgen); // Put elements in grid - unsigned symbol_idx = symbol_dist(rgen); - srsvec::aligned_vec symbols_gold(nof_elements); + unsigned symbol_idx = symbol_dist(rgen); + std::vector symbols_gold(nof_elements); // Select initial subcarrier unsigned k_init = subc_dist(rgen); @@ -201,7 +200,7 @@ void test_consecutive(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub } // Get elements - srsvec::aligned_vec symbols(nof_elements); + std::vector symbols(nof_elements); grid->get_reader().get(symbols, port_gold, symbol_idx, k_init); // Assert symbols diff --git a/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp b/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp index 749e9df4a2..585eb530bc 100644 --- a/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp +++ b/tests/unittests/phy/upper/channel_coding/polar/polar_chain_test.cpp @@ -9,7 +9,6 @@ */ #include "srsran/phy/upper/channel_coding/channel_coding_factories.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/support/srsran_test.h" #include #include @@ -153,7 +152,7 @@ int main(int argc, char** argv) TESTASSERT(rate_dematcher); // Create Tx data and fill - srsvec::aligned_vec data_tx(K); + std::vector data_tx(K); for (uint8_t& v : data_tx) { v = dist(rgen); } @@ -162,32 +161,32 @@ int main(int argc, char** argv) code->set(K, E, nMax, bil); // Allocate TX data - srsvec::aligned_vec allocated_tx(code->get_N()); + std::vector allocated_tx(code->get_N()); allocator->allocate(allocated_tx, data_tx, *code); // Encoder TX data - srsvec::aligned_vec encoded_tx(code->get_N()); + std::vector encoded_tx(code->get_N()); encoder->encode(encoded_tx, allocated_tx, code->get_n()); // Rate matching - srsvec::aligned_vec rate_matched_tx(E); + std::vector rate_matched_tx(E); rate_matcher->rate_match(rate_matched_tx, encoded_tx, *code); // Modulate - srsvec::aligned_vec rate_matched_rx(E); + std::vector rate_matched_rx(E); std::transform( rate_matched_tx.begin(), rate_matched_tx.end(), rate_matched_rx.begin(), [](uint8_t b) { return (1 - 2 * b); }); // Undo rate matching - srsvec::aligned_vec encoded_rx(code->get_N()); + std::vector encoded_rx(code->get_N()); rate_dematcher->rate_dematch(encoded_rx, rate_matched_rx, *code); // Decode Rx data - srsvec::aligned_vec allocated_rx(code->get_N()); + std::vector allocated_rx(code->get_N()); decoder->decode(allocated_rx, encoded_rx, *code); // Deallocate RX data - srsvec::aligned_vec data_rx(K); + std::vector data_rx(K); deallocator->deallocate(data_rx, allocated_rx, *code); // Assert decoded message diff --git a/tests/unittests/phy/upper/channel_modulation/modulation_mapper_test.cpp b/tests/unittests/phy/upper/channel_modulation/modulation_mapper_test.cpp index 0129f89cb4..c97b648ca5 100644 --- a/tests/unittests/phy/upper/channel_modulation/modulation_mapper_test.cpp +++ b/tests/unittests/phy/upper/channel_modulation/modulation_mapper_test.cpp @@ -10,7 +10,6 @@ #include "modulation_mapper_test_data.h" #include "srsran/phy/upper/channel_modulation/channel_modulation_factories.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/bit.h" #include "fmt/ostream.h" #include @@ -89,13 +88,13 @@ TEST_P(ModulationMapperFixture, ModulationMapperTest) srsvec::bit_pack(packed_data, testvector_data); // Modulate in complex float. - srsran::srsvec::aligned_vec symbols_cf(test_case.nsymbols); + std::vector symbols_cf(test_case.nsymbols); modulator->modulate(symbols_cf, packed_data, test_case.scheme); assert_symbols(symbols_cf, expected_symbols); // Modulate in complex i8. - srsran::srsvec::aligned_vec symbols_ci8(test_case.nsymbols); - float scale_ci8 = modulator->modulate(symbols_ci8, packed_data, test_case.scheme); + std::vector symbols_ci8(test_case.nsymbols); + float scale_ci8 = modulator->modulate(symbols_ci8, packed_data, test_case.scheme); assert_symbols(symbols_ci8, expected_symbols, scale_ci8); } } diff --git a/tests/unittests/phy/upper/sequence_generators/pseudo_random_generator_test.cpp b/tests/unittests/phy/upper/sequence_generators/pseudo_random_generator_test.cpp index 84bf2abfd7..5078734e92 100644 --- a/tests/unittests/phy/upper/sequence_generators/pseudo_random_generator_test.cpp +++ b/tests/unittests/phy/upper/sequence_generators/pseudo_random_generator_test.cpp @@ -9,7 +9,6 @@ */ #include "srsran/phy/upper/sequence_generators/sequence_generator_factories.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/bit.h" #include #include @@ -150,7 +149,7 @@ TEST_P(PseudoRandomGeneratorFixture, PseudoRandomGeneratorXorUnpacked) std::uniform_int_distribution distXorUnpacked(0, 1); // Create data buffer. - srsvec::aligned_vec data(size); + std::vector data(size); // Fill buffer with random data. for (unsigned char& v : data) { @@ -164,7 +163,7 @@ TEST_P(PseudoRandomGeneratorFixture, PseudoRandomGeneratorXorUnpacked) generator->advance(offset); // Apply sequence. - srsvec::aligned_vec data_xor(size); + std::vector data_xor(size); generator->apply_xor(data_xor, data); // Assert. @@ -180,7 +179,7 @@ TEST_P(PseudoRandomGeneratorFixture, PseudoRandomGeneratorXori8) log_likelihood_ratio::max().to_value_type()); // Create data buffer. - srsvec::aligned_vec data(size); + std::vector data(size); // Fill buffer with random data. for (log_likelihood_ratio& v : data) { @@ -194,7 +193,7 @@ TEST_P(PseudoRandomGeneratorFixture, PseudoRandomGeneratorXori8) generator->advance(offset); // Apply sequence. - srsvec::aligned_vec data_xor(size); + std::vector data_xor(size); generator->apply_xor(data_xor, data); // Assert. @@ -234,7 +233,7 @@ TEST_P(PseudoRandomGeneratorFixture, PseudoRandomGeneratorBit) TEST_P(PseudoRandomGeneratorFixture, PseudoRandomGeneratorFloat) { // Create data buffer. - srsvec::aligned_vec sequence(size); + std::vector sequence(size); // Initialize sequence generator. generator->init(c_init); diff --git a/tests/unittests/srsvec/CMakeLists.txt b/tests/unittests/srsvec/CMakeLists.txt index fbbfd19d6f..8b435f838c 100644 --- a/tests/unittests/srsvec/CMakeLists.txt +++ b/tests/unittests/srsvec/CMakeLists.txt @@ -10,10 +10,6 @@ add_executable(srsvec_add_test srsvec_add_test.cpp) target_link_libraries(srsvec_add_test srsvec srslog) add_test(srsvec_add_test srsvec_add_test) -add_executable(srsvec_aligned_test srsvec_aligned_test.cpp) -target_link_libraries(srsvec_aligned_test srsvec srslog) -add_test(srsvec_aligned_test srsvec_aligned_test) - add_executable(srsvec_bit_test srsvec_bit_test.cpp) target_link_libraries(srsvec_bit_test srsvec srslog gtest gtest_main) add_test(srsvec_bit_test srsvec_bit_test) diff --git a/tests/unittests/srsvec/srsvec_add_test.cpp b/tests/unittests/srsvec/srsvec_add_test.cpp index 9fb9b0b00d..cdb2a087c0 100644 --- a/tests/unittests/srsvec/srsvec_add_test.cpp +++ b/tests/unittests/srsvec/srsvec_add_test.cpp @@ -9,7 +9,6 @@ */ #include "srsran/srsvec/add.h" -#include "srsran/srsvec/aligned_vec.h" #include "srsran/support/srsran_test.h" #include @@ -23,17 +22,17 @@ void test_cf_add(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = cf_t(dist(rgen), dist(rgen)); } - srsvec::aligned_vec y(N); + std::vector y(N); for (cf_t& v : y) { v = cf_t(dist(rgen), dist(rgen)); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::add(x, y, z); @@ -48,17 +47,17 @@ void test_float_add(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (float& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (float& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::add(x, y, z); @@ -73,17 +72,17 @@ void test_i16_add(std::size_t N) { std::uniform_int_distribution dist(INT16_MIN / 2, INT16_MAX / 2); - srsvec::aligned_vec x(N); + std::vector x(N); for (int16_t& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (int16_t& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::add(x, y, z); @@ -98,17 +97,17 @@ void test_i8_add(std::size_t N) { std::uniform_int_distribution dist(INT8_MIN / 2, INT8_MAX / 2); - srsvec::aligned_vec x(N); + std::vector x(N); for (int8_t& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (int8_t& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::add(x, y, z); diff --git a/tests/unittests/srsvec/srsvec_aligned_test.cpp b/tests/unittests/srsvec/srsvec_aligned_test.cpp deleted file mode 100644 index 5fe3e7e111..0000000000 --- a/tests/unittests/srsvec/srsvec_aligned_test.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "srsran/srsvec/aligned_vec.h" -#include "srsran/srsvec/copy.h" -#include "srsran/srsvec/zero.h" -#include "srsran/support/srsran_test.h" -#include - -using namespace srsran; - -template -void test_resize(std::size_t N) -{ - // Allocate - srsvec::aligned_vec x(N); - - // Resize - x.resize(2 * N); -} - -template -void test_zero(std::size_t N) -{ - // Allocate - srsvec::aligned_vec x(N); - - // Zero - srsvec::zero(x); - - // Verify copy - for (size_t i = 0; i != N; i++) { - TESTASSERT_EQ(x[i], 0); - } -} - -template -void test_copy(std::size_t N) -{ - // Allocate - srsvec::aligned_vec x(N); - - // Fill vector - for (std::size_t i = 0; i != N; i++) { - x[i] = i; - } - - // Allocate and resize - srsvec::aligned_vec y(N); - - // Copy - srsvec::copy(y, x); - - // Verify copy - for (size_t i = 0; i != N; i++) { - TESTASSERT_EQ(x[i], y[i]); - } -} - -int main() -{ - std::vector sizes = {1, 5, 7, 19, 23, 257}; - - for (std::size_t N : sizes) { - test_resize(N); - test_resize(N); - test_resize(N); - - test_zero(N); - test_zero(N); - test_zero(N); - - test_copy(N); - test_copy(N); - test_copy(N); - } -} \ No newline at end of file diff --git a/tests/unittests/srsvec/srsvec_binary_test.cpp b/tests/unittests/srsvec/srsvec_binary_test.cpp index 79df8d44d9..30aab2db7f 100644 --- a/tests/unittests/srsvec/srsvec_binary_test.cpp +++ b/tests/unittests/srsvec/srsvec_binary_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/binary.h" #include "srsran/support/srsran_test.h" #include @@ -22,17 +21,17 @@ void test_binary_xor(std::size_t N) { std::uniform_int_distribution dist(0, RANGE); - srsvec::aligned_vec x(N); + std::vector x(N); for (T& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (T& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::binary_xor(x, y, z); @@ -47,17 +46,17 @@ void test_binary_and(std::size_t N) { std::uniform_int_distribution dist(0, RANGE); - srsvec::aligned_vec x(N); + std::vector x(N); for (T& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (T& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::binary_and(x, y, z); @@ -72,17 +71,17 @@ void test_binary_or(std::size_t N) { std::uniform_int_distribution dist(0, RANGE); - srsvec::aligned_vec x(N); + std::vector x(N); for (T& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (T& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::binary_or(x, y, z); diff --git a/tests/unittests/srsvec/srsvec_bit_test.cpp b/tests/unittests/srsvec/srsvec_bit_test.cpp index 0072643514..979bedbc94 100644 --- a/tests/unittests/srsvec/srsvec_bit_test.cpp +++ b/tests/unittests/srsvec/srsvec_bit_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/bit.h" #include #include @@ -46,7 +45,7 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestUnpack) unsigned value = dist(rgen); // Create destination - srsvec::aligned_vec unpacked(size); + std::vector unpacked(size); // Unpack span bit_buf = srsvec::bit_unpack(unpacked, value, size); @@ -73,10 +72,10 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestUnpackVector) } // Create destination - srsvec::aligned_vec unpacked(nbits); + std::vector unpacked(nbits); // Generate expected values. - srsvec::aligned_vec expected(nbits); + std::vector expected(nbits); std::generate(expected.begin(), expected.end(), [&, index = 0]() mutable { return packed.extract(index++, 1); }); // Unpack @@ -91,7 +90,7 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestPack) std::uniform_int_distribution dist(0, 1U); // Create unpacked data - srsvec::aligned_vec unpacked(size); + std::vector unpacked(size); for (uint8_t& value : unpacked) { value = dist(rgen); } @@ -116,7 +115,7 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestPackVector) std::uniform_int_distribution dist(0, 1U); // Create unpacked data - srsvec::aligned_vec unpacked(nbits); + std::vector unpacked(nbits); for (uint8_t& value : unpacked) { value = dist(rgen); } @@ -139,7 +138,7 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestPackFullVector) std::uniform_int_distribution dist(0, 1U); // Create unpacked data - srsvec::aligned_vec unpacked(size); + std::vector unpacked(size); for (uint8_t& value : unpacked) { value = dist(rgen); } @@ -157,7 +156,7 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestPackOffsetVector) std::uniform_int_distribution dist(0, 1U); // Create unpacked data - srsvec::aligned_vec unpacked(nbits); + std::vector unpacked(nbits); for (uint8_t& value : unpacked) { value = dist(rgen); } @@ -265,10 +264,10 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestUnpackVectorWithRemainder) } // Create destination - srsvec::aligned_vec unpacked(15); + std::vector unpacked(15); // Generate expected values. - srsvec::aligned_vec expected(15); + std::vector expected(15); std::generate(expected.begin(), expected.end(), [&, index = 0]() mutable { return packed.extract(index++, 1); }); // Unpack @@ -290,10 +289,10 @@ TEST_P(SrsvecBitFixture, SrsvecBitTestUnpackVectorOffset) } // Create destination - srsvec::aligned_vec unpacked(nbits - offset); + std::vector unpacked(nbits - offset); // Generate expected values. - srsvec::aligned_vec expected(nbits - offset); + std::vector expected(nbits - offset); std::generate(expected.begin(), expected.end(), [&, index = offset]() mutable { return packed.extract(index++, 1); }); // Unpack diff --git a/tests/unittests/srsvec/srsvec_clipping_test.cpp b/tests/unittests/srsvec/srsvec_clipping_test.cpp index 4f09383637..e14add1471 100644 --- a/tests/unittests/srsvec/srsvec_clipping_test.cpp +++ b/tests/unittests/srsvec/srsvec_clipping_test.cpp @@ -11,7 +11,6 @@ /// \file /// \brief Unit test for the clipping functions in the \c srsvec vector library. -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/clip.h" #include "srsran/support/srsran_test.h" #include @@ -21,9 +20,9 @@ static const float ASSERT_MAX_ERROR = 1e-6; using namespace srsran; -static srsvec::aligned_vec input; -static srsvec::aligned_vec output; -static srsvec::aligned_vec output_gold; +static std::vector input; +static std::vector output; +static std::vector output_gold; static void setup(std::size_t nof_samples, const float max_amplitude) { diff --git a/tests/unittests/srsvec/srsvec_compare_test.cpp b/tests/unittests/srsvec/srsvec_compare_test.cpp index cd3797e28f..cf862d1584 100644 --- a/tests/unittests/srsvec/srsvec_compare_test.cpp +++ b/tests/unittests/srsvec/srsvec_compare_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/compare.h" #include "srsran/support/math/math_utils.h" #include "srsran/support/srsran_test.h" @@ -22,14 +21,14 @@ static void test_max_abs_ccc(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = {dist(rgen), dist(rgen)}; } std::pair result = srsvec::max_abs_element(x); - cf_t* expected_it = std::max_element(x.begin(), x.end(), [](cf_t a, cf_t b) { return abs_sq(a) < abs_sq(b); }); + auto expected_it = std::max_element(x.begin(), x.end(), [](cf_t a, cf_t b) { return abs_sq(a) < abs_sq(b); }); unsigned expected_max_index = static_cast(expected_it - x.begin()); float expected_max_value = abs_sq(*expected_it); @@ -41,7 +40,7 @@ static void test_max_abs_ccc_same(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); std::fill(x.begin(), x.end(), 0); std::pair result = srsvec::max_abs_element(x); @@ -54,14 +53,14 @@ static void test_max_f(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (float& v : x) { v = dist(rgen); } std::pair result = srsvec::max_element(x); - float* expected_it = std::max_element(x.begin(), x.end()); + auto expected_it = std::max_element(x.begin(), x.end()); unsigned expected_max_index = static_cast(expected_it - x.begin()); float expected_max_value = *expected_it; @@ -71,7 +70,7 @@ static void test_max_f(std::size_t N) static void test_max_f_same(std::size_t N) { - srsvec::aligned_vec x(N); + std::vector x(N); std::fill(x.begin(), x.end(), 0); std::pair result = srsvec::max_element(x); @@ -85,7 +84,7 @@ static void test_count_if_part_abs_greater_than(std::size_t N) float threshold = 0.5; std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); std::generate(x.begin(), x.end(), [&dist]() { return cf_t{dist(rgen), dist(rgen)}; }); unsigned result = srsvec::count_if_part_abs_greater_than(x, threshold); diff --git a/tests/unittests/srsvec/srsvec_convert_test.cpp b/tests/unittests/srsvec/srsvec_convert_test.cpp index 0b207c06a9..132a882d45 100644 --- a/tests/unittests/srsvec/srsvec_convert_test.cpp +++ b/tests/unittests/srsvec/srsvec_convert_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/conversion.h" #include "srsran/support/srsran_test.h" #include @@ -54,12 +53,12 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestComplexInt16) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(size); + std::vector x(size); for (cf_t& v : x) { v = cf_t(dist(rgen), dist(rgen)); } - srsvec::aligned_vec z(2 * size); + std::vector z(2 * size); float scale = 1000.0F; @@ -77,12 +76,12 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestInt16Complex) { std::uniform_int_distribution dist(INT16_MIN, INT16_MAX); - srsvec::aligned_vec x(2 * size); + std::vector x(2 * size); for (int16_t& v : x) { v = dist(rgen); } - srsvec::aligned_vec z(size); + std::vector z(size); float scale = 1000.0F; @@ -99,12 +98,12 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestFloatInt16) { std::uniform_real_distribution dist(-1, 1); - srsvec::aligned_vec x(size); + std::vector x(size); for (float& v : x) { v = dist(rgen); } - srsvec::aligned_vec z(size); + std::vector z(size); float scale = 1000.0F; @@ -120,12 +119,12 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestInt16Float) { std::uniform_int_distribution dist(INT16_MIN, INT16_MAX); - srsvec::aligned_vec x(size); + std::vector x(size); for (int16_t& v : x) { v = dist(rgen); } - srsvec::aligned_vec z(size); + std::vector z(size); float scale = 1000.0F; @@ -143,11 +142,11 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestComplexComplex16Random) static constexpr float range = std::numeric_limits::max() / 2; std::uniform_real_distribution dist(-range, range); - srsvec::aligned_vec in(size); + std::vector in(size); std::generate(in.begin(), in.end(), [&dist]() { return cf_t(dist(rgen), dist(rgen)); }); - srsvec::aligned_vec out(size); - srsvec::aligned_vec data_cbf16(size); + std::vector out(size); + std::vector data_cbf16(size); // Convert from single precission to BF16. srsvec::convert(data_cbf16, in); @@ -178,14 +177,14 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestComplexComplex16Special) static const std::vector values = {nan, infinity, neg_infinity, one_round_down, one_round_up}; static const std::vector expected_values = {0x7fc0, 0x7f80, 0xff80, 0x3f80, 0x3f82}; - srsvec::aligned_vec in(size); + std::vector in(size); std::generate(in.begin(), in.end(), [n = 0]() mutable { float re = values[(n++) % values.size()]; float im = values[(n++) % values.size()]; return cf_t(re, im); }); - srsvec::aligned_vec data_cbf16(size); + std::vector data_cbf16(size); // Convert from single precission to BF16. srsvec::convert(data_cbf16, in); @@ -203,11 +202,11 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestFloatFloat16Random) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec in(size); + std::vector in(size); std::generate(in.begin(), in.end(), [&dist]() { return dist(rgen); }); // Convert from single precision to brain float. - srsvec::aligned_vec data_bf16(size); + std::vector data_bf16(size); srsvec::convert(data_bf16, in); // Assert conversion to BF16. @@ -216,7 +215,7 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestFloatFloat16Random) } // Convert back to single precision float. - srsvec::aligned_vec out(size); + std::vector out(size); srsvec::convert(out, data_bf16); // Assert conversion from BF16. @@ -232,15 +231,15 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestInt16Float16Random) float int16_scale = (1 << 15) - 1; - srsvec::aligned_vec in(size); + std::vector in(size); std::generate(in.begin(), in.end(), [&dist]() { return dist(rgen); }); // Convert from single precision to int16. - srsvec::aligned_vec in_int16(size); + std::vector in_int16(size); srsvec::convert(in, int16_scale, in_int16); // Convert from int16 to brain float. - srsvec::aligned_vec data_bf16(size); + std::vector data_bf16(size); srsvec::convert(data_bf16, in_int16, int16_scale); // Assert conversion to BF16. @@ -249,7 +248,7 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestInt16Float16Random) } // Convert from brain float back to int16. - srsvec::aligned_vec out_int16(size); + std::vector out_int16(size); srsvec::convert(out_int16, data_bf16, int16_scale); // Assert conversion from BF16. @@ -258,7 +257,7 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestInt16Float16Random) } // Convert int16 to float and compare with original data. - srsvec::aligned_vec out(size); + std::vector out(size); srsvec::convert(out_int16, int16_scale, out); for (size_t i = 0; i != size; ++i) { @@ -276,14 +275,14 @@ TEST_P(SrsvecConvertFixture, SrsvecConvertTestScaledInt16ComplexFloat16Random) const unsigned size_i16 = size * 2; - srsvec::aligned_vec in(size_i16); - srsvec::aligned_vec gain(size_i16); + std::vector in(size_i16); + std::vector gain(size_i16); std::generate(in.begin(), in.end(), [&dist_i]() { return dist_i(rgen); }); std::generate(gain.begin(), gain.end(), [&dist_f]() { return int16_gain * float(dist_f(rgen)); }); // Convert from int16 to brain float. - srsvec::aligned_vec data_cbf16(size); + std::vector data_cbf16(size); srsvec::convert(data_cbf16, in, gain); // Assert conversion to cbf16. diff --git a/tests/unittests/srsvec/srsvec_division_test.cpp b/tests/unittests/srsvec/srsvec_division_test.cpp index 5829aa7d9d..da87d322b2 100644 --- a/tests/unittests/srsvec/srsvec_division_test.cpp +++ b/tests/unittests/srsvec/srsvec_division_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/division.h" #include "srsran/support/srsran_test.h" #include @@ -22,17 +21,17 @@ void test_divide_fff(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec num(N); + std::vector num(N); for (float& v : num) { v = dist(rgen); } - srsvec::aligned_vec den(N); + std::vector den(N); for (float& v : den) { v = dist(rgen); } - srsvec::aligned_vec result(N); + std::vector result(N); srsvec::divide(result, num, den); diff --git a/tests/unittests/srsvec/srsvec_dot_prod_test.cpp b/tests/unittests/srsvec/srsvec_dot_prod_test.cpp index 525fd47e2f..78ad193a7e 100644 --- a/tests/unittests/srsvec/srsvec_dot_prod_test.cpp +++ b/tests/unittests/srsvec/srsvec_dot_prod_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/dot_prod.h" #include "srsran/support/srsran_test.h" #include @@ -22,12 +21,12 @@ static void test_dot_prod_ccc(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = {dist(rgen), dist(rgen)}; } - srsvec::aligned_vec y(N); + std::vector y(N); for (cf_t& v : y) { v = {dist(rgen), dist(rgen)}; } @@ -51,7 +50,7 @@ static void test_avg_power_cf(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = {dist(rgen), dist(rgen)}; } @@ -77,7 +76,7 @@ static void test_avg_power_cbf16(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cbf16_t& v : x) { v = cbf16_t(dist(rgen), dist(rgen)); } diff --git a/tests/unittests/srsvec/srsvec_modulus_square_test.cpp b/tests/unittests/srsvec/srsvec_modulus_square_test.cpp index afc2e79be2..f014d7796a 100644 --- a/tests/unittests/srsvec/srsvec_modulus_square_test.cpp +++ b/tests/unittests/srsvec/srsvec_modulus_square_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/modulus_square.h" #include "srsran/support/math/math_utils.h" #include "srsran/support/srsran_test.h" @@ -23,12 +22,12 @@ void test_modulus_square(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec input(N); + std::vector input(N); for (cf_t& v : input) { v = {dist(rgen), dist(rgen)}; } - srsvec::aligned_vec result(N); + std::vector result(N); srsvec::modulus_square(result, input); diff --git a/tests/unittests/srsvec/srsvec_prod_test.cpp b/tests/unittests/srsvec/srsvec_prod_test.cpp index a926e1cb2e..62f3021b2f 100644 --- a/tests/unittests/srsvec/srsvec_prod_test.cpp +++ b/tests/unittests/srsvec/srsvec_prod_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/prod.h" #include "srsran/support/srsran_test.h" #include @@ -22,17 +21,17 @@ void test_prod_ccc(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = {dist(rgen), dist(rgen)}; } - srsvec::aligned_vec y(N); + std::vector y(N); for (cf_t& v : y) { v = {dist(rgen), dist(rgen)}; } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::prod(x, y, z); @@ -47,17 +46,17 @@ void test_prod_fff(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (float& v : x) { v = dist(rgen); } - srsvec::aligned_vec y(N); + std::vector y(N); for (float& v : y) { v = dist(rgen); } - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::prod(x, y, z); diff --git a/tests/unittests/srsvec/srsvec_sc_prod_test.cpp b/tests/unittests/srsvec/srsvec_sc_prod_test.cpp index 38d34a8992..e71fa33cc0 100644 --- a/tests/unittests/srsvec/srsvec_sc_prod_test.cpp +++ b/tests/unittests/srsvec/srsvec_sc_prod_test.cpp @@ -8,7 +8,6 @@ * */ -#include "srsran/srsvec/aligned_vec.h" #include "srsran/srsvec/sc_prod.h" #include "srsran/support/srsran_test.h" #include @@ -22,14 +21,14 @@ void test_sc_prod_ccc(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = {dist(rgen), dist(rgen)}; } cf_t h = {dist(rgen), dist(rgen)}; - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::sc_prod(x, h, z); @@ -44,16 +43,16 @@ void test_sc_prod_ccc_bf16(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); std::generate(x.begin(), x.end(), [&dist]() { return to_cbf16(cf_t{dist(rgen), dist(rgen)}); }); cf_t h = {dist(rgen), dist(rgen)}; - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::sc_prod(x, h, z); - srsvec::aligned_vec expected(N); + std::vector expected(N); std::transform(x.begin(), x.end(), expected.begin(), [&h](cbf16_t value) { return h * to_cf(value); }); for (size_t i = 0; i != N; i++) { @@ -67,14 +66,14 @@ void test_sc_prod_cfc(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (cf_t& v : x) { v = {dist(rgen), dist(rgen)}; } float h = dist(rgen); - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::sc_prod(x, h, z); @@ -89,14 +88,14 @@ void test_sc_prod_fff(std::size_t N) { std::uniform_real_distribution dist(-1.0, 1.0); - srsvec::aligned_vec x(N); + std::vector x(N); for (float& v : x) { v = dist(rgen); } float h = dist(rgen); - srsvec::aligned_vec z(N); + std::vector z(N); srsvec::sc_prod(x, h, z); From 15936163c04b7a7f31ee4182c755f804bbbc8bf6 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 5 Nov 2024 10:46:55 +0100 Subject: [PATCH 36/72] phy: replace usages of avx load with loadu in conversion.cpp --- lib/srsvec/conversion.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index f5b2d9c724..51ede5dc07 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -351,8 +351,8 @@ static void convert_scaled_int16_to_bf16_simd(bf16_t* out, const int16_t* in, co __m256i input_vec_2 = _mm256_loadu_si256(reinterpret_cast(in + i + 16)); // Load the scale factor into a vector register. - __m512 scale_vec_1 = _mm512_load_ps(in_gain + i); - __m512 scale_vec_2 = _mm512_load_ps(in_gain + i + 16); + __m512 scale_vec_1 = _mm512_loadu_ps(in_gain + i); + __m512 scale_vec_2 = _mm512_loadu_ps(in_gain + i + 16); // Convert the int16_t elements to float and scale them. __m512 float_vec_1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(input_vec_1)); @@ -370,7 +370,7 @@ static void convert_scaled_int16_to_bf16_simd(bf16_t* out, const int16_t* in, co __m256i input_vec = _mm256_loadu_si256(reinterpret_cast(in + i)); // Load the scale factor into a vector register. - __m512 scale_vec = _mm512_load_ps(in_gain + i); + __m512 scale_vec = _mm512_loadu_ps(in_gain + i); // Convert the int16_t elements to float and scale them. __m512 float_vec = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(input_vec)); @@ -417,8 +417,8 @@ static void convert_scaled_int16_to_bf16_simd(bf16_t* out, const int16_t* in, co __m128i input_vec_2 = _mm_loadu_si128(reinterpret_cast(in + i + 8)); // Load the scale factor into a vector register. - __m256 scale_vec_1 = _mm256_load_ps(in_gain + i); - __m256 scale_vec_2 = _mm256_load_ps(in_gain + i + 8); + __m256 scale_vec_1 = _mm256_loadu_ps(in_gain + i); + __m256 scale_vec_2 = _mm256_loadu_ps(in_gain + i + 8); // Convert the int16_t elements to float and scale them __m256 float_vec_1 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(input_vec_1)); From 834a828821f43c2774c2cea39052997a27f4796d Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 30 Oct 2024 13:01:15 +0000 Subject: [PATCH 37/72] cu_cp: store and propragate NCC --- include/srsran/security/security.h | 3 +++ .../routines/mobility/intra_cu_handover_routine.cpp | 4 ++-- .../pdu_session_resource_modification_routine.cpp | 2 +- .../routines/pdu_session_resource_release_routine.cpp | 2 +- .../routines/pdu_session_resource_setup_routine.cpp | 2 +- lib/cu_cp/routines/pdu_session_routine_helpers.cpp | 6 +++--- lib/cu_cp/routines/pdu_session_routine_helpers.h | 2 +- .../reestablishment_context_modification_routine.cpp | 2 +- .../ue_security_manager/ue_security_manager_impl.cpp | 9 +++++++-- lib/cu_cp/ue_security_manager/ue_security_manager_impl.h | 3 ++- lib/ngap/ngap_asn1_converters.h | 2 +- 11 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/srsran/security/security.h b/include/srsran/security/security.h index dc98d71826..919d7e3cf3 100644 --- a/include/srsran/security/security.h +++ b/include/srsran/security/security.h @@ -180,6 +180,7 @@ using sec_short_mac_i = std::array; struct security_context { srslog::basic_logger& logger = srslog::fetch_basic_logger("SEC"); security::sec_key k; + uint8_t ncc = 0; security::supported_algorithms supported_int_algos; security::supported_algorithms supported_enc_algos; sec_selected_algos sel_algos; @@ -189,6 +190,7 @@ struct security_context { ~security_context() = default; security_context(const security_context& sec_ctxt) : k(sec_ctxt.k), + ncc(sec_ctxt.ncc), supported_int_algos(sec_ctxt.supported_int_algos), supported_enc_algos(sec_ctxt.supported_enc_algos), sel_algos(sec_ctxt.sel_algos), @@ -201,6 +203,7 @@ struct security_context { return *this; } k = sec_ctxt.k; + ncc = sec_ctxt.ncc; supported_int_algos = sec_ctxt.supported_int_algos; supported_enc_algos = sec_ctxt.supported_enc_algos; sel_algos = sec_ctxt.sel_algos; diff --git a/lib/cu_cp/routines/mobility/intra_cu_handover_routine.cpp b/lib/cu_cp/routines/mobility/intra_cu_handover_routine.cpp index 6252030fbe..9bf1b5064f 100644 --- a/lib/cu_cp/routines/mobility/intra_cu_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/intra_cu_handover_routine.cpp @@ -188,7 +188,7 @@ void intra_cu_handover_routine::operator()(coro_contextget_rrc_ue()->generate_meas_config(source_rrc_context.meas_cfg), true, /* Reestablish SRBs */ true /* Reestablish DRBs */, - true, /* Update keys */ + target_ue->get_security_manager().get_ncc(), /* Update keys */ target_cell_sib1.copy(), logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", request.source_ue_index, name()); @@ -326,4 +326,4 @@ bool intra_cu_handover_routine::add_security_context_to_bearer_context_modificat } return true; -} \ No newline at end of file +} diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index c976b681cd..5194fb3a02 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -165,7 +165,7 @@ void pdu_session_resource_modification_routine::operator()( rrc_ue->generate_meas_config(), false, false, - false, + {}, {}, logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", modify_request.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp index 1e20eb20b1..8e04703a1b 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -134,7 +134,7 @@ void pdu_session_resource_release_routine::operator()( rrc_ue->generate_meas_config(), false, false, - false, + {}, {}, logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", release_cmd.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 49950c8242..a3257b70f6 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -221,7 +221,7 @@ void pdu_session_resource_setup_routine::operator()( : std::optional{}, false, false, - false, + {}, {}, logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", setup_msg.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index 677fcda8aa..d92dccd178 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -67,7 +67,7 @@ bool srsran::srs_cu_cp::fill_rrc_reconfig_args( const std::optional rrc_meas_cfg, bool reestablish_srbs, bool reestablish_drbs, - bool update_keys, + std::optional ncc, byte_buffer sib1, const srslog::basic_logger& logger) { @@ -157,10 +157,10 @@ bool srsran::srs_cu_cp::fill_rrc_reconfig_args( rrc_recfg_v1530_ies.ded_nas_msg_list.push_back(nas_pdu.copy()); } - if (update_keys) { + if (ncc.has_value()) { rrc_recfg_v1530_ies.master_key_upd.emplace(); rrc_recfg_v1530_ies.master_key_upd.value().key_set_change_ind = false; - rrc_recfg_v1530_ies.master_key_upd.value().next_hop_chaining_count = 0; // TODO: remove hard-coded value + rrc_recfg_v1530_ies.master_key_upd.value().next_hop_chaining_count = ncc.value(); // TODO: remove hard-coded value } rrc_reconfig_args.non_crit_ext = rrc_recfg_v1530_ies; diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index 6a9063f4d6..4d25dc5f05 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -91,7 +91,7 @@ bool fill_rrc_reconfig_args(rrc_reconfiguration_procedure_request& const std::optional rrc_meas_cfg, bool reestablish_srbs, bool reestablish_drbs, - bool update_keys, + std::optional ncc, byte_buffer sib1, const srslog::basic_logger& logger); diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 2d8254305f..b9c855e9ba 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -127,7 +127,7 @@ void reestablishment_context_modification_routine::operator()(coro_context Date: Thu, 31 Oct 2024 12:20:47 +0000 Subject: [PATCH 38/72] cu_cp: use std::nullopt to indicate no NCC --- .../routines/pdu_session_resource_modification_routine.cpp | 2 +- lib/cu_cp/routines/pdu_session_resource_release_routine.cpp | 2 +- lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp | 2 +- .../routines/reestablishment_context_modification_routine.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index 5194fb3a02..ae6db7dc52 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -165,7 +165,7 @@ void pdu_session_resource_modification_routine::operator()( rrc_ue->generate_meas_config(), false, false, - {}, + std::nullopt, {}, logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", modify_request.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp index 8e04703a1b..586be011ca 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -134,7 +134,7 @@ void pdu_session_resource_release_routine::operator()( rrc_ue->generate_meas_config(), false, false, - {}, + std::nullopt, {}, logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", release_cmd.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index a3257b70f6..a5c9e0a429 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -221,7 +221,7 @@ void pdu_session_resource_setup_routine::operator()( : std::optional{}, false, false, - {}, + std::nullopt, {}, logger)) { logger.warning("ue={}: \"{}\" Failed to fill RrcReconfiguration", setup_msg.ue_index, name()); diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index b9c855e9ba..f77e4b2ee1 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -127,7 +127,7 @@ void reestablishment_context_modification_routine::operator()(coro_context Date: Tue, 5 Nov 2024 10:29:12 +0100 Subject: [PATCH 39/72] rlc_tx_am: delete status PDU in UE executor... ...after processing via pcell executor. --- lib/rlc/rlc_tx_am_entity.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index 033bf7d2be..f85cd4710a 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -642,6 +642,20 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_ trace_point status_tp = l2_tracer.now(); auto t_start = std::chrono::high_resolution_clock::now(); + auto on_function_exit = make_scope_exit([&]() { + auto t_end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(t_end - t_start); + logger.log_info("Handled status report. t={}us {}", duration.count(), status); + + // redirect deletion of status report to UE executor + auto delete_status_pdu_func = [status = std::move(status)]() mutable { + // leaving this scope will implicitly delete the status PDU + }; + if (not ue_executor.execute(std::move(delete_status_pdu_func))) { + logger.log_error("Unable to delete status report in UE executor. Deleting from pcell executor"); + } + }); + /* * Sanity check the received status report. * 1. Checking if the ACK_SN is inside the valid ACK_SN window (the TX window "off-by-one") @@ -675,12 +689,6 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_ } } - auto on_function_exit = make_scope_exit([&]() { - auto t_end = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(t_end - t_start); - logger.log_info("Handled status report. t={}us {}", duration.count(), status); - }); - /** * Section 5.3.3.3: Reception of a STATUS report * - if the STATUS report comprises a positive or negative acknowledgement for the RLC SDU with sequence From 5cf81b5e8e01c973eeefe4207ad757e2c5f0a0ee Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 4 Nov 2024 22:20:06 +0100 Subject: [PATCH 40/72] ran: improve NSSAI types to avoid ambiguity --- apps/gnb/gnb.cpp | 8 ++- apps/units/cu_cp/cu_cp_config_translators.cpp | 10 ++- apps/units/cu_cp/cu_cp_unit_config.h | 7 ++- .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 2 +- .../cu_cp/cu_cp_unit_config_yaml_writer.cpp | 10 +-- .../o_du_high/du_high/du_high_config.h | 6 +- .../du_high/du_high_config_cli11_schema.cpp | 6 +- .../du_high/du_high_config_translators.cpp | 2 +- include/srsran/ran/s_nssai.h | 61 +++++++++++++++++-- lib/e1ap/common/e1ap_asn1_converters.h | 6 +- lib/e1ap/common/e1ap_asn1_helpers.h | 2 +- .../e2sm_rc_control_action_du_executor.cpp | 12 ++-- lib/f1ap/asn1_helpers.cpp | 6 +- .../du/procedures/f1ap_du_setup_procedure.cpp | 6 +- lib/ngap/ngap_asn1_converters.h | 6 +- lib/ngap/ngap_asn1_helpers.h | 5 +- .../cu_up/pdu_session_manager_test.h | 2 +- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 2 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 2 +- 19 files changed, 113 insertions(+), 48 deletions(-) diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 136ceb8185..4c48f05516 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -152,8 +152,9 @@ static void autoderive_slicing_args(du_high_unit_config& du_hi_cfg, cu_cp_unit_c std::vector du_slices; for (const auto& cell_cfg : du_hi_cfg.cells_cfg) { for (const auto& slice : cell_cfg.cell.slice_cfg) { - if (du_slices.end() == std::find(du_slices.begin(), du_slices.end(), slice.s_nssai)) { - du_slices.push_back(slice.s_nssai); + s_nssai_t nssai{slice.sst, slice_differentiator::create(slice.sd).value()}; + if (du_slices.end() == std::find(du_slices.begin(), du_slices.end(), nssai)) { + du_slices.push_back(nssai); } } } @@ -220,7 +221,8 @@ int main(int argc, char** argv) // If test mode is enabled, we auto-enable "no_core" option and generate a amf config with no core. if (du_app_unit->get_du_high_unit_config().is_testmode_enabled()) { cu_cp_app_unit->get_cu_cp_unit_config().amf_config.no_core = true; - cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf.supported_tas = {{7, {{"00101", {s_nssai_t{1}}}}}}; + cu_cp_app_unit->get_cu_cp_unit_config().amf_config.amf.supported_tas = { + {7, {{"00101", {cu_cp_unit_plmn_item::tai_slice_t{1}}}}}}; } cu_cp_app_unit->on_configuration_parameters_autoderivation(app); diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index dafbc2f15a..596c2317d9 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -337,7 +337,10 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co for (const auto& plmn_item : supported_ta.plmn_list) { expected plmn = plmn_identity::parse(plmn_item.plmn_id); srsran_assert(plmn.has_value(), "Invalid PLMN: {}", plmn_item.plmn_id); - plmn_list.push_back({plmn.value(), plmn_item.tai_slice_support_list}); + plmn_list.push_back({plmn.value(), {}}); + for (const auto& elem : plmn_item.tai_slice_support_list) { + plmn_list.back().slice_support_list.push_back({elem.sst, slice_differentiator::create(elem.sd).value()}); + } } supported_tas.push_back({supported_ta.tac, plmn_list}); } @@ -351,7 +354,10 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co for (const auto& plmn_item : supported_ta.plmn_list) { expected plmn = plmn_identity::parse(plmn_item.plmn_id); srsran_assert(plmn.has_value(), "Invalid PLMN: {}", plmn_item.plmn_id); - plmn_list.push_back({plmn.value(), plmn_item.tai_slice_support_list}); + plmn_list.push_back({plmn.value(), {}}); + for (const auto& elem : plmn_item.tai_slice_support_list) { + plmn_list.back().slice_support_list.push_back({elem.sst, slice_differentiator::create(elem.sd).value()}); + } } supported_tas.push_back({supported_ta.tac, plmn_list}); } diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index 3d42f3e4b8..6e8906c753 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -22,9 +22,14 @@ namespace srsran { struct cu_cp_unit_plmn_item { + struct tai_slice_t { + uint8_t sst = 0; + uint32_t sd = 0xffffffU; + }; + std::string plmn_id; /// Supported Slices by the RAN node. - std::vector tai_slice_support_list; + std::vector tai_slice_support_list; }; struct cu_cp_unit_supported_ta_item { diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp index b89b65231d..2ad46b610b 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -50,7 +50,7 @@ static void configure_cli11_pcap_args(CLI::App& app, cu_cp_unit_pcap_config& pca add_option(app, "--e1ap_enable", pcap_params.e1ap.enabled, "Enable E1AP packet capture")->always_capture_default(); } -static void configure_cli11_tai_slice_support_args(CLI::App& app, s_nssai_t& config) +static void configure_cli11_tai_slice_support_args(CLI::App& app, cu_cp_unit_plmn_item::tai_slice_t& config) { add_option(app, "--sst", config.sst, "Slice Service Type")->capture_default_str()->check(CLI::Range(0, 255)); add_option(app, "--sd", config.sd, "Service Differentiator")->capture_default_str()->check(CLI::Range(0, 0xffffff)); diff --git a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp index 9df2675667..58cb2f291a 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp @@ -14,13 +14,13 @@ using namespace srsran; -static YAML::Node build_cu_cp_tai_slice_section(const s_nssai_t& config) +static YAML::Node build_cu_cp_tai_slice_section(const cu_cp_unit_plmn_item::tai_slice_t& config) { YAML::Node node; - node["sst"] = static_cast(config.sst); + node["sst"] = config.sst; if (config.sd) { - node["sd"] = config.sd.value(); + node["sd"] = config.sd; } return node; @@ -382,8 +382,8 @@ static void build_cu_cp_slicing_section(YAML::Node node, span s { for (const auto& slice : slice_cfg) { YAML::Node node_entry; - node_entry["sst"] = static_cast(slice.sst); - if (slice.sd) { + node_entry["sst"] = slice.sst.value(); + if (slice.sd.is_set()) { node_entry["sd"] = slice.sd.value(); } node["slicing"].push_back(node_entry); diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_du/o_du_high/du_high/du_high_config.h index 01a8c52f5a..58cb6b3417 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config.h @@ -559,8 +559,10 @@ struct du_high_unit_cell_slice_sched_config { /// Slice configuration for a cell. struct du_high_unit_cell_slice_config { - /// Slice identifier. - s_nssai_t s_nssai = s_nssai_t{1}; + /// Slice/Service Type. + uint8_t sst; + /// Slice Differentiator. + uint32_t sd; /// Slice scheduling configuration. du_high_unit_cell_slice_sched_config sched_cfg; }; diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 227315946a..b1dabcfa8d 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -1160,10 +1160,8 @@ static void configure_cli11_slicing_scheduling_args(CLI::App& static void configure_cli11_slicing_args(CLI::App& app, du_high_unit_cell_slice_config& slice_params) { - add_option(app, "--sst", slice_params.s_nssai.sst, "Slice Service Type") - ->capture_default_str() - ->check(CLI::Range(0, 255)); - add_option(app, "--sd", slice_params.s_nssai.sd, "Service Differentiator") + add_option(app, "--sst", slice_params.sst, "Slice Service Type")->capture_default_str()->check(CLI::Range(0, 255)); + add_option(app, "--sd", slice_params.sd, "Service Differentiator") ->capture_default_str() ->check(CLI::Range(0, 0xffffff)); diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp index b4cc1d4ab1..12b62af3c2 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp @@ -709,7 +709,7 @@ srsran::generate_du_slicing_rrm_policy_config(span for (const auto& plmn : plmns) { for (const auto& cfg : slice_cfg) { rrm_policy_cfgs.emplace_back(); - rrm_policy_cfgs.back().rrc_member.s_nssai = cfg.s_nssai; + rrm_policy_cfgs.back().rrc_member.s_nssai = {cfg.sst, slice_differentiator::create(cfg.sd).value()}; rrm_policy_cfgs.back().rrc_member.plmn_id = plmn_identity::parse(plmn).value(); rrm_policy_cfgs.back().min_prb = (nof_cell_crbs * cfg.sched_cfg.min_prb_policy_ratio) / 100; rrm_policy_cfgs.back().max_prb = (nof_cell_crbs * cfg.sched_cfg.max_prb_policy_ratio) / 100; diff --git a/include/srsran/ran/s_nssai.h b/include/srsran/ran/s_nssai.h index ef7633961c..3414a359ef 100644 --- a/include/srsran/ran/s_nssai.h +++ b/include/srsran/ran/s_nssai.h @@ -10,16 +10,67 @@ #pragma once +#include "srsran/adt/expected.h" #include namespace srsran { -/// Network slice information, see TS 38.413, Sec. 9.3.1.24 +/// Slice/Service Type (SST), as per TS 23.003, 28.4. When set, it takes at most 8 bits. +class slice_service_type +{ +public: + slice_service_type() = default; + slice_service_type(uint8_t val_) : val(val_) {} + + /// Determines whether the SST is within the range of standardized SSTs, as per TS 23.501. + bool is_standardized() const { return val < 128; } + bool is_operator_specific() const { return not is_standardized(); } + + uint8_t value() const { return val; } + + bool operator==(const slice_service_type& rhs) const { return val == rhs.val; } + bool operator!=(const slice_service_type& rhs) const { return not(val != rhs.val); } + +private: + uint8_t val = 0; +}; + +/// Slice Differentiator (SD) type, as per TS 23.003, 28.4. When set, it takes at most 24 bits. +class slice_differentiator +{ + static constexpr uint32_t default_val = 0xffffffU; + +public: + constexpr slice_differentiator() = default; + + bool is_default() const { return val == default_val; } + bool is_set() const { return val != default_val; } + + uint32_t value() const { return val; } + + bool operator==(const slice_differentiator& rhs) const { return val == rhs.val; } + bool operator!=(const slice_differentiator& rhs) const { return not(val != rhs.val); } + + static expected create(uint32_t new_val) + { + if (new_val > default_val) { + return make_unexpected(default_error_t{}); + } + slice_differentiator sd; + sd.val = new_val; + return sd; + } + +private: + uint32_t val = default_val; +}; + +/// Network Slice Selection Assistance Information, as per TS 23.003 and TS 23.501. struct s_nssai_t { - /// Slice/Service type (max 8bits). - uint8_t sst = 0; - /// Slice Differentiator (max 24bits). - std::optional sd; + /// Slice/Service type. + slice_service_type sst; + /// Slice Differentiator (SD). + slice_differentiator sd; bool operator==(const s_nssai_t& other) const { return sst == other.sst && sd == other.sd; } }; diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index fe21556dc5..e2ebfdfa5d 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -146,8 +146,8 @@ e1ap_asn1_to_integrity_algorithm(const asn1::e1ap::integrity_protection_algorith inline asn1::e1ap::snssai_s snssai_to_e1ap_asn1(srsran::s_nssai_t snssai) { asn1::e1ap::snssai_s asn1_snssai; - asn1_snssai.sst.from_number(snssai.sst); - if (snssai.sd.has_value()) { + asn1_snssai.sst.from_number(snssai.sst.value()); + if (snssai.sd.is_set()) { asn1_snssai.sd_present = true; asn1_snssai.sd.from_number(snssai.sd.value()); } @@ -164,7 +164,7 @@ inline srsran::s_nssai_t e1ap_asn1_to_snssai(asn1::e1ap::snssai_s asn1_snssai) snssai.sst = asn1_snssai.sst.to_number(); if (asn1_snssai.sd_present) { - snssai.sd = asn1_snssai.sd.to_number(); + snssai.sd = slice_differentiator::create(asn1_snssai.sd.to_number()).value(); } return snssai; diff --git a/lib/e1ap/common/e1ap_asn1_helpers.h b/lib/e1ap/common/e1ap_asn1_helpers.h index 46769ac242..6fdb451124 100644 --- a/lib/e1ap/common/e1ap_asn1_helpers.h +++ b/lib/e1ap/common/e1ap_asn1_helpers.h @@ -37,7 +37,7 @@ inline void fill_e1ap_cu_up_e1_setup_request(cu_up_e1_setup_request& slice_support.s_nssai.sst = asn1_slice_support_item.snssai.sst.to_number(); if (asn1_slice_support_item.snssai.sd_present) { - slice_support.s_nssai.sd = asn1_slice_support_item.snssai.sd.to_number(); + slice_support.s_nssai.sd = slice_differentiator::create(asn1_slice_support_item.snssai.sd.to_number()).value(); } plmn.slice_support_list.push_back(slice_support); diff --git a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp index aed12551da..22e03eaed2 100644 --- a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp +++ b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp @@ -121,7 +121,7 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( ctrl_cfg.param_list.push_back(cur_control_params); } else if (action_params[ran_param_id] == "SST") { if (ctrl_cfg.param_list.size()) { - if (ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sst) { + if (ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sst.value() != 0) { srs_du::control_config_params cur_control_params = {}; cur_control_params.rrm_policy_group.emplace(); cur_control_params = ctrl_cfg.param_list.back(); @@ -135,18 +135,18 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( } } else if (action_params[ran_param_id] == "SD") { if (ctrl_cfg.param_list.size()) { - if (ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sd.has_value()) { + if (ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sd.is_set()) { srs_du::control_config_params cur_control_params = {}; cur_control_params.rrm_policy_group.emplace(); cur_control_params = ctrl_cfg.param_list.back(); - cur_control_params.rrm_policy_group.value().pol_member.s_nssai.sd.emplace(); cur_control_params.rrm_policy_group.value().pol_member.s_nssai.sd = - ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number(); + slice_differentiator::create(ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number()) + .value(); ctrl_cfg.param_list.push_back(cur_control_params); } else { - ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sd.emplace(); ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sd = - ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number(); + slice_differentiator::create(ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number()) + .value(); } } } else if (action_params[ran_param_id] == "Min PRB Policy Ratio") { diff --git a/lib/f1ap/asn1_helpers.cpp b/lib/f1ap/asn1_helpers.cpp index a65c7aba4d..81b5d8a5f7 100644 --- a/lib/f1ap/asn1_helpers.cpp +++ b/lib/f1ap/asn1_helpers.cpp @@ -216,7 +216,7 @@ static f1ap_drb_info drb_info_from_f1ap_asn1(const asn1::f1ap::qos_info_c& asn1_ out.drb_qos.alloc_retention_prio.prio_level_arp = asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.prio_level; out.s_nssai.sst = asn1_drb_info.snssai.sst.to_number(); if (asn1_drb_info.snssai.sd_present) { - out.s_nssai.sd = asn1_drb_info.snssai.sd.to_number(); + out.s_nssai.sd = slice_differentiator::create(asn1_drb_info.snssai.sd.to_number()).value(); } // TODO: Do not populate gbr_flow_info for non-GBR flows. if (asn1_drb_info.drb_qos.gbr_qos_flow_info_present) { @@ -352,8 +352,8 @@ static qos_info_c qos_info_to_f1ap_asn1(const f1ap_drb_info& drb_info) } // s nssai - asn1_drb_info.snssai.sst.from_number(drb_info.s_nssai.sst); - if (drb_info.s_nssai.sd.has_value()) { + asn1_drb_info.snssai.sst.from_number(drb_info.s_nssai.sst.value()); + if (drb_info.s_nssai.sd.is_set()) { asn1_drb_info.snssai.sd_present = true; asn1_drb_info.snssai.sd.from_number(drb_info.s_nssai.sd.value()); } diff --git a/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp index c665f2ebb6..e7158baad1 100644 --- a/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_setup_procedure.cpp @@ -106,10 +106,10 @@ void f1ap_du_setup_procedure::send_f1_setup_request() f1ap_cell.served_cell_info.served_plmns[0].ie_exts.tai_slice_support_list_present = not cell_cfg.slices.empty(); for (const s_nssai_t& s_nssai : cell_cfg.slices) { slice_support_item_s slice{}; - slice.snssai.sst.from_number(s_nssai.sst); - slice.snssai.sd_present = s_nssai.sd.has_value(); + slice.snssai.sst.from_number(s_nssai.sst.value()); + slice.snssai.sd_present = s_nssai.sd.is_set(); if (slice.snssai.sd_present) { - slice.snssai.sd.from_number(*s_nssai.sd); + slice.snssai.sd.from_number(s_nssai.sd.value()); } f1ap_cell.served_cell_info.served_plmns[0].ie_exts.tai_slice_support_list.push_back(slice); } diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index adf906b274..868d848cc7 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -482,7 +482,7 @@ inline s_nssai_t ngap_asn1_to_s_nssai(const asn1::ngap::s_nssai_s& asn1_s_nssai) s_nssai_t s_nssai; s_nssai.sst = asn1_s_nssai.sst.to_number(); if (asn1_s_nssai.sd_present) { - s_nssai.sd = asn1_s_nssai.sd.to_number(); + s_nssai.sd = slice_differentiator::create(asn1_s_nssai.sd.to_number()).value(); } return s_nssai; @@ -491,9 +491,9 @@ inline s_nssai_t ngap_asn1_to_s_nssai(const asn1::ngap::s_nssai_s& asn1_s_nssai) inline asn1::ngap::s_nssai_s s_nssai_to_asn1(const s_nssai_t& s_nssai) { asn1::ngap::s_nssai_s asn1_s_nssai; - asn1_s_nssai.sst.from_number(s_nssai.sst); + asn1_s_nssai.sst.from_number(s_nssai.sst.value()); - if (s_nssai.sd.has_value()) { + if (s_nssai.sd.is_set()) { asn1_s_nssai.sd_present = true; asn1_s_nssai.sd.from_number(s_nssai.sd.value()); } diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index 4bba9b1a0b..8665e398e2 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -113,7 +113,8 @@ inline void fill_ngap_ng_setup_result(ngap_ng_setup_result& result, const asn1:: slice_support_item_t slice_support_item = {}; slice_support_item.s_nssai.sst = asn1_slice_support_item.s_nssai.sst.to_number(); if (asn1_slice_support_item.s_nssai.sd_present) { - slice_support_item.s_nssai.sd = asn1_slice_support_item.s_nssai.sd.to_number(); + slice_support_item.s_nssai.sd = + slice_differentiator::create(asn1_slice_support_item.s_nssai.sd.to_number()).value(); } plmn_support_item.slice_support_list.push_back(slice_support_item); } @@ -244,7 +245,7 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re // s-NSSAI if (asn1_session_item.s_nssai.sd_present) { - setup_item.s_nssai.sd = asn1_session_item.s_nssai.sd.to_number(); + setup_item.s_nssai.sd = slice_differentiator::create(asn1_session_item.s_nssai.sd.to_number()).value(); } setup_item.s_nssai.sst = asn1_session_item.s_nssai.sst.to_number(); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index d2eee5c716..24034f2b22 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -128,7 +128,7 @@ generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qo pdu_session_setup_item.pdu_session_id = psi; pdu_session_setup_item.pdu_session_type = "ipv4"; pdu_session_setup_item.snssai.sst = 1; - pdu_session_setup_item.snssai.sd = 10203; + pdu_session_setup_item.snssai.sd = slice_differentiator::create(10203).value(); pdu_session_setup_item.security_ind.integrity_protection_ind = integrity_protection_indication_t::not_needed; pdu_session_setup_item.security_ind.confidentiality_protection_ind = confidentiality_protection_indication_t::not_needed; diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 08aec1c974..98aa65c8f8 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -90,7 +90,7 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set res_to_setup_item.pdu_session_id = uint_to_pdu_session_id(0); res_to_setup_item.pdu_session_type = "ipv4"; res_to_setup_item.snssai.sst = 1; - res_to_setup_item.snssai.sd = 10203; + res_to_setup_item.snssai.sd = slice_differentiator::create(10203).value(); res_to_setup_item.security_ind.integrity_protection_ind = integrity_protection_indication_t::not_needed; res_to_setup_item.security_ind.confidentiality_protection_ind = confidentiality_protection_indication_t::not_needed; res_to_setup_item.pdu_session_res_dl_ambr = 330000000; diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index 6a8269bb2d..c31096de9c 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -257,7 +257,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi // s nssai drbs_to_be_setup_mod_item.qos_info.s_nssai.sst = 1; - drbs_to_be_setup_mod_item.qos_info.s_nssai.sd = 128; + drbs_to_be_setup_mod_item.qos_info.s_nssai.sd = slice_differentiator::create(128).value(); // notif ctrl drbs_to_be_setup_mod_item.qos_info.notif_ctrl = drb_notification_control::active; From b48e6a3613cd77d4223ee06682626b2e520c55ae Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 7 Nov 2024 10:14:42 +0100 Subject: [PATCH 41/72] ran: make sst ctor explicit --- apps/gnb/gnb.cpp | 2 +- apps/units/cu_cp/cu_cp_config_translators.cpp | 6 ++++-- apps/units/cu_cp/cu_cp_unit_config.h | 2 +- .../du_high/du_high_config_translators.cpp | 3 ++- include/srsran/ran/s_nssai.h | 5 +++-- lib/e1ap/common/e1ap_asn1_converters.h | 2 +- lib/e1ap/common/e1ap_asn1_helpers.h | 2 +- .../e2sm_rc_control_action_du_executor.cpp | 4 ++-- lib/f1ap/asn1_helpers.cpp | 2 +- lib/ngap/ngap_asn1_converters.h | 2 +- lib/ngap/ngap_asn1_helpers.h | 4 ++-- tests/integrationtests/du_high_cu/cu_du_test.cpp | 4 ++-- .../du_high_cu/du_high_cu_test_simulator.cpp | 4 ++-- .../ngap/ngap_integration_test.cpp | 4 ++-- tests/unittests/cu_cp/cu_cp_test_environment.h | 15 +++++++++------ tests/unittests/cu_cp/cu_cp_test_messages.cpp | 2 +- .../du_processor/du_processor_test_helpers.cpp | 3 ++- tests/unittests/cu_up/pdu_session_manager_test.h | 2 +- .../unittests/du_manager/du_ue/du_bearer_test.cpp | 4 ++-- .../e1ap/common/e1ap_cu_cp_test_messages.cpp | 2 +- .../f1ap/common/f1ap_cu_test_messages.cpp | 2 +- .../unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp | 2 +- tests/unittests/ngap/ngap_asn1_packer_test.cpp | 3 ++- tests/unittests/ngap/ngap_test_helpers.cpp | 7 ++++++- .../scheduler/slicing/slice_scheduler_test.cpp | 7 ++++--- 25 files changed, 55 insertions(+), 40 deletions(-) diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 4c48f05516..1f55b2f699 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -152,7 +152,7 @@ static void autoderive_slicing_args(du_high_unit_config& du_hi_cfg, cu_cp_unit_c std::vector du_slices; for (const auto& cell_cfg : du_hi_cfg.cells_cfg) { for (const auto& slice : cell_cfg.cell.slice_cfg) { - s_nssai_t nssai{slice.sst, slice_differentiator::create(slice.sd).value()}; + s_nssai_t nssai{slice_service_type{slice.sst}, slice_differentiator::create(slice.sd).value()}; if (du_slices.end() == std::find(du_slices.begin(), du_slices.end(), nssai)) { du_slices.push_back(nssai); } diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index 596c2317d9..85aed9223e 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -339,7 +339,8 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co srsran_assert(plmn.has_value(), "Invalid PLMN: {}", plmn_item.plmn_id); plmn_list.push_back({plmn.value(), {}}); for (const auto& elem : plmn_item.tai_slice_support_list) { - plmn_list.back().slice_support_list.push_back({elem.sst, slice_differentiator::create(elem.sd).value()}); + plmn_list.back().slice_support_list.push_back( + s_nssai_t{slice_service_type{elem.sst}, slice_differentiator::create(elem.sd).value()}); } } supported_tas.push_back({supported_ta.tac, plmn_list}); @@ -356,7 +357,8 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co srsran_assert(plmn.has_value(), "Invalid PLMN: {}", plmn_item.plmn_id); plmn_list.push_back({plmn.value(), {}}); for (const auto& elem : plmn_item.tai_slice_support_list) { - plmn_list.back().slice_support_list.push_back({elem.sst, slice_differentiator::create(elem.sd).value()}); + plmn_list.back().slice_support_list.push_back( + s_nssai_t{slice_service_type{elem.sst}, slice_differentiator::create(elem.sd).value()}); } } supported_tas.push_back({supported_ta.tac, plmn_list}); diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index 6e8906c753..abf2a74bc7 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -292,7 +292,7 @@ struct cu_cp_unit_config { /// QoS configuration. std::vector qos_cfg; /// Network slice configuration. - std::vector slice_cfg = {s_nssai_t{1}}; + std::vector slice_cfg = {s_nssai_t{slice_service_type{1}}}; /// E2 configuration. e2_config e2_cfg; }; diff --git a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp index 12b62af3c2..4c8f13dbac 100644 --- a/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/o_du_high/du_high/du_high_config_translators.cpp @@ -709,7 +709,8 @@ srsran::generate_du_slicing_rrm_policy_config(span for (const auto& plmn : plmns) { for (const auto& cfg : slice_cfg) { rrm_policy_cfgs.emplace_back(); - rrm_policy_cfgs.back().rrc_member.s_nssai = {cfg.sst, slice_differentiator::create(cfg.sd).value()}; + rrm_policy_cfgs.back().rrc_member.s_nssai = + s_nssai_t{slice_service_type{cfg.sst}, slice_differentiator::create(cfg.sd).value()}; rrm_policy_cfgs.back().rrc_member.plmn_id = plmn_identity::parse(plmn).value(); rrm_policy_cfgs.back().min_prb = (nof_cell_crbs * cfg.sched_cfg.min_prb_policy_ratio) / 100; rrm_policy_cfgs.back().max_prb = (nof_cell_crbs * cfg.sched_cfg.max_prb_policy_ratio) / 100; diff --git a/include/srsran/ran/s_nssai.h b/include/srsran/ran/s_nssai.h index 3414a359ef..76e7c49eee 100644 --- a/include/srsran/ran/s_nssai.h +++ b/include/srsran/ran/s_nssai.h @@ -19,8 +19,8 @@ namespace srsran { class slice_service_type { public: - slice_service_type() = default; - slice_service_type(uint8_t val_) : val(val_) {} + constexpr slice_service_type() = default; + constexpr explicit slice_service_type(uint8_t val_) : val(val_) {} /// Determines whether the SST is within the range of standardized SSTs, as per TS 23.501. bool is_standardized() const { return val < 128; } @@ -73,6 +73,7 @@ struct s_nssai_t { slice_differentiator sd; bool operator==(const s_nssai_t& other) const { return sst == other.sst && sd == other.sd; } + bool operator!=(const s_nssai_t& other) const { return not(*this == other); } }; } // namespace srsran diff --git a/lib/e1ap/common/e1ap_asn1_converters.h b/lib/e1ap/common/e1ap_asn1_converters.h index e2ebfdfa5d..b17a9a220a 100644 --- a/lib/e1ap/common/e1ap_asn1_converters.h +++ b/lib/e1ap/common/e1ap_asn1_converters.h @@ -161,7 +161,7 @@ inline asn1::e1ap::snssai_s snssai_to_e1ap_asn1(srsran::s_nssai_t snssai) inline srsran::s_nssai_t e1ap_asn1_to_snssai(asn1::e1ap::snssai_s asn1_snssai) { srsran::s_nssai_t snssai; - snssai.sst = asn1_snssai.sst.to_number(); + snssai.sst = slice_service_type{(uint8_t)asn1_snssai.sst.to_number()}; if (asn1_snssai.sd_present) { snssai.sd = slice_differentiator::create(asn1_snssai.sd.to_number()).value(); diff --git a/lib/e1ap/common/e1ap_asn1_helpers.h b/lib/e1ap/common/e1ap_asn1_helpers.h index 6fdb451124..3d722803b7 100644 --- a/lib/e1ap/common/e1ap_asn1_helpers.h +++ b/lib/e1ap/common/e1ap_asn1_helpers.h @@ -34,7 +34,7 @@ inline void fill_e1ap_cu_up_e1_setup_request(cu_up_e1_setup_request& for (const auto& asn1_slice_support_item : asn1_plmn_item.slice_support_list) { slice_support_item_t slice_support; - slice_support.s_nssai.sst = asn1_slice_support_item.snssai.sst.to_number(); + slice_support.s_nssai.sst = slice_service_type{(uint8_t)asn1_slice_support_item.snssai.sst.to_number()}; if (asn1_slice_support_item.snssai.sd_present) { slice_support.s_nssai.sd = slice_differentiator::create(asn1_slice_support_item.snssai.sd.to_number()).value(); diff --git a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp index 22e03eaed2..7d75cc768a 100644 --- a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp +++ b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp @@ -126,11 +126,11 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( cur_control_params.rrm_policy_group.emplace(); cur_control_params = ctrl_cfg.param_list.back(); cur_control_params.rrm_policy_group.value().pol_member.s_nssai.sst = - ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number(); + slice_service_type{(uint8_t)ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number()}; ctrl_cfg.param_list.push_back(cur_control_params); } else { ctrl_cfg.param_list.back().rrm_policy_group.value().pol_member.s_nssai.sst = - ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number(); + slice_service_type{(uint8_t)ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().to_number()}; } } } else if (action_params[ran_param_id] == "SD") { diff --git a/lib/f1ap/asn1_helpers.cpp b/lib/f1ap/asn1_helpers.cpp index 81b5d8a5f7..ba4c4db3df 100644 --- a/lib/f1ap/asn1_helpers.cpp +++ b/lib/f1ap/asn1_helpers.cpp @@ -214,7 +214,7 @@ static f1ap_drb_info drb_info_from_f1ap_asn1(const asn1::f1ap::qos_info_c& asn1_ non_dyn_5qi_descriptor& nondyn_5qi = out.drb_qos.qos_desc.get_nondyn_5qi(); nondyn_5qi.five_qi = uint_to_five_qi(asn1_non_dyn_5qi.five_qi); out.drb_qos.alloc_retention_prio.prio_level_arp = asn1_drb_info.drb_qos.ngra_nalloc_retention_prio.prio_level; - out.s_nssai.sst = asn1_drb_info.snssai.sst.to_number(); + out.s_nssai.sst = slice_service_type{(uint8_t)asn1_drb_info.snssai.sst.to_number()}; if (asn1_drb_info.snssai.sd_present) { out.s_nssai.sd = slice_differentiator::create(asn1_drb_info.snssai.sd.to_number()).value(); } diff --git a/lib/ngap/ngap_asn1_converters.h b/lib/ngap/ngap_asn1_converters.h index 868d848cc7..7da797977e 100644 --- a/lib/ngap/ngap_asn1_converters.h +++ b/lib/ngap/ngap_asn1_converters.h @@ -480,7 +480,7 @@ inline void asn1_to_handov_type(ngap_handov_type& handov_type, const asn1::ngap: inline s_nssai_t ngap_asn1_to_s_nssai(const asn1::ngap::s_nssai_s& asn1_s_nssai) { s_nssai_t s_nssai; - s_nssai.sst = asn1_s_nssai.sst.to_number(); + s_nssai.sst = slice_service_type{(uint8_t)asn1_s_nssai.sst.to_number()}; if (asn1_s_nssai.sd_present) { s_nssai.sd = slice_differentiator::create(asn1_s_nssai.sd.to_number()).value(); } diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index 8665e398e2..e829066bcc 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -111,7 +111,7 @@ inline void fill_ngap_ng_setup_result(ngap_ng_setup_result& result, const asn1:: for (const auto& asn1_slice_support_item : asn1_plmn_support_item.slice_support_list) { slice_support_item_t slice_support_item = {}; - slice_support_item.s_nssai.sst = asn1_slice_support_item.s_nssai.sst.to_number(); + slice_support_item.s_nssai.sst = slice_service_type{(uint8_t)asn1_slice_support_item.s_nssai.sst.to_number()}; if (asn1_slice_support_item.s_nssai.sd_present) { slice_support_item.s_nssai.sd = slice_differentiator::create(asn1_slice_support_item.s_nssai.sd.to_number()).value(); @@ -247,7 +247,7 @@ inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_re if (asn1_session_item.s_nssai.sd_present) { setup_item.s_nssai.sd = slice_differentiator::create(asn1_session_item.s_nssai.sd.to_number()).value(); } - setup_item.s_nssai.sst = asn1_session_item.s_nssai.sst.to_number(); + setup_item.s_nssai.sst = slice_service_type{(uint8_t)asn1_session_item.s_nssai.sst.to_number()}; // pDUSessionResourceSetupRequestTransfer asn1::ngap::pdu_session_res_setup_request_transfer_s asn1_setup_req_transfer; diff --git a/tests/integrationtests/du_high_cu/cu_du_test.cpp b/tests/integrationtests/du_high_cu/cu_du_test.cpp index 9e2fe1e293..b202405ae4 100644 --- a/tests/integrationtests/du_high_cu/cu_du_test.cpp +++ b/tests/integrationtests/du_high_cu/cu_du_test.cpp @@ -50,8 +50,8 @@ class cu_du_test : public ::testing::Test srs_cu_cp::cu_cp_configuration cu_cfg = config_helpers::make_default_cu_cp_config(); cu_cfg.services.cu_cp_executor = &workers.exec_mapper->du_control_executor(); // reuse du-high ctrl exec cu_cfg.services.timers = &timers; - cu_cfg.ngaps.push_back( - srs_cu_cp::cu_cp_configuration::ngap_params{&*amf, {{7, {{plmn_identity::test_value(), {{1}}}}}}}); + cu_cfg.ngaps.push_back(srs_cu_cp::cu_cp_configuration::ngap_params{ + &*amf, {{7, {{plmn_identity::test_value(), {{slice_service_type{1}}}}}}}}); // create CU-CP. cu_cp_obj = create_cu_cp(cu_cfg); diff --git a/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp b/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp index 106fbb46a4..c2ff474cec 100644 --- a/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp +++ b/tests/integrationtests/du_high_cu/du_high_cu_test_simulator.cpp @@ -73,8 +73,8 @@ du_high_cu_test_simulator::du_high_cu_test_simulator(const du_high_cu_cp_test_si srs_cu_cp::cu_cp_configuration cu_cfg = config_helpers::make_default_cu_cp_config(); cu_cfg.services.cu_cp_executor = workers.cu_cp_exec; cu_cfg.services.timers = &timers; - cu_cfg.ngaps.push_back( - srs_cu_cp::cu_cp_configuration::ngap_params{&n2_gw, {{7, {{plmn_identity::test_value(), {{1}}}}}}}); + cu_cfg.ngaps.push_back(srs_cu_cp::cu_cp_configuration::ngap_params{ + &n2_gw, {{7, {{plmn_identity::test_value(), {{slice_service_type{1}}}}}}}}); // Instatiate CU-CP. cu_cp_inst = create_cu_cp(cu_cfg); diff --git a/tests/integrationtests/ngap/ngap_integration_test.cpp b/tests/integrationtests/ngap/ngap_integration_test.cpp index 0ddcfcfd64..007c309a85 100644 --- a/tests/integrationtests/ngap/ngap_integration_test.cpp +++ b/tests/integrationtests/ngap/ngap_integration_test.cpp @@ -121,8 +121,8 @@ class ngap_integration_test : public ::testing::Test cu_cp_configuration cucfg = config_helpers::make_default_cu_cp_config(); cucfg.services.timers = &timers; cucfg.services.cu_cp_executor = &ctrl_worker; - cucfg.ngaps.push_back( - cu_cp_configuration::ngap_params{adapter.get(), {{7, {{plmn_identity::test_value(), {{1}}}}}}}); + cucfg.ngaps.push_back(cu_cp_configuration::ngap_params{ + adapter.get(), {{7, {{plmn_identity::test_value(), {{slice_service_type{1}}}}}}}}); return cucfg; }()) { diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index 8084852c1f..a1473c0845 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -33,12 +33,15 @@ struct cu_cp_test_amf_config { }; struct cu_cp_test_env_params { - cu_cp_test_env_params(unsigned max_nof_cu_ups_ = 8, - unsigned max_nof_dus_ = 8, - unsigned max_nof_ues_ = 8192, - unsigned max_nof_drbs_per_ue_ = 8, - const std::vector>& amf_config_ = - {{supported_tracking_area{7, {{plmn_identity::test_value(), {{1}}}}}}}) : + cu_cp_test_env_params( + unsigned max_nof_cu_ups_ = 8, + unsigned max_nof_dus_ = 8, + unsigned max_nof_ues_ = 8192, + unsigned max_nof_drbs_per_ue_ = 8, + const std::vector>& amf_config_ = {{supported_tracking_area{ + 7, + {plmn_item{plmn_identity::test_value(), + std::vector{s_nssai_t{slice_service_type{1}, slice_differentiator{}}}}}}}}) : max_nof_cu_ups(max_nof_cu_ups_), max_nof_dus(max_nof_dus_), max_nof_ues(max_nof_ues_), diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.cpp b/tests/unittests/cu_cp/cu_cp_test_messages.cpp index b6067ddcb6..73321aabea 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_messages.cpp @@ -46,7 +46,7 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(ue_index_t ue_index, (void)item.pdu_session_nas_pdu.resize(2); item.pdu_session_nas_pdu[0] = 0xaa; item.pdu_session_nas_pdu[1] = 0xbb; - item.s_nssai.sst = 1; + item.s_nssai.sst = slice_service_type{1}; item.pdu_session_aggregate_maximum_bit_rate_dl = 100; item.pdu_session_aggregate_maximum_bit_rate_ul = 100; diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp index 053ff49e94..fb0d6bb2c4 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp @@ -106,7 +106,8 @@ du_processor_test::du_processor_test() : cu_cp_configuration cucfg = config_helpers::make_default_cu_cp_config(); cucfg.services.timers = &timers; cucfg.services.cu_cp_executor = &ctrl_worker; - cu_cp_cfg.ngaps.push_back(cu_cp_configuration::ngap_params{nullptr, {{7, {{plmn_identity::test_value(), {{1}}}}}}}); + cu_cp_cfg.ngaps.push_back( + cu_cp_configuration::ngap_params{nullptr, {{7, {{plmn_identity::test_value(), {{slice_service_type{1}}}}}}}}); return cucfg; }()), diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 24034f2b22..f7bf0ff8f4 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -127,7 +127,7 @@ generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qo e1ap_pdu_session_res_to_setup_item pdu_session_setup_item; pdu_session_setup_item.pdu_session_id = psi; pdu_session_setup_item.pdu_session_type = "ipv4"; - pdu_session_setup_item.snssai.sst = 1; + pdu_session_setup_item.snssai.sst = slice_service_type{1}; pdu_session_setup_item.snssai.sd = slice_differentiator::create(10203).value(); pdu_session_setup_item.security_ind.integrity_protection_ind = integrity_protection_indication_t::not_needed; pdu_session_setup_item.security_ind.confidentiality_protection_ind = diff --git a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp index 6e0a2b060b..51a9149d8e 100644 --- a/tests/unittests/du_manager/du_ue/du_bearer_test.cpp +++ b/tests/unittests/du_manager/du_ue/du_bearer_test.cpp @@ -38,7 +38,7 @@ class du_ue_bearer_manager_test : public ::testing::Test { du_mng = std::make_unique( std::vector{config_helpers::make_default_du_cell_config()}); - dummy_slice_info = s_nssai_t{.sst = 1}; + dummy_slice_info = s_nssai_t{.sst = slice_service_type{1}}; } void SetUp() override @@ -57,7 +57,7 @@ class du_ue_bearer_manager_test : public ::testing::Test std::vector{config_helpers::make_default_du_cell_config()}); dummy_teid_pool teid_pool; dummy_rlc_rlf_notifier rlf_notifier; - s_nssai_t dummy_slice_info = s_nssai_t{.sst = 1}; + s_nssai_t dummy_slice_info = s_nssai_t{.sst = slice_service_type{1}}; std::unique_ptr create_dummy_drb(drb_id_t drb_id, lcid_t lcid) { diff --git a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp index 98aa65c8f8..6075d4a8ef 100644 --- a/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp +++ b/tests/unittests/e1ap/common/e1ap_cu_cp_test_messages.cpp @@ -89,7 +89,7 @@ e1ap_bearer_context_setup_request srsran::srs_cu_cp::generate_bearer_context_set e1ap_pdu_session_res_to_setup_item res_to_setup_item; res_to_setup_item.pdu_session_id = uint_to_pdu_session_id(0); res_to_setup_item.pdu_session_type = "ipv4"; - res_to_setup_item.snssai.sst = 1; + res_to_setup_item.snssai.sst = slice_service_type{1}; res_to_setup_item.snssai.sd = slice_differentiator::create(10203).value(); res_to_setup_item.security_ind.integrity_protection_ind = integrity_protection_indication_t::not_needed; res_to_setup_item.security_ind.confidentiality_protection_ind = confidentiality_protection_indication_t::not_needed; diff --git a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp index c31096de9c..2078512337 100644 --- a/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp +++ b/tests/unittests/f1ap/common/f1ap_cu_test_messages.cpp @@ -256,7 +256,7 @@ f1ap_ue_context_modification_request srsran::srs_cu_cp::generate_ue_context_modi drbs_to_be_setup_mod_item.qos_info.drb_qos.reflective_qos_attribute_subject_to = true; // s nssai - drbs_to_be_setup_mod_item.qos_info.s_nssai.sst = 1; + drbs_to_be_setup_mod_item.qos_info.s_nssai.sst = slice_service_type{1}; drbs_to_be_setup_mod_item.qos_info.s_nssai.sd = slice_differentiator::create(128).value(); // notif ctrl diff --git a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp index 43cc2155be..27c03c863b 100644 --- a/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp +++ b/tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.cpp @@ -147,7 +147,7 @@ srsran::srs_cu_cp::create_ue_context_setup_request(const std::initializer_list{s_nssai_t{slice_service_type{1}, slice_differentiator{}}}}}}}}); return cucfg; }()) { diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 83c7386595..404866b465 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -268,8 +268,9 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test static constexpr ran_slice_id_t drb2_slice_id{3}; rb_ratio_slice_scheduler_test() : - slice_scheduler_test({{{plmn_identity::test_value(), s_nssai_t{1}}, MIN_SLICE_RB, MAX_SLICE_RB}, - {{plmn_identity::test_value(), s_nssai_t{2}}, MIN_SLICE_RB, MAX_SLICE_RB}}) + slice_scheduler_test( + {{{plmn_identity::test_value(), s_nssai_t{slice_service_type{1}}}, MIN_SLICE_RB, MAX_SLICE_RB}, + {{plmn_identity::test_value(), s_nssai_t{slice_service_type{2}}}, MIN_SLICE_RB, MAX_SLICE_RB}}) { } @@ -283,7 +284,7 @@ class rb_ratio_slice_scheduler_test : public slice_scheduler_test, public ::test req.starts_in_fallback = false; if (lc_cfgs.size() == 0) { (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.plmn_id = plmn_identity::test_value(); - (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.s_nssai = s_nssai_t{1}; + (*req.cfg.lc_config_list)[drb1_idx].rrm_policy.s_nssai = s_nssai_t{slice_service_type{1}}; } else { *req.cfg.lc_config_list = lc_cfgs; } From 1d1d1ad3efa6a325a873973b1752838f7a2eab3b Mon Sep 17 00:00:00 2001 From: Oriol Font-Bach Date: Thu, 7 Nov 2024 10:48:03 +0000 Subject: [PATCH 42/72] phy: refactor tx ldpc segmenter to make it bufferless --- .../channel_coding/ldpc/ldpc_encoder_buffer.h | 2 +- .../ldpc/ldpc_segmenter_buffer.h | 73 ++++ .../channel_coding/ldpc/ldpc_segmenter_tx.h | 20 +- .../channel_processors/pdsch/factories.h | 4 +- .../channel_coding_factories.cpp | 9 +- .../upper/channel_coding/ldpc/CMakeLists.txt | 3 +- .../ldpc/ldpc_segmenter_helpers.h | 108 ++++++ .../ldpc/ldpc_segmenter_impl.cpp | 319 ------------------ .../channel_coding/ldpc/ldpc_segmenter_impl.h | 124 ------- .../ldpc/ldpc_segmenter_rx_impl.cpp | 94 ++++++ .../ldpc/ldpc_segmenter_rx_impl.h | 40 +++ .../ldpc/ldpc_segmenter_tx_impl.cpp | 242 +++++++++++++ .../ldpc/ldpc_segmenter_tx_impl.h | 97 ++++++ .../channel_processors/pdsch/factories.cpp | 28 +- .../pdsch/pdsch_codeblock_processor.cpp | 71 +--- .../pdsch/pdsch_codeblock_processor.h | 25 +- .../pdsch/pdsch_encoder_hw_impl.cpp | 132 ++------ .../pdsch/pdsch_encoder_hw_impl.h | 17 +- .../pdsch/pdsch_encoder_impl.cpp | 26 +- .../pdsch/pdsch_encoder_impl.h | 7 +- .../pdsch/pdsch_processor_concurrent_impl.cpp | 80 ++--- .../pdsch/pdsch_processor_concurrent_impl.h | 16 +- .../pdsch/pdsch_processor_lite_impl.cpp | 36 +- .../pdsch/pdsch_processor_lite_impl.h | 13 +- lib/phy/upper/upper_phy_factories.cpp | 2 +- .../pdsch_processor_benchmark.cpp | 4 +- .../pxsch_bler_test_factories.cpp | 2 +- .../ldpc/ldpc_segmenter_test.cpp | 21 +- .../pdsch/pdsch_processor_vectortest.cpp | 2 +- 29 files changed, 855 insertions(+), 762 deletions(-) create mode 100644 include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h create mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_helpers.h delete mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.cpp delete mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.h create mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.cpp create mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.h create mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.cpp create mode 100644 lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.h diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h index 920186606b..9ffec3579f 100644 --- a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_encoder_buffer.h @@ -17,7 +17,7 @@ namespace srsran { /// \brief LDPC encoder output buffer interface. /// -/// This interface allows the LDPC encoder to provide the encoded bits to the rate matcher without using anintermediate +/// This interface allows the LDPC encoder to provide the encoded bits to the rate matcher without using an intermediate /// buffer. class ldpc_encoder_buffer { diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h new file mode 100644 index 0000000000..a853500400 --- /dev/null +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h @@ -0,0 +1,73 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/adt/span.h" +#include "srsran/adt/static_vector.h" +#include "srsran/phy/upper/codeblock_metadata.h" + +namespace srsran { + +/// \brief LDPC segmenter output buffer interface. +/// +/// This interface allows the LDPC segmenter to provide the CBs to the LDPC encoder without using an intermediate +/// buffer. +class ldpc_segmenter_buffer +{ +public: + /// Default destructor. + virtual ~ldpc_segmenter_buffer() = default; + + /// \brief Gets the codeblock metadata structure for a given codeblock. + /// + /// \param[in] cb_index Codeblock index (within the TB). + /// \return Codeblock metadata structure for the codeblock with index \c cb_index. + virtual codeblock_metadata get_cb_metadata(unsigned cb_index) const = 0; + + /// Gets the number of codeblocks resulting from TB segmentation. + virtual unsigned get_nof_codeblocks() const = 0; + + /// Gets the number of of segments that will have a short rate-matched length. + virtual unsigned get_nof_short_segments() const = 0; + + /// \brief Gets the number of information bits for a given segment. + /// + /// \param[in] cb_index Segment index. + /// \return Number of information bits for the segment with index \c cb_index. + virtual units::bits get_cb_info_bits(unsigned cb_index) const = 0; + + /// Gets the segment length resulting from TB segmentation. + virtual units::bits get_segment_length() const = 0; + + /// Gets the codeword length. + virtual units::bits get_cw_length() const = 0; + + /// Gets the zero padding length. + virtual units::bits get_zero_pad() const = 0; + + /// Gets the number of TB CRC bits. + virtual units::bits get_tb_crc_bits() const = 0; + + /// Gets the number of filler bits. + virtual units::bits get_nof_filler_bits() const = 0; + + /// Gets the codeblock length. + virtual unsigned get_rm_length(unsigned cb_index) const = 0; + + /// \brief Reads the segmented codeblock data, including the CB CRC, for the CB at index \c cb_index. + /// + /// \param[out] codeblock Read destination. + /// \param[in] transport_block Read source. + /// \param[in] cb_index Codeblock index (within the TB). + virtual void read_codeblock(bit_buffer codeblock, span transport_block, unsigned cb_index) const = 0; +}; + +} // namespace srsran diff --git a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h index 12a9622ae2..88fcadef23 100644 --- a/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h +++ b/include/srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h @@ -13,12 +13,13 @@ #pragma once #include "srsran/adt/span.h" -#include "srsran/adt/static_vector.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" #include "srsran/phy/upper/codeblock_metadata.h" namespace srsran { +class ldpc_segmenter_buffer; + /// Carries out the segmentation of a transport block into a number of codeblocks. class ldpc_segmenter_tx { @@ -26,20 +27,17 @@ class ldpc_segmenter_tx /// Default destructor. virtual ~ldpc_segmenter_tx() = default; - /// \brief Adds the CRC to the a transport block, carries out segmentation and computes all codeblock metadata for - /// later use (encoder and rate matching). + /// \brief Performs transport block segmentation on a codeblock basis without using an intermediate buffer. /// - /// First, the transport block CRC is attached, as per TS38.212 Section 7.2.1. Then, the transport block is split into - /// a number of segments and, if needed, a CRC is attached to each segment_tx. This is done according to TS38.212 - /// Section 5.2.2. The function also computes other segment_tx metadata (e.g., coded and rate-matched length) - /// according to TS38.212 Section 5.4.2.1. + /// If needed, a CRC is attached to the generated segment, according to TS38.212 Section 5.2.2. Moreover, the + /// transport block CRC is attached to the last segment, as per TS38.212 Section 7.2.1. The function also computes + /// relevant segment metadata (e.g., coded and rate-matched length) according to TS38.212 Section 5.4.2.1. /// - /// \param[out] described_segments Segments (unpacked, one bit per entry) and corresponding metadata. /// \param[in] transport_block The transport block to segment_tx (packed, one byte per entry). /// \param[in] cfg Parameters affecting splitting and codeblock metadata. - virtual void segment(static_vector& described_segments, - span transport_block, - const segmenter_config& cfg) = 0; + /// \return A reference to the LDPC segmenter buffer. + virtual const ldpc_segmenter_buffer& new_transmission(span transport_block, + const segmenter_config& cfg) = 0; }; } // namespace srsran diff --git a/include/srsran/phy/upper/channel_processors/pdsch/factories.h b/include/srsran/phy/upper/channel_processors/pdsch/factories.h index 32e32894b2..8c9fd1775b 100644 --- a/include/srsran/phy/upper/channel_processors/pdsch/factories.h +++ b/include/srsran/phy/upper/channel_processors/pdsch/factories.h @@ -78,7 +78,7 @@ create_pdsch_processor_factory_sw(std::shared_ptr std::shared_ptr ptrs_factory); std::shared_ptr -create_pdsch_concurrent_processor_factory_sw(std::shared_ptr crc_factory, +create_pdsch_concurrent_processor_factory_sw(std::shared_ptr ldpc_segmenter_factory, std::shared_ptr ldpc_enc_factory, std::shared_ptr ldpc_rm_factory, std::shared_ptr prg_factory, @@ -106,4 +106,4 @@ create_pdsch_processor_asynchronous_pool(std::shared_ptr create_pdsch_processor_pool(std::shared_ptr pdsch_proc_factory, unsigned max_nof_processors); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/phy/upper/channel_coding/channel_coding_factories.cpp b/lib/phy/upper/channel_coding/channel_coding_factories.cpp index bcd7849a55..abb4249ca2 100644 --- a/lib/phy/upper/channel_coding/channel_coding_factories.cpp +++ b/lib/phy/upper/channel_coding/channel_coding_factories.cpp @@ -15,7 +15,8 @@ #include "ldpc/ldpc_encoder_generic.h" #include "ldpc/ldpc_rate_dematcher_impl.h" #include "ldpc/ldpc_rate_matcher_impl.h" -#include "ldpc/ldpc_segmenter_impl.h" +#include "ldpc/ldpc_segmenter_rx_impl.h" +#include "ldpc/ldpc_segmenter_tx_impl.h" #include "polar/polar_allocator_impl.h" #include "polar/polar_code_impl.h" #include "polar/polar_deallocator_impl.h" @@ -211,19 +212,19 @@ class ldpc_segmenter_tx_factory_sw : public ldpc_segmenter_tx_factory std::unique_ptr create() override { - ldpc_segmenter_impl::sch_crc sch_crc = { + ldpc_segmenter_tx_impl::sch_crc sch_crc = { crc_factory->create(crc_generator_poly::CRC16), crc_factory->create(crc_generator_poly::CRC24A), crc_factory->create(crc_generator_poly::CRC24B), }; - return ldpc_segmenter_impl::create_ldpc_segmenter_impl_tx(sch_crc); + return std::make_unique(sch_crc); } }; class ldpc_segmenter_rx_factory_sw : public ldpc_segmenter_rx_factory { public: - std::unique_ptr create() override { return ldpc_segmenter_impl::create_ldpc_segmenter_impl_rx(); } + std::unique_ptr create() override { return std::make_unique(); } }; class polar_factory_sw : public polar_factory diff --git a/lib/phy/upper/channel_coding/ldpc/CMakeLists.txt b/lib/phy/upper/channel_coding/ldpc/CMakeLists.txt index 8f3d46e465..40b7610f2d 100644 --- a/lib/phy/upper/channel_coding/ldpc/CMakeLists.txt +++ b/lib/phy/upper/channel_coding/ldpc/CMakeLists.txt @@ -15,7 +15,8 @@ set(ldpc_sources ldpc_decoder_generic.cpp ldpc_rate_matcher_impl.cpp ldpc_rate_dematcher_impl.cpp - ldpc_segmenter_impl.cpp + ldpc_segmenter_tx_impl.cpp + ldpc_segmenter_rx_impl.cpp ) if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_helpers.h b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_helpers.h new file mode 100644 index 0000000000..e075121b79 --- /dev/null +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_helpers.h @@ -0,0 +1,108 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief Helper functions for LDPC segmenter implementations. + +#pragma once + +#include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" +#include "srsran/phy/upper/codeblock_metadata.h" + +namespace srsran { + +struct segment_parameters { + /// \name Attributes relative to TS38.212 Section 5.2.2. + ///@{ + /// Final length of a segment (corresponds to \f$K\f$). + units::bits segment_length{0}; + /// Number of bits in the transport block (corresponds to \f$B\f$). + units::bits nof_tb_bits_in{0}; + /// Augmented number of bits in the transport block, including new CRCs (corresponds to \f$B'\f$). + units::bits nof_tb_bits_out{0}; + /// Number of segments resulting from the transport block (corresponds to \f$C\f$). + unsigned nof_segments = 0; + ///@} + /// \name Attributes relative to TS38.212 Section 5.4.2.1. + ///@{ + /// Number of symbols per transmission layer (corresponds to \f$G / (N_L Q_m)\f$). + unsigned nof_symbols_per_layer = 0; + /// \brief Number of segments of short rate-matched length (corresponds to \f$C - \bigr(\bigl(G / (N_L Q_m)\bigr) + /// \bmod C\bigr)\f$). + unsigned nof_short_segments = 0; + ///@} + /// Base graph used for encoding/decoding the current transport block. + ldpc_base_graph_type base_graph = ldpc_base_graph_type::BG1; + /// Lifting size used for encoding/decoding the current transport block. + unsigned lifting_size = 0; + /// Total codeword length. + units::bits cw_length; + /// Number of filler bits. + units::bits nof_filler_bits; + /// Number of segment-specific CRC bits. + units::bits nof_crc_bits; + // Number of information bits that is assigned to a segment. + units::bits cb_info_bits; + // Number of information bits that is assigned to the last segment. + units::bits cb_info_bits_last; + // Number of zero-pad bits. + units::bits zero_pad; + /// Number of TB-specific CRC bits. + units::bits nof_tb_crc_bits; + /// Array of codeblock starting offset within the codeword. + std::array cw_offset; + /// Array of segment starting offset within the transport block. + std::array tb_offset; + /// Array of codeblock metadata structure. + std::array cb_metadata; +}; + +/// Computes the length of the rate-matched codeblock corresponding to each segment, as per TS38.212 +/// Section 5.4.2.1. +inline unsigned +compute_rm_length(const segment_parameters& seg_param, modulation_scheme mod, unsigned nof_layers, unsigned i_seg) +{ + unsigned tmp = 0; + if (i_seg < seg_param.nof_short_segments) { + // For unsigned, division then floor is the same as integer division. + tmp = seg_param.nof_symbols_per_layer / seg_param.nof_segments; + } else { + tmp = divide_ceil(seg_param.nof_symbols_per_layer, seg_param.nof_segments); + } + return tmp * nof_layers * get_bits_per_symbol(mod); +} + +/// Generates a codeblock metadata structure for the current segment configuration. +inline codeblock_metadata +generate_cb_metadata(const segment_parameters& seg_param, const segmenter_config& cfg, unsigned i_seg) +{ + codeblock_metadata tmp_description; + + tmp_description.tb_common.base_graph = seg_param.base_graph; + tmp_description.tb_common.lifting_size = static_cast(seg_param.lifting_size); + tmp_description.tb_common.rv = cfg.rv; + tmp_description.tb_common.mod = cfg.mod; + tmp_description.tb_common.Nref = cfg.Nref; + tmp_description.tb_common.cw_length = seg_param.cw_length.value(); + + unsigned rm_length = compute_rm_length(seg_param, cfg.mod, cfg.nof_layers, i_seg); + + tmp_description.cb_specific.full_length = + ldpc::compute_full_codeblock_size(seg_param.base_graph, seg_param.segment_length).value(); + tmp_description.cb_specific.nof_filler_bits = seg_param.nof_filler_bits.value(); + tmp_description.cb_specific.rm_length = rm_length; + tmp_description.cb_specific.cw_offset = seg_param.cw_offset[i_seg]; + tmp_description.cb_specific.nof_crc_bits = + (seg_param.nof_segments == 1) ? seg_param.nof_tb_crc_bits.value() : seg_param.nof_crc_bits.value(); + + return tmp_description; +} + +} // namespace srsran diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.cpp deleted file mode 100644 index 72aeef85e7..0000000000 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "ldpc_segmenter_impl.h" -#include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" -#include "srsran/phy/upper/codeblock_metadata.h" -#include "srsran/srsvec/bit.h" -#include "srsran/srsvec/copy.h" -#include "srsran/support/math/math_utils.h" -#include "srsran/support/srsran_assert.h" - -using namespace srsran; -using namespace srsran::ldpc; - -/// Length of the CRC checksum added to the segments. -static constexpr units::bits SEG_CRC_LENGTH{24}; -/// Maximum accepted transport block size. -/// Note: This value has to be multiple of 8. -static constexpr units::bits MAX_TBS{1277992}; -static_assert(MAX_TBS.is_byte_exact(), "Value is not a multiple of 8"); - -std::unique_ptr ldpc_segmenter_impl::create_ldpc_segmenter_impl_tx(ldpc_segmenter_impl::sch_crc& c) -{ - srsran_assert(c.crc16, "Invalid CRC16 calculator."); - srsran_assert(c.crc24A, "Invalid CRC24A calculator."); - srsran_assert(c.crc24B, "Invalid CRC24B calculator."); - srsran_assert(c.crc16->get_generator_poly() == crc_generator_poly::CRC16, "Not a CRC generator of type CRC16."); - srsran_assert(c.crc24A->get_generator_poly() == crc_generator_poly::CRC24A, "Not a CRC generator of type CRC24A."); - srsran_assert(c.crc24B->get_generator_poly() == crc_generator_poly::CRC24B, "Not a CRC generator of type CRC24B."); - - return std::unique_ptr(new ldpc_segmenter_impl(std::move(c))); -} - -std::unique_ptr ldpc_segmenter_impl::create_ldpc_segmenter_impl_rx() -{ - return std::unique_ptr(new ldpc_segmenter_impl()); -} - -unsigned ldpc_segmenter_impl::compute_rm_length(unsigned i_seg, modulation_scheme mod, unsigned nof_layers) const -{ - unsigned tmp = 0; - if (i_seg < nof_short_segments) { - // For unsigned, division then floor is the same as integer division. - tmp = nof_symbols_per_layer / nof_segments; - } else { - tmp = divide_ceil(nof_symbols_per_layer, nof_segments); - } - return tmp * nof_layers * get_bits_per_symbol(mod); -} - -static void check_inputs_tx(const static_vector& segments, - span transport_block, - const segmenter_config& cfg) -{ - using namespace units::literals; - srsran_assert(segments.empty(), "Argument segments should be empty."); - srsran_assert(!transport_block.empty(), "Argument transport_block should not be empty."); - srsran_assert(units::bytes(transport_block.size()).to_bits() + 24_bits <= MAX_TBS, - "Transport block too long. The admissible size, including CRC, is {}.", - MAX_TBS.truncate_to_bytes()); - - srsran_assert((cfg.rv >= 0) && (cfg.rv <= 3), "Invalid redundancy version."); - - srsran_assert((cfg.nof_layers >= 1) && (cfg.nof_layers <= 4), "Invalid number of layers."); - - srsran_assert(cfg.nof_ch_symbols % (cfg.nof_layers) == 0, - "The number of channel symbols should be a multiple of the product between the number of layers."); -} - -// For the Tx-chain segmenter. -void ldpc_segmenter_impl::segment(static_vector& described_segments, - span transport_block, - const segmenter_config& cfg) -{ - check_inputs_tx(described_segments, transport_block, cfg); - - using namespace units::literals; - - base_graph = cfg.base_graph; - // Each transport_block entry is a byte, and TBS can always be expressed as an integer number of bytes (see, e.g., - // TS38.214 Section 5.1.3.2). - units::bits nof_tb_bits_tmp = units::bytes(transport_block.size()).to_bits(); - - constexpr units::bits MAX_BITS_CRC16{3824}; - crc_calculator& tb_crc = (nof_tb_bits_tmp <= MAX_BITS_CRC16) ? *crc_set.crc16 : *crc_set.crc24A; - units::bits nof_tb_crc_bits = compute_tb_crc_size(nof_tb_bits_tmp); - - nof_tb_bits_in = nof_tb_bits_tmp + nof_tb_crc_bits; - - nof_segments = ldpc::compute_nof_codeblocks(nof_tb_bits_tmp, base_graph); - nof_tb_bits_out = nof_tb_bits_in; - if (nof_segments > 1) { - nof_tb_bits_out += units::bits(nof_segments * SEG_CRC_LENGTH.value()); - } - lifting_size = compute_lifting_size(nof_tb_bits_tmp, base_graph, nof_segments); - segment_length = compute_codeblock_size(base_graph, lifting_size); - - units::bits nof_crc_bits = (nof_segments > 1) ? SEG_CRC_LENGTH : 0_bits; - - // Compute the number of information bits that is assigned to a segment. - units::bits cb_info_bits = units::bits(divide_ceil(nof_tb_bits_out.value(), nof_segments)) - nof_crc_bits; - - // Zero-padding if necessary. - units::bits zero_pad = units::bits((cb_info_bits + nof_crc_bits).value() * nof_segments) - nof_tb_bits_out; - - // Append TB CRC. - crc_calculator_checksum_t tb_checksum = tb_crc.calculate_byte(transport_block); - - // Number of channel symbols assigned to a transmission layer. - nof_symbols_per_layer = cfg.nof_ch_symbols / cfg.nof_layers; - // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to - // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is - // rounded up. - nof_short_segments = nof_segments - (nof_symbols_per_layer % nof_segments); - - // Codeword length (after concatenation of codeblocks). - units::bits cw_length(cfg.nof_ch_symbols * get_bits_per_symbol(cfg.mod)); - - // Number of filler bits in this segment. - units::bits nof_filler_bits = segment_length - cb_info_bits - nof_crc_bits; - - unsigned cw_offset = 0; - unsigned tb_offset = 0; - for (unsigned i_segment = 0; i_segment != nof_segments; ++i_segment) { - bool last_cb = (i_segment == nof_segments - 1); - - // Generate metadata for this segment. - codeblock_metadata cb_metadata = - generate_cb_metadata({i_segment, cw_length, cw_offset, nof_filler_bits, nof_crc_bits, nof_tb_crc_bits}, cfg); - - // Prepare segment data. - described_segments.emplace_back(cb_metadata, segment_length); - described_segment& segment = described_segments.back(); - - // Segment bit buffer. - bit_buffer& cb_bit_buffer = segment.get_data(); - - // Number of information bits to get from the transport block. Remove transport block CRC bits if it is the last CB. - units::bits nof_used_bits = cb_info_bits; - if (last_cb) { - nof_used_bits -= nof_tb_crc_bits + zero_pad; - } - - // Copy information bits from the transport block. - bit_buffer cb_info_bit_buffer = cb_bit_buffer.first(nof_used_bits.value()); - srsvec::copy_offset(cb_info_bit_buffer, transport_block, tb_offset); - tb_offset += nof_used_bits.value(); - - // If it is the last CB, append the transport block CRC and padding bits. - if (last_cb) { - // For each byte of the transport block CRC... - for (unsigned i_checksum_byte = 0, i_checksum_byte_end = nof_tb_crc_bits.truncate_to_bytes().value(); - i_checksum_byte != i_checksum_byte_end; - ++i_checksum_byte) { - // Extract byte from the CRC. - unsigned tb_crc_byte = (tb_checksum >> (nof_tb_crc_bits.value() - (i_checksum_byte + 1) * 8)) & 0xffUL; - // Insert the byte at the end of the bit buffer. - cb_bit_buffer.insert(tb_crc_byte, nof_used_bits.value(), 8); - // Increment the number of bits. - nof_used_bits += 8_bits; - } - tb_offset += nof_tb_crc_bits.value(); - - // Insert zero padding bits. - for (units::bits nof_used_bits_end = nof_used_bits + zero_pad; nof_used_bits != nof_used_bits_end;) { - // Calculate the number of zeros to pad, no more than a byte at a time. - units::bits nof_zeros = std::min(8_bits, nof_used_bits_end - nof_used_bits); - // Insert the zeros at the end of the bit buffer. - cb_bit_buffer.insert(0UL, nof_used_bits.value(), nof_zeros.value()); - // Increment the number of bits. - nof_used_bits += nof_zeros; - } - } - - // Append codeblock CRC if required. - if (nof_crc_bits != 0_bits) { - crc_calculator_checksum_t cb_checksum = crc_set.crc24B->calculate(cb_bit_buffer.first(nof_used_bits.value())); - - // For each byte of the transport block CRC... - for (unsigned i_checksum_byte = 0, i_checksum_byte_end = nof_crc_bits.truncate_to_bytes().value(); - i_checksum_byte != i_checksum_byte_end; - ++i_checksum_byte) { - // Extract byte from the CRC. - unsigned cb_crc_byte = (cb_checksum >> (nof_crc_bits.value() - (i_checksum_byte + 1) * 8)) & 0xffUL; - // Insert the byte at the end of the bit buffer. - cb_bit_buffer.insert(cb_crc_byte, nof_used_bits.value(), 8); - // Increment the number of bits. - nof_used_bits += 8_bits; - } - } - - // Append filler bits as zeros. - while (nof_used_bits != segment_length) { - // Calculate the number of zeros to pad, no more than a byte at a time. - units::bits nof_zeros = std::min(8_bits, segment_length - nof_used_bits); - // Insert the zeros at the end of the bit buffer. - cb_bit_buffer.insert(0UL, nof_used_bits.value(), nof_zeros.value()); - // Increment the number of bits. - nof_used_bits += nof_zeros; - } - - // Advance offsets. - cw_offset += cb_metadata.cb_specific.rm_length; - } - - // After segmenting no bits should be left in the buffer. - srsran_assert(nof_tb_bits_in.value() == tb_offset, - "Transport block offset ({}) must be equal to the transport block size including CRC ({}).", - tb_offset, - nof_tb_bits_in); - // After accumulating all codeblock rate-matched lengths, cw_offset should be the same as cw_length. - srsran_assert(cw_length.value() == cw_offset, - "Codeblock offset ({}) must be equal to the codeword size ({}).", - cw_offset, - cw_length.value()); -} - -static void check_inputs_rx(span codeword_llrs, const segmenter_config& cfg) -{ - srsran_assert(!codeword_llrs.empty(), "Argument transport_block should not be empty."); - srsran_assert(codeword_llrs.size() == cfg.nof_ch_symbols * get_bits_per_symbol(cfg.mod), - "Wrong number of LLRs {} (expected {}).", - codeword_llrs.size(), - cfg.nof_ch_symbols * get_bits_per_symbol(cfg.mod)); - - srsran_assert((cfg.rv >= 0) && (cfg.rv <= 3), "Invalid redundancy version."); - - srsran_assert((cfg.nof_layers >= 1) && (cfg.nof_layers <= 4), "Invalid number of layers."); - - srsran_assert(cfg.nof_ch_symbols % (cfg.nof_layers) == 0, - "The number of channel symbols should be a multiple of the product between the number of layers."); -} - -// For the Rx-chain segmenter. -void ldpc_segmenter_impl::segment(static_vector& described_codeblocks, - span codeword_llrs, - unsigned tbs, - const segmenter_config& cfg) -{ - check_inputs_rx(codeword_llrs, cfg); - - using namespace units::literals; - - base_graph = cfg.base_graph; - - units::bits tbs_bits(tbs); - units::bits nof_tb_crc_bits = compute_tb_crc_size(tbs_bits); - - nof_tb_bits_in = tbs_bits + nof_tb_crc_bits; - - nof_segments = ldpc::compute_nof_codeblocks(tbs_bits, base_graph); - nof_tb_bits_out = nof_tb_bits_in; - if (nof_segments > 1) { - nof_tb_bits_out += units::bits(nof_segments * SEG_CRC_LENGTH.value()); - } - lifting_size = compute_lifting_size(tbs_bits, base_graph, nof_segments); - segment_length = compute_codeblock_size(base_graph, lifting_size); - - units::bits nof_crc_bits = (nof_segments > 1) ? SEG_CRC_LENGTH : 0_bits; - - // Compute the maximum number of information bits that can be assigned to a segment. - units::bits max_info_bits = units::bits(divide_ceil(nof_tb_bits_out.value(), nof_segments)) - nof_crc_bits; - - // Number of channel symbols assigned to a transmission layer. - nof_symbols_per_layer = cfg.nof_ch_symbols / cfg.nof_layers; - // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to - // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is - // rounded up. - nof_short_segments = nof_segments - (nof_symbols_per_layer % nof_segments); - - // Codeword length (after concatenation of codeblocks). - units::bits cw_length(codeword_llrs.size()); - - unsigned cw_offset = 0; - for (unsigned i_segment = 0; i_segment != nof_segments; ++i_segment) { - units::bits nof_filler_bits = segment_length - (max_info_bits + nof_crc_bits); - - codeblock_metadata tmp_description = - generate_cb_metadata({i_segment, cw_length, cw_offset, nof_filler_bits, nof_crc_bits, nof_tb_crc_bits}, cfg); - - unsigned rm_length = tmp_description.cb_specific.rm_length; - described_codeblocks.push_back({codeword_llrs.subspan(cw_offset, rm_length), tmp_description}); - cw_offset += rm_length; - } - // After accumulating all codeblock rate-matched lengths, cw_offset should be the same as cw_length. - srsran_assert(cw_length.value() == cw_offset, "Cw offset must be equal to the cw length"); -} - -codeblock_metadata ldpc_segmenter_impl::generate_cb_metadata(const segment_internal& seg_extra, - const segmenter_config& cfg) const -{ - codeblock_metadata tmp_description; - - tmp_description.tb_common.base_graph = base_graph; - tmp_description.tb_common.lifting_size = static_cast(lifting_size); - tmp_description.tb_common.rv = cfg.rv; - tmp_description.tb_common.mod = cfg.mod; - tmp_description.tb_common.Nref = cfg.Nref; - tmp_description.tb_common.cw_length = seg_extra.cw_length.value(); - - unsigned rm_length = compute_rm_length(seg_extra.i_segment, cfg.mod, cfg.nof_layers); - - tmp_description.cb_specific.full_length = compute_full_codeblock_size(base_graph, segment_length).value(); - tmp_description.cb_specific.nof_filler_bits = seg_extra.nof_filler_bits.value(); - tmp_description.cb_specific.rm_length = rm_length; - tmp_description.cb_specific.cw_offset = seg_extra.cw_offset; - // nof_crc_bits == 0 indicates that we are using the TB CRC with length 16. - tmp_description.cb_specific.nof_crc_bits = - (nof_segments == 1) ? seg_extra.nof_tb_crc_bits.value() : seg_extra.nof_crc_bits.value(); - - return tmp_description; -} diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.h deleted file mode 100644 index 6018429472..0000000000 --- a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_impl.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -/// \file -/// \brief LDPC codeblock segmentation declaration. - -#pragma once - -#include "ldpc_graph_impl.h" -#include "srsran/phy/upper/channel_coding/crc_calculator.h" -#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx.h" -#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h" - -namespace srsran { - -/// \brief Generic implementation of LDPC segmentation. -/// -/// Implements both ldpc_segmenter_tx and ldpc_segmenter_rx. For this reason, the constructor has been hidden behind the -/// static wrapper methods create_ldpc_segmenter_impl_tx() and create_ldpc_segmenter_impl_rx(). -class ldpc_segmenter_impl : public ldpc_segmenter_tx, public ldpc_segmenter_rx -{ -public: - /// CRC calculators used in shared channels. - struct sch_crc { - /// For short TB checksums. - std::unique_ptr crc16; - /// For long TB checksums. - std::unique_ptr crc24A; - /// For segment-specific checksums. - std::unique_ptr crc24B; - }; - - /// \brief Wraps the constructor of the Tx version of the LDPC segmenter. - static std::unique_ptr create_ldpc_segmenter_impl_tx(sch_crc&); - - /// \brief Wraps the constructor of the Rx version of the LDPC segmenter. - /// \remark The receive-chain version of the segmenter does not need CRC calculators. - static std::unique_ptr create_ldpc_segmenter_impl_rx(); - - // Tx-chain segmentation. - // See interface for the documentation. - void segment(static_vector& described_segments, - span transport_block, - const segmenter_config& cfg) override; - - // Rx-chain segmentation. - // See interface for the documentation. - void segment(static_vector& described_codeblocks, - span codeword_llrs, - unsigned tbs, - const segmenter_config& cfg) override; - -private: - /// Default constructor. - ldpc_segmenter_impl() = default; - - /// \brief Creates an LDPC segmentation object that aggregates a crc_calculator. - /// - /// \param[in] c The CRC calculators to aggregate. The generation polynomials must math their respective types. - explicit ldpc_segmenter_impl(sch_crc c) : crc_set({std::move(c.crc16), std::move(c.crc24A), std::move(c.crc24B)}) {} - - /// Computes the length of the rate-matched codeblock corresponding to each segment, as per TS38.212 - /// Section 5.4.2.1. - unsigned compute_rm_length(unsigned i_seg, modulation_scheme mod, unsigned nof_layers) const; - - /// Internally computed segment metadata. - struct segment_internal { - /// Segment index. - unsigned i_segment; - /// Total codeword length. - units::bits cw_length; - /// Codeblock starting index within the codeword. - unsigned cw_offset; - /// Number of filler bits. - units::bits nof_filler_bits; - /// Number of segment-specific CRC bits. - units::bits nof_crc_bits; - /// Number of TB-specific CRC bits. - units::bits nof_tb_crc_bits; - }; - - /// Generates a codeblock metadata structure for the current segment configuration. - codeblock_metadata generate_cb_metadata(const segment_internal& seg_extra, const segmenter_config& cfg) const; - - /// Base graph used for encoding/decoding the current transport block. - ldpc_base_graph_type base_graph = ldpc_base_graph_type::BG1; - /// Lifting size used for encoding/decoding the current transport block. - unsigned lifting_size = 0; - - /// \name Attributes relative to TS38.212 Section 5.2.2. - ///@{ - - /// Final length of a segment (corresponds to \f$K\f$). - units::bits segment_length{0}; - /// Number of bits in the transport block (corresponds to \f$B\f$). - units::bits nof_tb_bits_in{0}; - /// Augmented number of bits in the transport block, including new CRCs (corresponds to \f$B'\f$). - units::bits nof_tb_bits_out{0}; - /// Number of segments resulting from the transport block (corresponds to \f$C\f$). - unsigned nof_segments = 0; - ///@} - - /// \name Attributes relative to TS38.212 Section 5.4.2.1. - ///@{ - - /// Number of symbols per transmission layer (corresponds to \f$G / (N_L Q_m)\f$). - unsigned nof_symbols_per_layer = 0; - /// \brief Number of segments of short rate-matched length (corresponds to \f$C - \bigr(\bigl(G / (N_L Q_m)\bigr) - /// \bmod C\bigr)\f$). - unsigned nof_short_segments = 0; - ///@} - - /// CRC calculators for transport-block and segment-specific checksums. - sch_crc crc_set; -}; - -} // namespace srsran diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.cpp new file mode 100644 index 0000000000..614c8d6153 --- /dev/null +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.cpp @@ -0,0 +1,94 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "ldpc_segmenter_rx_impl.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" +#include "srsran/phy/upper/codeblock_metadata.h" +#include "srsran/srsvec/bit.h" +#include "srsran/srsvec/copy.h" +#include "srsran/support/math/math_utils.h" +#include "srsran/support/srsran_assert.h" + +using namespace srsran; +using namespace srsran::ldpc; + +/// Length of the CRC checksum added to the segments. +static constexpr units::bits SEG_CRC_LENGTH{24}; + +static void check_inputs_rx(span codeword_llrs, const segmenter_config& cfg) +{ + srsran_assert(!codeword_llrs.empty(), "Argument transport_block should not be empty."); + srsran_assert(codeword_llrs.size() == cfg.nof_ch_symbols * get_bits_per_symbol(cfg.mod), + "Wrong number of LLRs {} (expected {}).", + codeword_llrs.size(), + cfg.nof_ch_symbols * get_bits_per_symbol(cfg.mod)); + + srsran_assert((cfg.rv >= 0) && (cfg.rv <= 3), "Invalid redundancy version."); + + srsran_assert((cfg.nof_layers >= 1) && (cfg.nof_layers <= 4), "Invalid number of layers."); + + srsran_assert(cfg.nof_ch_symbols % (cfg.nof_layers) == 0, + "The number of channel symbols should be a multiple of the product between the number of layers."); +} + +void ldpc_segmenter_rx_impl::segment(static_vector& described_codeblocks, + span codeword_llrs, + unsigned tbs, + const segmenter_config& cfg) +{ + check_inputs_rx(codeword_llrs, cfg); + + using namespace units::literals; + + params.base_graph = cfg.base_graph; + + units::bits tbs_bits(tbs); + params.nof_tb_crc_bits = compute_tb_crc_size(tbs_bits); + + params.nof_tb_bits_in = tbs_bits + params.nof_tb_crc_bits; + + params.nof_segments = ldpc::compute_nof_codeblocks(tbs_bits, params.base_graph); + params.nof_tb_bits_out = params.nof_tb_bits_in; + if (params.nof_segments > 1) { + params.nof_tb_bits_out += units::bits(params.nof_segments * SEG_CRC_LENGTH.value()); + } + params.lifting_size = compute_lifting_size(tbs_bits, params.base_graph, params.nof_segments); + params.segment_length = compute_codeblock_size(params.base_graph, params.lifting_size); + + params.nof_crc_bits = (params.nof_segments > 1) ? SEG_CRC_LENGTH : 0_bits; + + // Compute the maximum number of information bits that can be assigned to a segment. + units::bits max_info_bits = + units::bits(divide_ceil(params.nof_tb_bits_out.value(), params.nof_segments)) - params.nof_crc_bits; + + // Number of channel symbols assigned to a transmission layer. + params.nof_symbols_per_layer = cfg.nof_ch_symbols / cfg.nof_layers; + // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to + // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is + // rounded up. + params.nof_short_segments = params.nof_segments - (params.nof_symbols_per_layer % params.nof_segments); + + // Codeword length (after concatenation of codeblocks). + params.cw_length = static_cast(codeword_llrs.size()); + + unsigned cw_offset = 0; + for (unsigned i_segment = 0; i_segment != params.nof_segments; ++i_segment) { + params.cw_offset[i_segment] = cw_offset; + params.nof_filler_bits = params.segment_length - (max_info_bits + params.nof_crc_bits); + + codeblock_metadata tmp_description = generate_cb_metadata(params, cfg, i_segment); + + unsigned rm_length = tmp_description.cb_specific.rm_length; + described_codeblocks.push_back({codeword_llrs.subspan(cw_offset, rm_length), tmp_description}); + cw_offset += rm_length; + } + // After accumulating all codeblock rate-matched lengths, cw_offset should be the same as cw_length. + srsran_assert(params.cw_length.value() == cw_offset, "Cw offset must be equal to the cw length"); +} diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.h new file mode 100644 index 0000000000..d6eb035fa6 --- /dev/null +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx_impl.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief LDPC codeblock segmentation declaration. + +#pragma once + +#include "ldpc_graph_impl.h" +#include "ldpc_segmenter_helpers.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_rx.h" + +namespace srsran { + +/// \brief Generic implementation of Rx-chain LDPC segmentation. +class ldpc_segmenter_rx_impl : public ldpc_segmenter_rx +{ +public: + /// Default constructor. + ldpc_segmenter_rx_impl() = default; + + // See interface for the documentation. + void segment(static_vector& described_codeblocks, + span codeword_llrs, + unsigned tbs, + const segmenter_config& cfg) override; + +private: + /// Segmentation parameters. + segment_parameters params; +}; + +} // namespace srsran diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.cpp b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.cpp new file mode 100644 index 0000000000..872a750ab1 --- /dev/null +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.cpp @@ -0,0 +1,242 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "ldpc_segmenter_tx_impl.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" +#include "srsran/phy/upper/codeblock_metadata.h" +#include "srsran/srsvec/bit.h" +#include "srsran/srsvec/copy.h" +#include "srsran/support/math/math_utils.h" +#include "srsran/support/srsran_assert.h" + +using namespace srsran; +using namespace srsran::ldpc; + +/// Length of the CRC checksum added to the segments. +static constexpr units::bits SEG_CRC_LENGTH{24}; +/// Maximum accepted transport block size. +/// Note: This value has to be multiple of 8. +static constexpr units::bits MAX_TBS{1277992}; +static_assert(MAX_TBS.is_byte_exact(), "Value is not a multiple of 8"); + +static void check_inputs_tx(span transport_block, const segmenter_config& cfg) +{ + using namespace units::literals; + srsran_assert(!transport_block.empty(), "Argument transport_block should not be empty."); + srsran_assert(units::bytes(transport_block.size()).to_bits() + 24_bits <= MAX_TBS, + "Transport block too long. The admissible size, including CRC, is {}.", + MAX_TBS.truncate_to_bytes()); + + srsran_assert((cfg.rv >= 0) && (cfg.rv <= 3), "Invalid redundancy version."); + + srsran_assert((cfg.nof_layers >= 1) && (cfg.nof_layers <= 4), "Invalid number of layers."); + + srsran_assert(cfg.nof_ch_symbols % (cfg.nof_layers) == 0, + "The number of channel symbols should be a multiple of the product between the number of layers."); +} + +// For the Tx-chain segmenter without using an intermediate buffer. +ldpc_segmenter_buffer& ldpc_segmenter_tx_impl::new_transmission(span transport_block, + const segmenter_config& cfg) +{ + check_inputs_tx(transport_block, cfg); + + using namespace units::literals; + + params.base_graph = cfg.base_graph; + // Each transport_block entry is a byte, and TBS can always be expressed as an integer number of bytes (see, e.g., + // TS38.214 Section 5.1.3.2). + units::bits nof_tb_bits_tmp = units::bytes(transport_block.size()).to_bits(); + + params.nof_tb_crc_bits = compute_tb_crc_size(nof_tb_bits_tmp); + + params.nof_tb_bits_in = nof_tb_bits_tmp + params.nof_tb_crc_bits; + + params.nof_segments = ldpc::compute_nof_codeblocks(nof_tb_bits_tmp, params.base_graph); + params.nof_tb_bits_out = params.nof_tb_bits_in; + if (params.nof_segments > 1) { + params.nof_tb_bits_out += units::bits(params.nof_segments * SEG_CRC_LENGTH.value()); + } + params.lifting_size = compute_lifting_size(nof_tb_bits_tmp, params.base_graph, params.nof_segments); + params.segment_length = compute_codeblock_size(params.base_graph, params.lifting_size); + + params.nof_crc_bits = (params.nof_segments > 1) ? SEG_CRC_LENGTH : 0_bits; + + // Compute the number of information bits that is assigned to a segment. + params.cb_info_bits = + units::bits(divide_ceil(params.nof_tb_bits_out.value(), params.nof_segments)) - params.nof_crc_bits; + + // Zero-padding if necessary. + params.zero_pad = + units::bits((params.cb_info_bits + params.nof_crc_bits).value() * params.nof_segments) - params.nof_tb_bits_out; + + // Number of channel symbols assigned to a transmission layer. + params.nof_symbols_per_layer = cfg.nof_ch_symbols / cfg.nof_layers; + // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to + // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is + // rounded up. + params.nof_short_segments = params.nof_segments - (params.nof_symbols_per_layer % params.nof_segments); + + // Codeword length (after concatenation of codeblocks). + params.cw_length = static_cast(cfg.nof_ch_symbols * get_bits_per_symbol(cfg.mod)); + + // Number of filler bits in this segment. + params.nof_filler_bits = params.segment_length - params.cb_info_bits - params.nof_crc_bits; + + unsigned cw_offset = 0; + unsigned tb_offset = 0; + for (unsigned i_segment = 0; i_segment != params.nof_segments; ++i_segment) { + bool last_cb = (i_segment == params.nof_segments - 1); + + // Save codeblock offsets. + params.cw_offset[i_segment] = cw_offset; + params.tb_offset[i_segment] = tb_offset; + + // Generate metadata for this segment. + params.cb_metadata[i_segment] = generate_cb_metadata(params, cfg, i_segment); + + // Number of information bits to get from the transport block. Remove transport block CRC bits if it is the last CB. + units::bits nof_used_bits = params.cb_info_bits; + if (last_cb) { + nof_used_bits -= params.nof_tb_crc_bits + params.zero_pad; + params.cb_info_bits_last = nof_used_bits; + tb_offset += params.nof_tb_crc_bits.value(); + } + + // Advance codeblock offsets. + tb_offset += nof_used_bits.value(); + cw_offset += this->get_rm_length(i_segment); + } + + // After segmenting no bits should be left in the buffer. + srsran_assert(params.nof_tb_bits_in.value() == tb_offset, + "Transport block offset ({}) must be equal to the transport block size including CRC ({}).", + tb_offset, + params.nof_tb_bits_in); + // After accumulating all codeblock rate-matched lengths, cw_offset should be the same as cw_length. + srsran_assert(params.cw_length.value() == cw_offset, + "Codeblock offset ({}) must be equal to the codeword size ({}).", + cw_offset, + params.cw_length.value()); + + return *this; +} + +void ldpc_segmenter_tx_impl::read_codeblock(bit_buffer codeblock, + span transport_block, + unsigned cb_index) const +{ + srsran_assert(codeblock.size() == params.segment_length.value(), + "Invalid codeblock size (i.e., {}), expected {}.", + codeblock.size(), + params.segment_length.value()); + srsran_assert(cb_index < params.nof_segments, + "Codeblock index ({}) must be lower than the number of segments ({}).", + cb_index, + params.nof_segments); + + using namespace units::literals; + + units::bits nof_used_bits = 0_bits; + unsigned nof_segment_bits = this->get_cb_info_bits(cb_index).value(); + + // Copy codeblock data. + { + bit_buffer message = codeblock.first(nof_segment_bits); + srsvec::copy_offset(message, transport_block, params.tb_offset[cb_index]); + nof_used_bits += units::bits(nof_segment_bits); + } + + // Append transport block CRC if applicable. + if ((params.tb_offset[cb_index] + nof_segment_bits) == units::bytes(transport_block.size()).to_bits().value()) { + // Append TB CRC. + constexpr units::bits MAX_BITS_CRC16{3824}; + crc_calculator& tb_crc = + (units::bytes(transport_block.size()).to_bits() <= MAX_BITS_CRC16) ? *crc_set.crc16 : *crc_set.crc24A; + crc_calculator_checksum_t tb_checksum = tb_crc.calculate_byte(transport_block); + + for (unsigned i_checksum_byte = 0, i_checksum_byte_end = params.nof_tb_crc_bits.truncate_to_bytes().value(); + i_checksum_byte != i_checksum_byte_end; + ++i_checksum_byte) { + // Extract byte from the CRC. + unsigned tb_crc_byte = (tb_checksum >> (params.nof_tb_crc_bits.value() - (i_checksum_byte + 1) * 8)) & 0xffUL; + // Insert the byte at the end of the bit buffer. + codeblock.insert(tb_crc_byte, nof_used_bits.value(), 8); + // Increment the number of bits. + nof_used_bits += 8_bits; + } + + // Insert zero padding bits. + for (units::bits nof_used_bits_end = nof_used_bits + params.zero_pad; nof_used_bits != nof_used_bits_end;) { + // Calculate the number of zeros to pad, no more than a byte at a time. + units::bits nof_zeros = std::min(8_bits, nof_used_bits_end - nof_used_bits); + // Insert the zeros at the end of the bit buffer. + codeblock.insert(0UL, nof_used_bits.value(), nof_zeros.value()); + // Increment the number of bits. + nof_used_bits += nof_zeros; + } + } + + // Append codeblock CRC if applicable. + if (params.nof_crc_bits != 0_bits) { + crc_calculator_checksum_t cb_checksum = crc_set.crc24B->calculate(codeblock.first(nof_used_bits.value())); + for (unsigned i_checksum_byte = 0, i_checksum_byte_end = 3; i_checksum_byte != i_checksum_byte_end; + ++i_checksum_byte) { + // Extract byte from the CRC. + unsigned cb_crc_byte = (cb_checksum >> (24 - (i_checksum_byte + 1) * 8)) & 0xffUL; + // Insert the byte at the end of the bit buffer. + codeblock.insert(cb_crc_byte, nof_used_bits.value(), 8); + // Increment the number of bits. + nof_used_bits += 8_bits; + } + } + + // Append filler bits as zeros. + while (nof_used_bits != params.segment_length) { + // Calculate the number of zeros to pad, no more than a byte at a time. + units::bits nof_zeros = std::min(8_bits, units::bits(params.segment_length) - nof_used_bits); + // Insert the zeros at the end of the bit buffer. + codeblock.insert(0UL, nof_used_bits.value(), nof_zeros.value()); + // Increment the number of bits. + nof_used_bits += nof_zeros; + } +} + +codeblock_metadata ldpc_segmenter_tx_impl::get_cb_metadata(unsigned cb_index) const +{ + srsran_assert(cb_index < params.nof_segments, + "Codeblock index ({}) must be lower than the number of segments ({}).", + cb_index, + params.nof_segments); + + return params.cb_metadata[cb_index]; +} + +units::bits ldpc_segmenter_tx_impl::get_cb_info_bits(unsigned cb_index) const +{ + srsran_assert(cb_index < params.nof_segments, + "Codeblock index ({}) must be lower than the number of segments ({}).", + cb_index, + params.nof_segments); + + bool last_cb = (cb_index == params.nof_segments - 1); + + return last_cb ? params.cb_info_bits_last : params.cb_info_bits; +} + +unsigned ldpc_segmenter_tx_impl::get_rm_length(unsigned cb_index) const +{ + srsran_assert(cb_index < params.nof_segments, + "Codeblock index ({}) must be lower than the number of segments ({}).", + cb_index, + params.nof_segments); + + return params.cb_metadata[cb_index].cb_specific.rm_length; +} diff --git a/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.h b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.h new file mode 100644 index 0000000000..68f2438455 --- /dev/null +++ b/lib/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx_impl.h @@ -0,0 +1,97 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +/// \file +/// \brief Tx-chain bufferless LDPC codeblock segmentation. + +#pragma once + +#include "ldpc_graph_impl.h" +#include "ldpc_segmenter_helpers.h" +#include "srsran/phy/upper/channel_coding/crc_calculator.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h" + +namespace srsran { + +/// \brief Bufferless implementation of Tx-chain LDPC segmentation. +class ldpc_segmenter_tx_impl : public ldpc_segmenter_tx, private ldpc_segmenter_buffer +{ +public: + /// CRC calculators used in shared channels. + struct sch_crc { + /// For short TB checksums. + std::unique_ptr crc16; + /// For long TB checksums. + std::unique_ptr crc24A; + /// For segment-specific checksums. + std::unique_ptr crc24B; + }; + + /// \brief Initializes the internal Tx-chain LDPC segmenter blocks. + /// \param[in] crc Unique pointers to CRC calculators. + ldpc_segmenter_tx_impl(sch_crc& c) : crc_set({std::move(c.crc16), std::move(c.crc24A), std::move(c.crc24B)}) + { + srsran_assert(crc_set.crc16, "Invalid CRC16 calculator."); + srsran_assert(crc_set.crc24A, "Invalid CRC24A calculator."); + srsran_assert(crc_set.crc24B, "Invalid CRC24B calculator."); + srsran_assert(crc_set.crc16->get_generator_poly() == crc_generator_poly::CRC16, + "Not a CRC generator of type CRC16."); + srsran_assert(crc_set.crc24A->get_generator_poly() == crc_generator_poly::CRC24A, + "Not a CRC generator of type CRC24A."); + srsran_assert(crc_set.crc24B->get_generator_poly() == crc_generator_poly::CRC24B, + "Not a CRC generator of type CRC24B."); + } + + // See interface for the documentation. + ldpc_segmenter_buffer& new_transmission(span transport_block, const segmenter_config& cfg) override; + +private: + /// Segmentation parameters. + segment_parameters params; + + /// CRC calculators for transport-block and segment-specific checksums. + sch_crc crc_set; + + // See ldpc_segmenter_buffer interface for documentation. + void read_codeblock(bit_buffer codeblock, span transport_block, unsigned cb_index) const override; + + // See ldpc_segmenter_buffer interface for documentation. + codeblock_metadata get_cb_metadata(unsigned cb_index) const override; + + // See ldpc_segmenter_buffer interface for documentation. + unsigned get_nof_codeblocks() const override { return params.nof_segments; }; + + // See ldpc_segmenter_buffer interface for documentation. + units::bits get_cb_info_bits(unsigned cb_index) const override; + + // See ldpc_segmenter_buffer interface for documentation. + units::bits get_segment_length() const override { return params.segment_length; }; + + // See ldpc_segmenter_buffer interface for documentation. + units::bits get_cw_length() const override { return params.cw_length; }; + + // See ldpc_segmenter_buffer interface for documentation. + units::bits get_zero_pad() const override { return params.zero_pad; }; + + // See ldpc_segmenter_buffer interface for documentation. + units::bits get_tb_crc_bits() const override { return params.nof_tb_crc_bits; }; + + // See ldpc_segmenter_buffer interface for documentation. + units::bits get_nof_filler_bits() const override { return params.nof_filler_bits; }; + + // See ldpc_segmenter_buffer interface for documentation. + unsigned get_nof_short_segments() const override { return params.nof_short_segments; }; + + // See ldpc_segmenter_buffer interface for documentation. + unsigned get_rm_length(unsigned cb_index) const override; +}; + +} // namespace srsran diff --git a/lib/phy/upper/channel_processors/pdsch/factories.cpp b/lib/phy/upper/channel_processors/pdsch/factories.cpp index 1b8d2799db..90138a6e1c 100644 --- a/lib/phy/upper/channel_processors/pdsch/factories.cpp +++ b/lib/phy/upper/channel_processors/pdsch/factories.cpp @@ -148,7 +148,7 @@ class pdsch_processor_factory_sw : public pdsch_processor_factory class pdsch_processor_concurrent_factory_sw : public pdsch_processor_factory { public: - pdsch_processor_concurrent_factory_sw(std::shared_ptr crc_factory, + pdsch_processor_concurrent_factory_sw(std::shared_ptr segmenter_factory_, std::shared_ptr encoder_factory, std::shared_ptr rate_matcher_factory, std::shared_ptr prg_factory_, @@ -158,9 +158,12 @@ class pdsch_processor_concurrent_factory_sw : public pdsch_processor_factory std::shared_ptr ptrs_factory, task_executor& executor_, unsigned nof_concurrent_threads) : - prg_factory(std::move(prg_factory_)), rg_mapper_factory(std::move(rg_mapper_factory_)), executor(executor_) + segmenter_factory(std::move(segmenter_factory_)), + prg_factory(std::move(prg_factory_)), + rg_mapper_factory(std::move(rg_mapper_factory_)), + executor(executor_) { - srsran_assert(crc_factory, "Invalid CRC calculator factory."); + srsran_assert(segmenter_factory, "Invalid segmenter factory."); srsran_assert(encoder_factory, "Invalid encoder factory."); srsran_assert(rate_matcher_factory, "Invalid rate matcher factory."); srsran_assert(prg_factory, "Invalid PRG factory."); @@ -174,10 +177,7 @@ class pdsch_processor_concurrent_factory_sw : public pdsch_processor_factory std::vector> cb_processors; for (unsigned i_encoder = 0; i_encoder != nof_concurrent_threads; ++i_encoder) { cb_processors.emplace_back( - std::make_unique(crc_factory->create(crc_generator_poly::CRC24A), - crc_factory->create(crc_generator_poly::CRC24B), - crc_factory->create(crc_generator_poly::CRC16), - encoder_factory->create(), + std::make_unique(encoder_factory->create(), rate_matcher_factory->create(), prg_factory->create(), modulator_factory->create_modulation_mapper())); @@ -210,7 +210,8 @@ class pdsch_processor_concurrent_factory_sw : public pdsch_processor_factory std::unique_ptr create() override { - return std::make_unique(cb_processor_pool, + return std::make_unique(segmenter_factory->create(), + cb_processor_pool, prg_factory->create(), rg_mapper_factory->create(), dmrs_generator_pool, @@ -224,6 +225,7 @@ class pdsch_processor_concurrent_factory_sw : public pdsch_processor_factory } private: + std::shared_ptr segmenter_factory; std::shared_ptr prg_factory; std::shared_ptr rg_mapper_factory; task_executor& executor; @@ -415,9 +417,9 @@ srsran::create_pdsch_processor_factory_sw(std::shared_ptr } std::shared_ptr -srsran::create_pdsch_concurrent_processor_factory_sw(std::shared_ptr crc_factory, - std::shared_ptr ldpc_enc_factory, - std::shared_ptr ldpc_rm_factory, +srsran::create_pdsch_concurrent_processor_factory_sw(std::shared_ptr ldpc_segmenter_factory, + std::shared_ptr ldpc_enc_factory, + std::shared_ptr ldpc_rm_factory, std::shared_ptr prg_factory, std::shared_ptr rg_mapper_factory, std::shared_ptr modulator_factory, @@ -426,7 +428,7 @@ srsran::create_pdsch_concurrent_processor_factory_sw(std::shared_ptr(std::move(crc_factory), + return std::make_shared(std::move(ldpc_segmenter_factory), std::move(ldpc_enc_factory), std::move(ldpc_rm_factory), std::move(prg_factory), @@ -476,4 +478,4 @@ std::unique_ptr pdsch_processor_factory::create(srslog::basic_l bool enable_logging_broadcast) { return std::make_unique(logger, enable_logging_broadcast, create()); -} \ No newline at end of file +} diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.cpp b/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.cpp index 3a8e9c8870..f1f76bc8b9 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.cpp +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.cpp @@ -12,8 +12,9 @@ using namespace srsran; -pdsch_codeblock_processor::result pdsch_codeblock_processor::process(span data, - const configuration& config) +pdsch_codeblock_processor::result pdsch_codeblock_processor::process(span data, + const ldpc_segmenter_buffer& segment_buffer, + const configuration& config) { using namespace units::literals; @@ -24,7 +25,6 @@ pdsch_codeblock_processor::result pdsch_codeblock_processor::process(spanadvance(config.metadata.cb_specific.cw_offset); // Prepare codeblock data. - units::bits nof_used_bits = 0_bits; cb_data.resize(config.cb_size.value()); // Calculate transport block size. @@ -39,7 +39,7 @@ pdsch_codeblock_processor::result pdsch_codeblock_processor::process(span= 1, "Number of bits per resource element must be greater than or equal to 1."); - // Copy codeblock data. - { - bit_buffer message = cb_data.first(config.cb_info_size.value()); - srsvec::copy_offset(message, data, config.tb_offset.value()); - nof_used_bits += units::bits(config.cb_info_size); - } - - // Append transport block CRC if applicable. - if ((config.tb_offset + config.cb_info_size) == tbs) { - constexpr units::bits MAX_BITS_CRC16{3824}; - crc_calculator& tb_crc = (tbs <= MAX_BITS_CRC16) ? *crc16 : *crc24a; - units::bits nof_tb_crc_bits = units::bits(get_crc_size(tb_crc.get_generator_poly())); - - crc_calculator_checksum_t tb_checksum = tb_crc.calculate_byte(data); - for (unsigned i_checksum_byte = 0, i_checksum_byte_end = nof_tb_crc_bits.truncate_to_bytes().value(); - i_checksum_byte != i_checksum_byte_end; - ++i_checksum_byte) { - // Extract byte from the CRC. - unsigned tb_crc_byte = (tb_checksum >> (nof_tb_crc_bits.value() - (i_checksum_byte + 1) * 8)) & 0xffUL; - // Insert the byte at the end of the bit buffer. - cb_data.insert(tb_crc_byte, nof_used_bits.value(), 8); - // Increment the number of bits. - nof_used_bits += 8_bits; - } - - // Insert zero padding bits. - for (units::bits nof_used_bits_end = nof_used_bits + config.zero_pad; nof_used_bits != nof_used_bits_end;) { - // Calculate the number of zeros to pad, no more than a byte at a time. - units::bits nof_zeros = std::min(8_bits, nof_used_bits_end - nof_used_bits); - // Insert the zeros at the end of the bit buffer. - cb_data.insert(0UL, nof_used_bits.value(), nof_zeros.value()); - // Increment the number of bits. - nof_used_bits += nof_zeros; - } - } - - // Append codeblock CRC if applicable. - if (config.has_cb_crc) { - crc_calculator& cb_crc = *crc24b; - - crc_calculator_checksum_t cb_checksum = cb_crc.calculate(cb_data.first(nof_used_bits.value())); - for (unsigned i_checksum_byte = 0, i_checksum_byte_end = 3; i_checksum_byte != i_checksum_byte_end; - ++i_checksum_byte) { - // Extract byte from the CRC. - unsigned cb_crc_byte = (cb_checksum >> (24 - (i_checksum_byte + 1) * 8)) & 0xffUL; - // Insert the byte at the end of the bit buffer. - cb_data.insert(cb_crc_byte, nof_used_bits.value(), 8); - // Increment the number of bits. - nof_used_bits += 8_bits; - } - } - - // Append filler bits as zeros. - while (nof_used_bits != config.cb_size) { - // Calculate the number of zeros to pad, no more than a byte at a time. - units::bits nof_zeros = std::min(8_bits, units::bits(config.cb_size) - nof_used_bits); - // Insert the zeros at the end of the bit buffer. - cb_data.insert(0UL, nof_used_bits.value(), nof_zeros.value()); - // Increment the number of bits. - nof_used_bits += nof_zeros; - } + // Copy codeblock data, including TB and/or CB CRC if applicable, as well as filler and zero padding bits. + segment_buffer.read_codeblock(cb_data, data, config.cb_index); // Encode the segment into a codeblock. const ldpc_encoder_buffer& rm_buffer = encoder->encode(cb_data, config.metadata.tb_common); diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.h b/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.h index 47933ec0a4..ddec0f9354 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.h +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_codeblock_processor.h @@ -13,6 +13,7 @@ #include "srsran/phy/upper/channel_coding/crc_calculator.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" #include "srsran/phy/upper/channel_modulation/modulation_mapper.h" #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" #include "srsran/ran/pdsch/pdsch_constants.h" @@ -40,6 +41,8 @@ class pdsch_codeblock_processor public: /// Collects the parameters necessary for processing a PDSCH codeblock. struct configuration { + /// Index of the codeblock within the transport block. + unsigned cb_index; /// Position of the codeblock relative to the first bit of the transport block. units::bits tb_offset; /// Codeblock number of information bits. @@ -65,27 +68,15 @@ class pdsch_codeblock_processor }; /// Builds a codeblock processor with the required dependencies. - pdsch_codeblock_processor(std::unique_ptr crc24a_, - std::unique_ptr crc24b_, - std::unique_ptr crc16_, - std::unique_ptr encoder_, + pdsch_codeblock_processor(std::unique_ptr encoder_, std::unique_ptr rate_matcher_, std::unique_ptr scrambler_, std::unique_ptr modulator_) : - crc24a(std::move(crc24a_)), - crc24b(std::move(crc24b_)), - crc16(std::move(crc16_)), encoder(std::move(encoder_)), rate_matcher(std::move(rate_matcher_)), scrambler(std::move(scrambler_)), modulator(std::move(modulator_)) { - srsran_assert(crc24a, "Invalid CRC calculator."); - srsran_assert(crc24b, "Invalid CRC calculator."); - srsran_assert(crc16, "Invalid CRC calculator."); - srsran_assert(crc24a->get_generator_poly() == crc_generator_poly::CRC24A, "Invalid CRC calculator."); - srsran_assert(crc24b->get_generator_poly() == crc_generator_poly::CRC24B, "Invalid CRC calculator."); - srsran_assert(crc16->get_generator_poly() == crc_generator_poly::CRC16, "Invalid CRC calculator."); srsran_assert(encoder, "Invalid LDPC encoder."); srsran_assert(rate_matcher, "Invalid LDPC rate matcher."); srsran_assert(scrambler, "Invalid scrambler."); @@ -100,7 +91,7 @@ class pdsch_codeblock_processor /// \param[in] data Original transport block data without CRC. /// \param[in] config Required parameters for processing a codeblock. /// \return A struct with the results. - result process(span data, const configuration& config); + result process(span data, const ldpc_segmenter_buffer& segment_buffer, const configuration& config); /// Gets the QAM modulation scaling, as per TS38.211 Section 5.1. float get_scaling(modulation_scheme modulation) @@ -110,12 +101,6 @@ class pdsch_codeblock_processor } private: - /// Pointer to CRC24A. - std::unique_ptr crc24a; - /// Pointer to CRC24B. - std::unique_ptr crc24b; - /// Pointer to CRC16. - std::unique_ptr crc16; /// Pointer to an LDPC encoder. std::unique_ptr encoder; /// Pointer to an LDPC rate matcher. diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.cpp b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.cpp index 8f82f4f075..2c1029ac8e 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.cpp @@ -16,9 +16,6 @@ using namespace srsran; using namespace srsran::ldpc; -/// Length of the CRC checksum added to the segments. -static constexpr units::bits SEG_CRC_LENGTH{24}; - void pdsch_encoder_hw_impl::encode(span codeword, span transport_block, const configuration& config) @@ -50,14 +47,15 @@ void pdsch_encoder_hw_impl::encode(span codeword, segmenter_cfg.nof_layers = config.nof_layers; segmenter_cfg.nof_ch_symbols = config.nof_ch_symbols; - if (cb_mode) { - // Clear the buffer. - d_segments.clear(); + // Initialize the segmenter. + segment_buffer = &segmenter->new_transmission(transport_block, segmenter_cfg); - // Segmentation (it includes CRC attachment for the entire transport block and each individual segment). - segmenter->segment(d_segments, transport_block, segmenter_cfg); + units::bits cb_size = segment_buffer->get_segment_length(); + if (cb_mode) { + // Prepare codeblock data. + cb_data.resize(cb_size.value()); } - set_hw_enc_tb_configuration(hw_cfg, transport_block, d_segments, segmenter_cfg); + set_hw_enc_tb_configuration(hw_cfg, transport_block, segmenter_cfg); if (cb_mode) { nof_ops = hw_cfg.nof_segments; } @@ -75,16 +73,17 @@ void pdsch_encoder_hw_impl::encode(span codeword, // Get the data to be encoded. span data; if (cb_mode) { - // Retrieve the CB. - described_segment& descr_seg = d_segments[cb_id]; + // Copy codeblock data, including TB and/or CB CRC if applicable, as well as filler and zero padding bits. + segment_buffer->read_codeblock(cb_data, transport_block, cb_id); // Set the encoding parameters of the CB as required by the hardware-accelerated PDSCH encoder. - set_hw_enc_cb_configuration(hw_cfg, descr_seg.get_metadata(), cb_id); + set_hw_enc_cb_configuration(hw_cfg, segment_buffer->get_cb_metadata(cb_id), cb_id); // Retrieve the current CB to be encoded. - unsigned segment_length = static_cast(descr_seg.get_data().size()) - hw_cfg.nof_filler_bits; + unsigned segment_length = + static_cast(segment_buffer->get_segment_length().value()) - hw_cfg.nof_filler_bits; unsigned segment_length_bytes = static_cast(ceil(static_cast(segment_length) / 8.0)); - data = descr_seg.get_data().get_buffer().first(segment_length_bytes); + data = cb_data.get_buffer().first(segment_length_bytes); } else { // Set the encoding parameters of the CB as required by the hardware-accelerated PDSCH encoder. set_hw_enc_cb_configuration(hw_cfg, {}, cb_id); @@ -124,7 +123,7 @@ void pdsch_encoder_hw_impl::encode(span codeword, unsigned rm_length = 0; span codeblock; if (cb_mode) { - rm_length = d_segments[cb_id].get_metadata().cb_specific.rm_length; + rm_length = segment_buffer->get_rm_length(cb_id); srsran_assert(offset + rm_length <= codeword.size(), "Wrong codeword length."); codeblock = span(codeword).subspan(offset, rm_length); @@ -170,37 +169,9 @@ void pdsch_encoder_hw_impl::encode(span codeword, encoder->free_queue(); } -/// \brief Computes the length of the rate-matched codeblock corresponding to each segment, -/// as per TS38.212 Section 5.4.2.1. -/// \param[in] i_seg Index of the segment. -/// \param[in] nof_segments Number of segments in the transport block. -/// \param[in] nof_short_segments Number of segments that will have a short rate-matched length. -/// \param[in] nof_symbols_per_layer Number of channel symbols assigned to a transmission layer. -/// \param[in] modulation_scheme Modulation scheme. -/// \param[in] nof_layers Number of transmission layers the transport block is mapped onto. -/// \return The length of the rate-matched codeblock corresponding to the indicated segment. -static unsigned compute_rm_length(unsigned i_seg, - unsigned nof_segments, - unsigned nof_short_segments, - unsigned nof_symbols_per_layer, - modulation_scheme mod, - unsigned nof_layers) -{ - unsigned tmp = 0; - if (i_seg < nof_short_segments) { - // For unsigned, division then floor is the same as integer division. - tmp = nof_symbols_per_layer / nof_segments; - } else { - tmp = divide_ceil(nof_symbols_per_layer, nof_segments); - } - return tmp * nof_layers * get_bits_per_symbol(mod); -} - -void pdsch_encoder_hw_impl::set_hw_enc_tb_configuration( - hal::hw_pdsch_encoder_configuration& hw_cfg, - span transport_block, - const static_vector& d_segs, - const segmenter_config& cfg) +void pdsch_encoder_hw_impl::set_hw_enc_tb_configuration(hal::hw_pdsch_encoder_configuration& hw_cfg, + span transport_block, + const segmenter_config& cfg) { using namespace units::literals; @@ -216,34 +187,19 @@ void pdsch_encoder_hw_impl::set_hw_enc_tb_configuration( // Each transport_block entry is a byte, and TBS can always be expressed as an integer number of bytes (see, e.g., // TS38.214 Section 5.1.3.2). units::bits nof_tb_bits = units::bytes(transport_block.size()).to_bits(); - units::bits nof_tb_crc_bits = ldpc::compute_tb_crc_size(nof_tb_bits); + units::bits nof_tb_crc_bits = segment_buffer->get_tb_crc_bits(); hw_cfg.nof_tb_bits = static_cast(nof_tb_bits.value()); hw_cfg.nof_tb_crc_bits = static_cast(nof_tb_crc_bits.value()); // Number of segments. - unsigned nof_segments = 0; - if (cb_mode) { - nof_segments = static_cast(d_segments.size()); - } else { - nof_segments = ldpc::compute_nof_codeblocks(nof_tb_bits, cfg.base_graph); - } - hw_cfg.nof_segments = nof_segments; - - // TB size in bits, accounting for CRC bits. - units::bits nof_tb_bits_out = nof_tb_bits + nof_tb_crc_bits; - uint8_t crc_byte_0 = 0; - uint8_t crc_byte_1 = 0; - uint8_t crc_byte_2 = 0; - if (nof_segments > 1) { - // Internally the CB CRC bits are also accounted for. - nof_tb_bits_out += units::bits(nof_segments * SEG_CRC_LENGTH.value()); - } + unsigned nof_segments = segment_buffer->get_nof_codeblocks(); + hw_cfg.nof_segments = nof_segments; // Compute the TB CRC bits (needed for both FPGA and bbdev). - crc_calculator_checksum_t tb_crc = compute_tb_crc(transport_block, hw_cfg.nof_tb_crc_bits); - crc_byte_0 = (static_cast(tb_crc) >> 16) & 0xff; - crc_byte_1 = (static_cast(tb_crc) >> 8) & 0xff; - crc_byte_2 = static_cast(tb_crc) & 0xff; + crc_calculator_checksum_t tb_crc = compute_tb_crc(transport_block, hw_cfg.nof_tb_crc_bits); + uint8_t crc_byte_0 = (static_cast(tb_crc) >> 16) & 0xff; + uint8_t crc_byte_1 = (static_cast(tb_crc) >> 8) & 0xff; + uint8_t crc_byte_2 = static_cast(tb_crc) & 0xff; if (hw_cfg.nof_tb_crc_bits > 16) { hw_cfg.tb_crc = {crc_byte_0, crc_byte_1, crc_byte_2}; } else { @@ -251,47 +207,29 @@ void pdsch_encoder_hw_impl::set_hw_enc_tb_configuration( hw_cfg.tb_crc = {crc_byte_1, crc_byte_2}; } - // Number of channel symbols assigned to a transmission layer. - unsigned nof_symbols_per_layer = cfg.nof_ch_symbols / cfg.nof_layers; // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is // rounded up. - unsigned nof_short_segments = nof_segments - (nof_symbols_per_layer % nof_segments); + unsigned nof_short_segments = segment_buffer->get_nof_short_segments(); hw_cfg.nof_short_segments = nof_short_segments; // Codeword length for short rate-matched segments in bits (Ea). The FPGA will insert the CB CRC, thus the CB size // needs to be adjusted. unsigned cw_length_a = 0; - codeblock_metadata common_cfg; - if (cb_mode) { - common_cfg = d_segments[0].get_metadata(); - cw_length_a = common_cfg.cb_specific.rm_length; - } else { - cw_length_a = - compute_rm_length(0, nof_segments, nof_short_segments, nof_symbols_per_layer, cfg.mod, cfg.nof_layers); - } - hw_cfg.cw_length_a = cw_length_a; + codeblock_metadata common_cfg = segment_buffer->get_cb_metadata(0); + cw_length_a = segment_buffer->get_rm_length(0); + hw_cfg.cw_length_a = cw_length_a; // Codeword length for long rate-matched segments in bits (Eb). The FPGA will insert the CB CRC, thus the CB size // needs to be adjusted. unsigned cw_length_b = cw_length_a; if (nof_segments > nof_short_segments) { - if (cb_mode) { - cw_length_b = d_segments[nof_short_segments].get_metadata().cb_specific.rm_length; - } else { - cw_length_b = compute_rm_length( - nof_short_segments, nof_segments, nof_short_segments, nof_symbols_per_layer, cfg.mod, cfg.nof_layers); - } + cw_length_b = segment_buffer->get_rm_length(nof_short_segments); } hw_cfg.cw_length_b = cw_length_b; // LDPC lifting size. - unsigned lifting_size = 0; - if (cb_mode) { - lifting_size = common_cfg.tb_common.lifting_size; - } else { - lifting_size = ldpc::compute_lifting_size(nof_tb_bits, cfg.base_graph, nof_segments); - } - hw_cfg.lifting_size = lifting_size; + unsigned lifting_size = common_cfg.tb_common.lifting_size; + hw_cfg.lifting_size = lifting_size; // Base graph index and length of the circular buffer in bits, as described in TS38.212 Section 5.4.2.1. unsigned N = 0; @@ -304,17 +242,13 @@ void pdsch_encoder_hw_impl::set_hw_enc_tb_configuration( hw_cfg.Ncb = N; hw_cfg.Nref = cfg.Nref; - // Number of CRC bits per segment. - units::bits nof_crc_bits = (nof_segments > 1) ? SEG_CRC_LENGTH : 0_bits; - // Number of information bits that is assigned to a segment. - units::bits cb_info_bits = units::bits(divide_ceil(nof_tb_bits_out.value(), nof_segments)) - nof_crc_bits; + units::bits cb_info_bits = segment_buffer->get_cb_info_bits(0); hw_cfg.nof_segment_bits = static_cast(cb_info_bits.value()); if (!cb_mode) { // Number of filler bits. - units::bits segment_length = ldpc::compute_codeblock_size(cfg.base_graph, lifting_size); - units::bits nof_filler_bits = segment_length - cb_info_bits - nof_crc_bits; + units::bits nof_filler_bits = segment_buffer->get_nof_filler_bits(); hw_cfg.nof_filler_bits = static_cast(nof_filler_bits.value()); } } diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.h b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.h index 73c666fda6..55c96db0cf 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.h +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_hw_impl.h @@ -16,6 +16,7 @@ #include "srsran/hal/hw_accelerator.h" #include "srsran/hal/phy/upper/channel_processors/hw_accelerator_pdsch_enc.h" #include "srsran/phy/upper/channel_coding/crc_calculator.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h" #include "srsran/phy/upper/channel_processors/pdsch/pdsch_encoder.h" #include "srsran/ran/pdsch/pdsch_constants.h" @@ -86,8 +87,13 @@ class pdsch_encoder_hw_impl : public pdsch_encoder /// Pointer to a Hardware-accelerated PDSCH encoder. std::unique_ptr encoder; - /// Buffer for storing data segments obtained after transport block segmentation. - static_vector d_segments = {}; + /// Pointer to an LDPC segmenter output buffer interface. + const ldpc_segmenter_buffer* segment_buffer; + + /// \brief Temporary codeblock message. + /// + /// It contains codeblock information bits, codeblock CRC (if applicable) and filler bits. + static_bit_buffer cb_data; /// Buffer for storing temporary encoded and packed codeblock. static_vector codeblock_packed; @@ -97,10 +103,9 @@ class pdsch_encoder_hw_impl : public pdsch_encoder /// \param[in] transport_block The transport block to encode (packed, one byte per entry). /// \param[in] d_segs Buffer storing the data segments comprising the transport block. /// \param[in] cfg PDSCH configuration parameters. - void set_hw_enc_tb_configuration(hal::hw_pdsch_encoder_configuration& hw_cfg, - span transport_block, - const static_vector& d_segs, - const segmenter_config& cfg); + void set_hw_enc_tb_configuration(hal::hw_pdsch_encoder_configuration& hw_cfg, + span transport_block, + const segmenter_config& cfg); /// \brief Computes the segmentation parameters required by the hardware-accelerated PDSCH encoder function. /// \param[out] hw_cfg Hardware-accelerated PDSCH encoder configuration parameters. diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.cpp b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.cpp index c2bbdd16c8..0e7ea7bd59 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.cpp @@ -17,9 +17,6 @@ void pdsch_encoder_impl::encode(span codeword, span transport_block, const configuration& config) { - // Clear the buffer. - d_segments.clear(); - segmenter_config segmenter_cfg; segmenter_cfg.base_graph = config.base_graph; segmenter_cfg.rv = config.rv; @@ -28,25 +25,32 @@ void pdsch_encoder_impl::encode(span codeword, segmenter_cfg.nof_layers = config.nof_layers; segmenter_cfg.nof_ch_symbols = config.nof_ch_symbols; - // Segmentation (it includes CRC attachment for the entire transport block and each individual segment). - segmenter->segment(d_segments, transport_block, segmenter_cfg); + // Initialize the segmenter. + const ldpc_segmenter_buffer& segment_buffer = segmenter->new_transmission(transport_block, segmenter_cfg); + + // Prepare codeblock data. + units::bits cb_size = segment_buffer.get_segment_length(); + cb_data.resize(cb_size.value()); unsigned offset = 0; - for (unsigned i_cb = 0, i_cb_end = d_segments.size(); i_cb != i_cb_end; ++i_cb) { - // Select segment description. - const described_segment& descr_seg = d_segments[i_cb]; + for (unsigned i_cb = 0, i_cb_end = segment_buffer.get_nof_codeblocks(); i_cb != i_cb_end; ++i_cb) { + // Retrieve segment description. + const codeblock_metadata cb_metadata = segment_buffer.get_cb_metadata(i_cb); + + // Copy codeblock data, including TB and/or CB CRC if applicable, as well as filler and zero padding bits. + segment_buffer.read_codeblock(cb_data, transport_block, i_cb); // Encode the segment into a codeblock. - const ldpc_encoder_buffer& rm_buffer = encoder->encode(descr_seg.get_data(), descr_seg.get_metadata().tb_common); + const ldpc_encoder_buffer& rm_buffer = encoder->encode(cb_data, cb_metadata.tb_common); // Select the correct chunk of the output codeword. - unsigned rm_length = descr_seg.get_metadata().cb_specific.rm_length; + unsigned rm_length = segment_buffer.get_rm_length(i_cb); srsran_assert(offset + rm_length <= codeword.size(), "Wrong codeword length."); span codeblock = span(codeword).subspan(offset, rm_length); // Rate match the codeblock. codeblock_packed.resize(rm_length); - rate_matcher->rate_match(codeblock_packed, rm_buffer, descr_seg.get_metadata()); + rate_matcher->rate_match(codeblock_packed, rm_buffer, cb_metadata); // Unpack code block. srsvec::bit_unpack(codeblock, codeblock_packed); diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.h b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.h index ecd622368f..99b0cc2664 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.h +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_encoder_impl.h @@ -15,6 +15,7 @@ #include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h" #include "srsran/phy/upper/channel_processors/pdsch/pdsch_encoder.h" #include "srsran/phy/upper/codeblock_metadata.h" @@ -51,8 +52,10 @@ class pdsch_encoder_impl : public pdsch_encoder /// Pointer to an LDPC rate matcher. std::unique_ptr rate_matcher; - /// Buffer for storing data segments obtained after transport block segmentation. - static_vector d_segments; + /// \brief Temporary codeblock message. + /// + /// It contains codeblock information bits, codeblock CRC (if applicable) and filler bits. + static_bit_buffer cb_data; /// \brief Maximum codeblock length. /// /// This is the maximum length of an encoded codeblock, achievable with base graph 1 (rate 1/3). diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.cpp b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.cpp index 53b4bd18e0..e4f26ebb49 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.cpp @@ -130,52 +130,39 @@ void pdsch_processor_concurrent_impl::save_inputs(resource_grid_writer& grid // Calculate number of codeblocks. nof_cb = ldpc::compute_nof_codeblocks(tbs, config.ldpc_base_graph); - // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to - // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is - // rounded up. - unsigned nof_short_segments = nof_cb - (nof_re_pdsch % nof_cb); - - // Compute number of CRC bits for the transport block. - units::bits nof_tb_crc_bits = ldpc::compute_tb_crc_size(tbs); + modulation_scheme modulation = config.codewords.front().modulation; + units::bits bits_per_symbol(get_bits_per_symbol(modulation)); - // Compute number of CRC bits for each codeblock. - units::bits nof_cb_crc_bits = (nof_cb > 1) ? 24_bits : 0_bits; + // Calculate rate match buffer size. + units::bits Nref = ldpc::compute_N_ref(config.tbs_lbrm, nof_cb); - // Calculate the total number of bits including transport block and codeblock CRC. - units::bits nof_tb_bits_out = tbs + nof_tb_crc_bits + units::bits(nof_cb_crc_bits * nof_cb); + // Initialize the segmenter. + segmenter_config segmenter_cfg; + segmenter_cfg.base_graph = config.ldpc_base_graph; + segmenter_cfg.rv = config.codewords.front().rv; + segmenter_cfg.mod = modulation; + segmenter_cfg.Nref = Nref.value(); + segmenter_cfg.nof_layers = nof_layers; + segmenter_cfg.nof_ch_symbols = nof_ch_symbols; - // Compute the number of information bits that is assigned to a codeblock. - cb_info_bits = units::bits(divide_ceil(nof_tb_bits_out.value(), nof_cb)) - nof_cb_crc_bits; + // Initialize the segmenter. + segment_buffer = &segmenter->new_transmission(data.get_buffer(), segmenter_cfg); - unsigned lifting_size = ldpc::compute_lifting_size(tbs, config.ldpc_base_graph, nof_cb); - segment_length = ldpc::compute_codeblock_size(config.ldpc_base_graph, lifting_size); + // Retrieve the segment length. + segment_length = segment_buffer->get_segment_length(); - modulation_scheme modulation = config.codewords.front().modulation; - units::bits bits_per_symbol(get_bits_per_symbol(modulation)); + // Number of segments that will have a short rate-matched length. In TS38.212 Section 5.4.2.1, these correspond to + // codeblocks whose length E_r is computed by rounding down - floor. For the remaining codewords, the length is + // rounded up. + unsigned nof_short_segments = segment_buffer->get_nof_short_segments(); - units::bits full_codeblock_size = ldpc::compute_full_codeblock_size(config.ldpc_base_graph, segment_length); - units::bits cw_length = units::bits(nof_re_pdsch * nof_layers * bits_per_symbol); - zero_pad = (cb_info_bits + nof_cb_crc_bits) * nof_cb - nof_tb_bits_out; + // Compute the number of information bits that is assigned to a codeblock. + cb_info_bits = segment_buffer->get_cb_info_bits(0); - // Calculate rate match buffer size. - units::bits Nref = ldpc::compute_N_ref(config.tbs_lbrm, nof_cb); + units::bits cw_length = segment_buffer->get_cw_length(); + zero_pad = segment_buffer->get_zero_pad(); - // Prepare codeblock metadata. - cb_metadata.tb_common.base_graph = config.ldpc_base_graph; - cb_metadata.tb_common.lifting_size = static_cast(lifting_size); - cb_metadata.tb_common.rv = config.codewords.front().rv; - cb_metadata.tb_common.mod = modulation; - cb_metadata.tb_common.Nref = Nref.value(); - cb_metadata.tb_common.cw_length = cw_length.value(); - cb_metadata.cb_specific.full_length = full_codeblock_size.value(); - cb_metadata.cb_specific.rm_length = 0; - cb_metadata.cb_specific.nof_filler_bits = (segment_length - cb_info_bits - nof_cb_crc_bits).value(); - cb_metadata.cb_specific.cw_offset = 0; - cb_metadata.cb_specific.nof_crc_bits = nof_tb_crc_bits.value(); - - // Calculate RM length for each codeblock. - rm_length.resize(nof_cb); - cw_offset.resize(nof_cb); + // Calculate RE offset for each codeblock. re_offset.resize(nof_cb); unsigned re_count_sum = 0; for (unsigned i_cb = 0; i_cb != nof_cb; ++i_cb) { @@ -185,12 +172,6 @@ void pdsch_processor_concurrent_impl::save_inputs(resource_grid_writer& grid rm_length_re = nof_re_pdsch / nof_cb; } - // Convert RM length from RE to bits. - rm_length[i_cb] = rm_length_re * nof_layers * bits_per_symbol; - - // Set and increment CW offset. - cw_offset[i_cb] = re_count_sum * nof_layers * bits_per_symbol; - // Set RE offset for the resource mapper. re_offset[i_cb] = re_count_sum; @@ -276,24 +257,21 @@ void pdsch_processor_concurrent_impl::fork_cb_batches() absolute_i_cb = nof_cb - 1 - absolute_i_cb; // Limit the codeblock number of information bits. - units::bits nof_info_bits = std::min(cb_info_bits, tbs - cb_info_bits * absolute_i_cb); + units::bits nof_info_bits = segment_buffer->get_cb_info_bits(absolute_i_cb); // Set CB processor configuration. pdsch_codeblock_processor::configuration cb_config; + cb_config.cb_index = absolute_i_cb; cb_config.tb_offset = cb_info_bits * absolute_i_cb; cb_config.has_cb_crc = nof_cb > 1; cb_config.cb_info_size = nof_info_bits; cb_config.cb_size = segment_length; cb_config.zero_pad = zero_pad; - cb_config.metadata = cb_metadata; + cb_config.metadata = segment_buffer->get_cb_metadata(absolute_i_cb); cb_config.c_init = scrambler->get_state(); - // Update codeblock specific metadata fields. - cb_config.metadata.cb_specific.cw_offset = cw_offset[absolute_i_cb].value(); - cb_config.metadata.cb_specific.rm_length = rm_length[absolute_i_cb].value(); - // Process codeblock. - pdsch_codeblock_processor::result result = cb_processor.process(data.get_buffer(), cb_config); + pdsch_codeblock_processor::result result = cb_processor.process(data.get_buffer(), *segment_buffer, cb_config); // Build resource grid mapper adaptor. resource_grid_mapper::symbol_buffer_adapter buffer(result.cb_symbols); diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.h b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.h index d59249272c..9bb7f9ba8c 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.h +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_concurrent_impl.h @@ -11,6 +11,8 @@ #include "pdsch_codeblock_processor.h" #include "srsran/phy/support/resource_grid_mapper.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h" #include "srsran/phy/upper/channel_processors/pdsch/pdsch_processor.h" #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" #include "srsran/phy/upper/signal_processors/dmrs_pdsch_processor.h" @@ -34,16 +36,19 @@ class pdsch_processor_concurrent_impl : public pdsch_processor using pdsch_ptrs_generator_pool = concurrent_thread_local_object_pool; /// \brief Creates a concurrent PDSCH processor with all the dependencies. + /// \param[in] segmenter_ LDPC segmenter. /// \param[in] cb_processor_pool_ Codeblock processor pool. /// \param[in] scrambler_ Scrambling pseudo-random generator. /// \param[in] dmrs_generator_pool_ DM-RS for PDSCH generator. /// \param[in] executor_ Asynchronous task executor. - pdsch_processor_concurrent_impl(std::shared_ptr cb_processor_pool_, + pdsch_processor_concurrent_impl(std::unique_ptr segmenter_, + std::shared_ptr cb_processor_pool_, std::unique_ptr scrambler_, std::unique_ptr mapper_, std::shared_ptr dmrs_generator_pool_, std::shared_ptr ptrs_generator_pool_, task_executor& executor_) : + segmenter(std::move(segmenter_)), scrambler(std::move(scrambler_)), mapper(std::move(mapper_)), cb_processor_pool(std::move(cb_processor_pool_)), @@ -51,6 +56,7 @@ class pdsch_processor_concurrent_impl : public pdsch_processor ptrs_generator_pool(std::move(ptrs_generator_pool_)), executor(executor_) { + srsran_assert(segmenter, "Invalid LDPC segmenter."); srsran_assert(scrambler, "Invalid scrambler pointer."); srsran_assert(cb_processor_pool, "Invalid CB processor pool pointer."); srsran_assert(dmrs_generator_pool, "Invalid DM-RS pointer."); @@ -73,6 +79,8 @@ class pdsch_processor_concurrent_impl : public pdsch_processor /// Creates code block processing batches and starts the asynchronous processing. void fork_cb_batches(); + /// Pointer to an LDPC segmenter. + std::unique_ptr segmenter; /// Pseudo-random generator. std::unique_ptr scrambler; /// Resource grid mapper. @@ -85,6 +93,8 @@ class pdsch_processor_concurrent_impl : public pdsch_processor std::shared_ptr ptrs_generator_pool; /// Asynchronous task executor. task_executor& executor; + /// Pointer to an LDPC segmenter output buffer interface. + const ldpc_segmenter_buffer* segment_buffer; resource_grid_writer* grid; pdsch_processor_notifier* notifier; @@ -111,10 +121,6 @@ class pdsch_processor_concurrent_impl : public pdsch_processor re_pattern_list reserved; /// Precoding configuration scaled. precoding_configuration precoding; - /// Rate matching length in bits for each of the segments. - static_vector rm_length; - /// Codeblock bit offset within the codeword. - static_vector cw_offset; /// Codeblock resource block offset. static_vector re_offset; /// Codeblock counter. diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.cpp b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.cpp index 268e993251..d92fae41ea 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.cpp +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.cpp @@ -57,38 +57,46 @@ void pdsch_block_processor::configure_new_transmission(span encoder_config.nof_layers = nof_layers; encoder_config.nof_ch_symbols = nof_re_pdsch * nof_layers; - // Clear the buffer. - d_segments.clear(); + // Initialize the segmenter. + segment_buffer = &segmenter.new_transmission(data, encoder_config); - // Segmentation (it includes CRC attachment for the entire transport block and each individual segment). - segmenter.segment(d_segments, data, encoder_config); + cb_size = segment_buffer->get_segment_length(); // Initialize the codeblock counter. next_i_cb = 0; + + // Save the pointer to the input data. + transport_block = data; } void pdsch_block_processor::new_codeblock() { - srsran_assert(next_i_cb < d_segments.size(), + srsran_assert(next_i_cb < segment_buffer->get_nof_codeblocks(), "The codeblock index (i.e., {}) exceeds the number of codeblocks (i.e., {})", next_i_cb, - d_segments.size()); + segment_buffer->get_nof_codeblocks()); + + // Prepare codeblock data. + cb_data.resize(cb_size.value()); - // Select segment description. - const described_segment& descr_seg = d_segments[next_i_cb]; + // Retrieve segment description. + const codeblock_metadata cb_metadata = segment_buffer->get_cb_metadata(next_i_cb); // Rate Matching output length. - unsigned rm_length = descr_seg.get_metadata().cb_specific.rm_length; + unsigned rm_length = segment_buffer->get_rm_length(next_i_cb); // Number of symbols. unsigned nof_symbols = rm_length / get_bits_per_symbol(modulation); + // Copy codeblock data, including TB and/or CB CRC if applicable, as well as filler and zero padding bits. + segment_buffer->read_codeblock(cb_data, transport_block, next_i_cb); + // Encode the segment into a codeblock. - const ldpc_encoder_buffer& rm_buffer = encoder.encode(descr_seg.get_data(), descr_seg.get_metadata().tb_common); + const ldpc_encoder_buffer& rm_buffer = encoder.encode(cb_data, cb_metadata.tb_common); // Rate match the codeblock. temp_codeblock.resize(rm_length); - rate_matcher.rate_match(temp_codeblock, rm_buffer, descr_seg.get_metadata()); + rate_matcher.rate_match(temp_codeblock, rm_buffer, cb_metadata); // Apply scrambling sequence in-place. scrambler.apply_xor(temp_codeblock, temp_codeblock); @@ -128,8 +136,8 @@ unsigned pdsch_block_processor::get_max_block_size() const return codeblock_symbols.size(); } - if (next_i_cb != d_segments.size()) { - unsigned rm_length = d_segments[next_i_cb].get_metadata().cb_specific.rm_length; + if (next_i_cb != segment_buffer->get_nof_codeblocks()) { + unsigned rm_length = segment_buffer->get_rm_length(next_i_cb); unsigned bits_per_symbol = get_bits_per_symbol(modulation); return rm_length / bits_per_symbol; } @@ -139,7 +147,7 @@ unsigned pdsch_block_processor::get_max_block_size() const bool pdsch_block_processor::empty() const { - return codeblock_symbols.empty() && (next_i_cb == d_segments.size()); + return codeblock_symbols.empty() && (next_i_cb == segment_buffer->get_nof_codeblocks()); } void pdsch_processor_lite_impl::process(resource_grid_writer& grid, diff --git a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.h b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.h index 810e8e1b6b..a5aed0b53e 100644 --- a/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.h +++ b/lib/phy/upper/channel_processors/pdsch/pdsch_processor_lite_impl.h @@ -13,6 +13,7 @@ #include "srsran/phy/support/resource_grid_mapper.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_encoder.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_rate_matcher.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_tx.h" #include "srsran/phy/upper/channel_modulation/modulation_mapper.h" #include "srsran/phy/upper/channel_processors/pdsch/pdsch_processor.h" @@ -67,8 +68,12 @@ class pdsch_block_processor : public resource_grid_mapper::symbol_buffer pseudo_random_generator& scrambler; /// Modulation mapper. modulation_mapper& modulator; - /// Buffer for storing data segments obtained after transport block segmentation. - static_vector d_segments; + /// Pointer to an LDPC segmenter output buffer interface. + const ldpc_segmenter_buffer* segment_buffer; + /// \brief Temporary codeblock message. + /// + /// It contains codeblock information bits, codeblock CRC (if applicable) and filler bits. + static_bit_buffer cb_data; /// Temporary packed bits. static_bit_buffer temp_codeblock; /// Current transmission modulation. @@ -79,6 +84,10 @@ class pdsch_block_processor : public resource_grid_mapper::symbol_buffer std::array temp_codeblock_symbols; /// Current view of the codeblock modulated symbols. span codeblock_symbols; + /// Codeblock size. It includes information, CRC, and filler bits. + units::bits cb_size; + /// Local pointer to the input data. + span transport_block; /// Processes a new codeblock and writes the new data in \ref temp_codeblock_symbols. void new_codeblock(); diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 7632fdead0..5992f0e088 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -791,7 +791,7 @@ srsran::create_downlink_processor_factory_sw(const downlink_processor_factory_sw // Create concurrent PDSCH processor factory base. pdsch_proc_factory = - create_pdsch_concurrent_processor_factory_sw(crc_calc_factory, + create_pdsch_concurrent_processor_factory_sw(ldpc_seg_tx_factory, ldpc_enc_factory, ldpc_rm_factory, prg_factory, diff --git a/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp index a7126b7760..3e34ce97aa 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pdsch_processor_benchmark.cpp @@ -576,7 +576,7 @@ static pdsch_processor_factory& get_processor_factory() std::shared_ptr ldpc_rm_factory = create_ldpc_rate_matcher_factory_sw(); TESTASSERT(ldpc_rm_factory); - // Create LDPC desegmenter factory. + // Create LDPC segmenter factory. std::shared_ptr ldpc_segm_tx_factory = create_ldpc_segmenter_tx_factory_sw(crc_calc_factory); TESTASSERT(ldpc_segm_tx_factory); @@ -646,7 +646,7 @@ static pdsch_processor_factory& get_processor_factory() "pdsch_proc", nof_pdsch_processor_concurrent_threads, 1024); executor = std::make_unique>(*worker_pool); - pdsch_proc_factory = create_pdsch_concurrent_processor_factory_sw(crc_calc_factory, + pdsch_proc_factory = create_pdsch_concurrent_processor_factory_sw(ldpc_segm_tx_factory, ldpc_enc_factory, ldpc_rm_factory, prg_factory, diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp index fbbe00bfa8..925969b5a7 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp @@ -164,7 +164,7 @@ std::shared_ptr srsran::create_sw_pdsch_processor_facto } #endif // HWACC_PDSCH_ENABLED && HWACC_PUSCH_ENABLED - return create_pdsch_concurrent_processor_factory_sw(crc_calc_factory, + return create_pdsch_concurrent_processor_factory_sw(segmenter_factory, ldpc_encoder_factory, ldpc_rate_matcher_factory, pseudo_random_gen_factory, diff --git a/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_segmenter_test.cpp b/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_segmenter_test.cpp index 05cb4791c2..68cf40629f 100644 --- a/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_segmenter_test.cpp +++ b/tests/unittests/phy/upper/channel_coding/ldpc/ldpc_segmenter_test.cpp @@ -16,6 +16,7 @@ #include "ldpc_segmenter_test_data.h" #include "srsran/phy/upper/channel_coding/channel_coding_factories.h" +#include "srsran/phy/upper/channel_coding/ldpc/ldpc_segmenter_buffer.h" #include "srsran/srsvec/bit.h" #include @@ -108,17 +109,23 @@ TEST_P(LDPCSegmenterFixture, LDPCSegmenterTest) const std::vector trans_block = test_data.trans_block.read(); const std::vector segments_check = test_data.segments.read(); - static_vector segments; - segmenter_tx->segment(segments, trans_block, seg_cfg); + // Initialize the segmenter. + const ldpc_segmenter_buffer& segment_buffer = segmenter_tx->new_transmission(trans_block, seg_cfg); + static_bit_buffer cb_data; + cb_data.resize(segment_buffer.get_segment_length().value()); - EXPECT_EQ(segments.size(), test_data.nof_segments) << "Wrong number of segments."; + EXPECT_EQ(segment_buffer.get_nof_codeblocks(), test_data.nof_segments) << "Wrong number of segments."; std::vector segment_data(test_data.segment_length); unsigned seg_offset = 0; - for (const auto& seg : segments) { - srsvec::bit_unpack(segment_data, seg.get_data()); - span filler_bits = span(segment_data).last(seg.get_metadata().cb_specific.nof_filler_bits); + for (unsigned i_cb = 0, i_cb_end = segment_buffer.get_nof_codeblocks(); i_cb != i_cb_end; ++i_cb) { + // Copy codeblock data, including TB and/or CB CRC if applicable, as well as filler and zero padding bits. + segment_buffer.read_codeblock(cb_data, trans_block, i_cb); + + srsvec::bit_unpack(segment_data, cb_data); + span filler_bits = + span(segment_data).last(segment_buffer.get_cb_metadata(i_cb).cb_specific.nof_filler_bits); std::fill(filler_bits.begin(), filler_bits.end(), FILLER_BIT); EXPECT_EQ(span(segment_data), @@ -127,7 +134,7 @@ TEST_P(LDPCSegmenterFixture, LDPCSegmenterTest) seg_offset += test_data.segment_length; } - std::vector cw_llrs(segments[0].get_metadata().tb_common.cw_length); + std::vector cw_llrs(segment_buffer.get_cb_metadata(0).tb_common.cw_length); std::generate(cw_llrs.begin(), cw_llrs.end(), [n = static_cast(-127)]() mutable { int8_t r = std::clamp(n, LLR_MIN.to_value_type(), LLR_MAX.to_value_type()); ++n; diff --git a/tests/unittests/phy/upper/channel_processors/pdsch/pdsch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pdsch/pdsch_processor_vectortest.cpp index 75b77fd3e6..232415c3a2 100644 --- a/tests/unittests/phy/upper/channel_processors/pdsch/pdsch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pdsch/pdsch_processor_vectortest.cpp @@ -283,7 +283,7 @@ class PdschProcessorFixture : public ::testing::TestWithParam>(*worker_pool); - return create_pdsch_concurrent_processor_factory_sw(crc_calc_factory, + return create_pdsch_concurrent_processor_factory_sw(ldpc_segmenter_tx_factory, ldpc_encoder_factory, ldpc_rate_matcher_factory, prg_factory, From 2bb5bf51b424a49a6ac49c936c9a31cc33b3ead9 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 6 Nov 2024 15:53:59 +0100 Subject: [PATCH 43/72] [Support] Fix users of sdu_window relying on the implementation in lib While there, devirtualize it as it does not provide any advantage --- include/srsran/pdcp/pdcp_sn_size.h | 2 + include/srsran/support/sdu_window.h | 62 +++++++++++++++++++---- lib/gtpu/gtpu_tunnel_ngu_rx_impl.h | 22 ++++----- lib/pdcp/pdcp_entity_rx.cpp | 62 ++++++++--------------- lib/pdcp/pdcp_entity_rx.h | 11 ++--- lib/pdcp/pdcp_entity_tx.cpp | 1 - lib/pdcp/pdcp_tx_window.cpp | 44 ++++++----------- lib/pdcp/pdcp_tx_window.h | 13 ++--- lib/rlc/rlc_rx_am_entity.cpp | 68 +++++++++---------------- lib/rlc/rlc_rx_am_entity.h | 9 +--- lib/rlc/rlc_rx_um_entity.cpp | 63 ++++++++--------------- lib/rlc/rlc_rx_um_entity.h | 9 +--- lib/rlc/rlc_tx_am_entity.cpp | 77 +++++++++++------------------ lib/rlc/rlc_tx_am_entity.h | 9 +--- lib/support/sdu_window_impl.h | 65 ------------------------ 15 files changed, 187 insertions(+), 330 deletions(-) delete mode 100644 lib/support/sdu_window_impl.h diff --git a/include/srsran/pdcp/pdcp_sn_size.h b/include/srsran/pdcp/pdcp_sn_size.h index 32f834cd8a..a7d94db3e8 100644 --- a/include/srsran/pdcp/pdcp_sn_size.h +++ b/include/srsran/pdcp/pdcp_sn_size.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/support/srsran_assert.h" #include "fmt/format.h" #include @@ -33,6 +34,7 @@ inline bool pdcp_sn_size_from_uint(pdcp_sn_size& sn_size, uint16_t num) /// \brief Convert PDCP SN size from enum to unsigned integer. constexpr uint8_t pdcp_sn_size_to_uint(pdcp_sn_size sn_size) { + srsran_assert(sn_size != pdcp_sn_size::invalid, "Invalid PDCP SN size"); return static_cast(sn_size); } diff --git a/include/srsran/support/sdu_window.h b/include/srsran/support/sdu_window.h index 3333039d15..8b359dd536 100644 --- a/include/srsran/support/sdu_window.h +++ b/include/srsran/support/sdu_window.h @@ -10,24 +10,66 @@ #pragma once +#include "srsran/adt/circular_map.h" +#include "srsran/support/srsran_assert.h" #include #include namespace srsran { -template +/// \brief This class provides a container for the Tx/Rx windows holding SDU info objects that are indexed by Sequence +/// Numbers (SN). +/// +/// \tparam T Storage Type. +/// \tparam PREFIXED_LOGGER An implementation of a prefixed_logger for logging. +template class sdu_window { public: - virtual ~sdu_window() = default; - virtual T& add_sn(size_t sn) = 0; - virtual void remove_sn(size_t sn) = 0; - virtual T& operator[](size_t sn) = 0; - virtual size_t size() const = 0; - virtual bool empty() const = 0; - virtual bool full() const = 0; - virtual void clear() = 0; - virtual bool has_sn(uint32_t sn) const = 0; + sdu_window(PREFIXED_LOGGER& logger_, size_t size) : logger(logger_), window(size) {} + + T& add_sn(size_t sn) + { + if (has_sn(sn)) { + logger.log_error("sn={} already present in window, overwriting.", sn); + srsran_assertion_failure("sn={} already present in window.", sn); + } else { + logger.log_debug("Adding sn={} to window.", sn); + } + + window.overwrite(sn, T()); + + return window[sn]; + } + + void remove_sn(size_t sn) + { + if (not has_sn(sn)) { + logger.log_error("Cannot remove sn={} because not contained in the window.", sn); + srsran_assertion_failure("Cannot remove sn={} because not contained in the window.", sn); + return; + } + + logger.log_debug("Removing sn={} from window", sn); + window.erase(sn); + } + + T& operator[](size_t sn) { return window[sn]; } + const T& operator[](size_t sn) const { return window[sn]; } + + size_t size() const { return window.size(); } + + bool full() const { return window.full(); } + + bool empty() const { return window.empty(); } + + void clear() { window.clear(); } + + bool has_sn(uint32_t sn) const { return window.contains(sn); } + +private: + PREFIXED_LOGGER& logger; + circular_map window; }; } // namespace srsran diff --git a/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h b/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h index d3dcc103eb..d93e2071d0 100644 --- a/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h +++ b/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h @@ -10,12 +10,12 @@ #pragma once -#include "../support/sdu_window_impl.h" #include "gtpu_tunnel_base_rx.h" #include "srsran/gtpu/gtpu_config.h" #include "srsran/gtpu/gtpu_tunnel_ngu_rx.h" #include "srsran/psup/psup_packing.h" #include "srsran/ran/cu_types.h" +#include "srsran/support/sdu_window.h" #include "srsran/support/timers.h" namespace srsran { @@ -53,7 +53,7 @@ class gtpu_tunnel_ngu_rx_impl : public gtpu_tunnel_base_rx psup_packer(logger.get_basic_logger()), lower_dn(rx_lower_), config(cfg), - rx_window(std::make_unique>(logger)), + rx_window(logger, gtpu_rx_window_size), ue_dl_timer_factory(ue_dl_timer_factory_) { if (config.t_reordering.count() != 0) { @@ -160,12 +160,12 @@ class gtpu_tunnel_ngu_rx_impl : public gtpu_tunnel_base_rx } // Check if PDU has been received - if (rx_window->has_sn(sn)) { + if (rx_window.has_sn(sn)) { logger.log_warning("Duplicate PDU dropped. sn={} pdu_len={}", sn, pdu_len); return; } - gtpu_rx_sdu_info& rx_sdu_info = rx_window->add_sn(sn); + gtpu_rx_sdu_info& rx_sdu_info = rx_window.add_sn(sn); rx_sdu_info.sdu = std::move(rx_sdu); rx_sdu_info.qos_flow_id = pdu_session_info.qos_flow_id; rx_sdu_info.sn = sn; @@ -209,10 +209,10 @@ class gtpu_tunnel_ngu_rx_impl : public gtpu_tunnel_base_rx void deliver_all_consecutive_sdus() { - while (st.rx_deliv != st.rx_next && rx_window->has_sn(st.rx_deliv)) { - gtpu_rx_sdu_info& sdu_info = (*rx_window)[st.rx_deliv]; + while (st.rx_deliv != st.rx_next && rx_window.has_sn(st.rx_deliv)) { + gtpu_rx_sdu_info& sdu_info = rx_window[st.rx_deliv]; deliver_sdu(sdu_info); - rx_window->remove_sn(st.rx_deliv); + rx_window.remove_sn(st.rx_deliv); // Update RX_DELIV st.rx_deliv = st.rx_deliv + 1; @@ -232,10 +232,10 @@ class gtpu_tunnel_ngu_rx_impl : public gtpu_tunnel_base_rx } while (st.rx_deliv != st.rx_reord) { - if (rx_window->has_sn(st.rx_deliv)) { - gtpu_rx_sdu_info& sdu_info = (*rx_window)[st.rx_deliv]; + if (rx_window.has_sn(st.rx_deliv)) { + gtpu_rx_sdu_info& sdu_info = rx_window[st.rx_deliv]; deliver_sdu(sdu_info); - rx_window->remove_sn(st.rx_deliv); + rx_window.remove_sn(st.rx_deliv); } // Update RX_DELIV @@ -267,7 +267,7 @@ class gtpu_tunnel_ngu_rx_impl : public gtpu_tunnel_base_rx gtpu_rx_state st = {}; /// Rx window - std::unique_ptr> rx_window; + sdu_window rx_window; /// Rx reordering timer unique_timer reordering_timer; diff --git a/lib/pdcp/pdcp_entity_rx.cpp b/lib/pdcp/pdcp_entity_rx.cpp index cfa77e8fb4..dbd751761f 100644 --- a/lib/pdcp/pdcp_entity_rx.cpp +++ b/lib/pdcp/pdcp_entity_rx.cpp @@ -10,7 +10,6 @@ #include "pdcp_entity_rx.h" #include "../security/security_engine_impl.h" -#include "../support/sdu_window_impl.h" #include "srsran/instrumentation/traces/up_traces.h" #include "srsran/support/bit_encoding.h" #include "srsran/support/format/fmt_optional.h" @@ -29,7 +28,7 @@ pdcp_entity_rx::pdcp_entity_rx(uint32_t ue_index, pdcp_entity_tx_rx_base(rb_id_, cfg_.rb_type, cfg_.rlc_mode, cfg_.sn_size), logger("PDCP", {ue_index, rb_id_, "UL"}), cfg(cfg_), - rx_window(create_rx_window(cfg.sn_size)), + rx_window(logger, pdcp_window_size(pdcp_sn_size_to_uint(cfg.sn_size))), upper_dn(upper_dn_), upper_cn(upper_cn_), ue_ul_timer_factory(ue_ul_timer_factory_), @@ -90,7 +89,7 @@ void pdcp_entity_rx::handle_pdu(byte_buffer_chain buf) // Log PDU logger.log_debug(buf.begin(), buf.end(), "RX PDU. pdu_len={}", buf.length()); // Sanity check - if (buf.length() == 0) { + if (buf.empty()) { metrics.add_dropped_pdus(1); logger.log_error("Dropping empty PDU."); return; @@ -251,19 +250,18 @@ void pdcp_entity_rx::handle_data_pdu(byte_buffer pdu) } // Check if PDU has been received - if (rx_window->has_sn(rcvd_count)) { - const pdcp_rx_sdu_info& sdu_info = (*rx_window)[rcvd_count]; + if (rx_window.has_sn(rcvd_count)) { + const pdcp_rx_sdu_info& sdu_info = rx_window[rcvd_count]; if (sdu_info.count == rcvd_count) { logger.log_debug("Duplicate PDU dropped. count={}", rcvd_count); return; // PDU already present, drop. - } else { - logger.log_error("Removing old PDU with count={} for new PDU with count={}", sdu_info.count, rcvd_count); - rx_window->remove_sn(rcvd_count); } + logger.log_error("Removing old PDU with count={} for new PDU with count={}", sdu_info.count, rcvd_count); + rx_window.remove_sn(rcvd_count); } // Store PDU in Rx window - pdcp_rx_sdu_info& sdu_info = rx_window->add_sn(rcvd_count); + pdcp_rx_sdu_info& sdu_info = rx_window.add_sn(rcvd_count); sdu_info.sdu = std::move(pdu); sdu_info.count = rcvd_count; sdu_info.time_of_arrival = time_start; @@ -331,15 +329,15 @@ void pdcp_entity_rx::handle_control_pdu(byte_buffer_chain pdu) // Update RX_DELIV after submitting to higher layers void pdcp_entity_rx::deliver_all_consecutive_counts() { - while (st.rx_deliv != st.rx_next && rx_window->has_sn(st.rx_deliv)) { - pdcp_rx_sdu_info& sdu_info = (*rx_window)[st.rx_deliv]; + while (st.rx_deliv != st.rx_next && rx_window.has_sn(st.rx_deliv)) { + pdcp_rx_sdu_info& sdu_info = rx_window[st.rx_deliv]; logger.log_info("RX SDU. count={}", st.rx_deliv); // Pass PDCP SDU to the upper layers metrics.add_sdus(1, sdu_info.sdu.length()); record_reordering_dealy(sdu_info.time_of_arrival); upper_dn.on_new_sdu(std::move(sdu_info.sdu)); - rx_window->remove_sn(st.rx_deliv); + rx_window.remove_sn(st.rx_deliv); // Update RX_DELIV st.rx_deliv = st.rx_deliv + 1; @@ -352,15 +350,15 @@ void pdcp_entity_rx::deliver_all_consecutive_counts() void pdcp_entity_rx::deliver_all_sdus() { for (uint32_t count = st.rx_deliv; count < st.rx_next; count++) { - if (rx_window->has_sn(count)) { - pdcp_rx_sdu_info& sdu_info = (*rx_window)[count]; + if (rx_window.has_sn(count)) { + pdcp_rx_sdu_info& sdu_info = rx_window[count]; logger.log_info("RX SDU. count={}", count); // Pass PDCP SDU to the upper layers metrics.add_sdus(1, sdu_info.sdu.length()); record_reordering_dealy(sdu_info.time_of_arrival); upper_dn.on_new_sdu(std::move(sdu_info.sdu)); - rx_window->remove_sn(count); + rx_window.remove_sn(count); } } } @@ -369,8 +367,8 @@ void pdcp_entity_rx::deliver_all_sdus() void pdcp_entity_rx::discard_all_sdus() { while (st.rx_deliv != st.rx_next) { - if (rx_window->has_sn(st.rx_deliv)) { - rx_window->remove_sn(st.rx_deliv); + if (rx_window.has_sn(st.rx_deliv)) { + rx_window.remove_sn(st.rx_deliv); logger.log_debug("Discarded RX SDU. count={}", st.rx_next); } @@ -404,33 +402,13 @@ byte_buffer pdcp_entity_rx::compile_status_report() for (uint32_t i = bitmap_begin; i < bitmap_end; i++) { // Bit == 0: PDCP SDU with COUNT = (FMC + bit position) modulo 2^32 is missing. // Bit == 1: PDCP SDU with COUNT = (FMC + bit position) modulo 2^32 is correctly received. - unsigned bit = rx_window->has_sn(i) ? 1 : 0; + unsigned bit = rx_window.has_sn(i) ? 1 : 0; enc.pack(bit, 1); } return buf; } -std::unique_ptr> pdcp_entity_rx::create_rx_window(pdcp_sn_size sn_size_) -{ - std::unique_ptr> rx_window_; - switch (sn_size_) { - case pdcp_sn_size::size12bits: - rx_window_ = std::make_unique>(logger); - break; - case pdcp_sn_size::size18bits: - rx_window_ = std::make_unique>(logger); - break; - default: - srsran_assertion_failure("Cannot create rx_window for unsupported sn_size={}.", pdcp_sn_size_to_uint(sn_size_)); - } - return rx_window_; -} - /* * Deciphering and Integrity Protection Helpers */ @@ -554,15 +532,15 @@ void pdcp_entity_rx::handle_t_reordering_expire() metrics.add_t_reordering_timeouts(1); // Deliver all PDCP SDU(s) with associated COUNT value(s) < RX_REORD while (st.rx_deliv != st.rx_reord) { - if (rx_window->has_sn(st.rx_deliv)) { - pdcp_rx_sdu_info& sdu_info = (*rx_window)[st.rx_deliv]; + if (rx_window.has_sn(st.rx_deliv)) { + pdcp_rx_sdu_info& sdu_info = rx_window[st.rx_deliv]; logger.log_info("RX SDU. count={}", st.rx_deliv); // Pass PDCP SDU to the upper layers metrics.add_sdus(1, sdu_info.sdu.length()); record_reordering_dealy(sdu_info.time_of_arrival); upper_dn.on_new_sdu(std::move(sdu_info.sdu)); - rx_window->remove_sn(st.rx_deliv); + rx_window.remove_sn(st.rx_deliv); } // Update RX_DELIV @@ -634,4 +612,4 @@ void pdcp_entity_rx::record_reordering_dealy(std::chrono::system_clock::time_poi std::chrono::microseconds time_taken = std::chrono::duration_cast(std::chrono::system_clock::now() - time_of_arrival); metrics.add_reordering_delay_us((uint32_t)time_taken.count()); -} \ No newline at end of file +} diff --git a/lib/pdcp/pdcp_entity_rx.h b/lib/pdcp/pdcp_entity_rx.h index 4d1c53baaa..986e8de697 100644 --- a/lib/pdcp/pdcp_entity_rx.h +++ b/lib/pdcp/pdcp_entity_rx.h @@ -41,8 +41,8 @@ struct pdcp_rx_state { }; struct pdcp_rx_sdu_info { - byte_buffer sdu = {}; - uint32_t count = {}; + byte_buffer sdu; + uint32_t count = 0; std::chrono::system_clock::time_point time_of_arrival; }; @@ -121,7 +121,7 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, pdcp_rx_state st = {}; /// Rx window - std::unique_ptr> rx_window; + sdu_window rx_window; /// Rx reordering timer unique_timer reordering_timer; @@ -163,11 +163,6 @@ class pdcp_entity_rx final : public pdcp_entity_tx_rx_base, pdcp_metrics_aggregator& metrics_agg; unique_timer metrics_timer; - /// Creates the rx_window according to sn_size - /// \param sn_size Size of the sequence number (SN) - /// \return unique pointer to rx_window instance - std::unique_ptr> create_rx_window(pdcp_sn_size sn_size_); - void log_state(srslog::basic_levels level) { logger.log(level, "RX entity state. {}", st); } }; diff --git a/lib/pdcp/pdcp_entity_tx.cpp b/lib/pdcp/pdcp_entity_tx.cpp index 8221b0f240..eefa48077f 100644 --- a/lib/pdcp/pdcp_entity_tx.cpp +++ b/lib/pdcp/pdcp_entity_tx.cpp @@ -10,7 +10,6 @@ #include "pdcp_entity_tx.h" #include "../security/security_engine_impl.h" -#include "../support/sdu_window_impl.h" #include "srsran/instrumentation/traces/up_traces.h" #include "srsran/support/bit_encoding.h" #include "srsran/support/srsran_assert.h" diff --git a/lib/pdcp/pdcp_tx_window.cpp b/lib/pdcp/pdcp_tx_window.cpp index 7311816199..1f942bb2bb 100644 --- a/lib/pdcp/pdcp_tx_window.cpp +++ b/lib/pdcp/pdcp_tx_window.cpp @@ -8,12 +8,10 @@ * */ -#include - -#include "../support/sdu_window_impl.h" #include "pdcp_tx_window.h" #include "srsran/pdcp/pdcp_config.h" #include "srsran/support/srsran_assert.h" +#include using namespace srsran; @@ -21,41 +19,27 @@ pdcp_tx_window::pdcp_tx_window(pdcp_rb_type rb_type_, pdcp_rlc_mode rlc_mode_, pdcp_sn_size sn_size_, pdcp_bearer_logger logger_) : - rb_type(rb_type_), rlc_mode(rlc_mode_), sn_size(sn_size_), logger(std::move(logger_)) + logger(std::move(logger_)), + tx_window(logger, pdcp_window_size(pdcp_sn_size_to_uint(sn_size_))), + rb_type(rb_type_), + rlc_mode(rlc_mode_), + sn_size(sn_size_) { - create_tx_window(); -} -void pdcp_tx_window::create_tx_window() -{ - switch (sn_size) { - case pdcp_sn_size::size12bits: - tx_window = std::make_unique>(logger); - break; - case pdcp_sn_size::size18bits: - tx_window = std::make_unique>(logger); - break; - default: - srsran_assertion_failure("Cannot create tx_window for unsupported sn_size={}.", pdcp_sn_size_to_uint(sn_size)); - } } -bool pdcp_tx_window::has_sn(uint32_t count) +bool pdcp_tx_window::has_sn(uint32_t count) const { - return tx_window->has_sn(count); + return tx_window.has_sn(count); } pdcp_tx_sdu_info& pdcp_tx_window::operator[](uint32_t count) { - return (*tx_window)[count]; + return tx_window[count]; } void pdcp_tx_window::add_sdu(uint32_t count, byte_buffer sdu, unique_timer discard_timer) { - pdcp_tx_sdu_info& sdu_info = tx_window->add_sn(count); + pdcp_tx_sdu_info& sdu_info = tx_window.add_sn(count); sdu_info.count = count; sdu_info.discard_timer = std::move(discard_timer); sdu_info.sdu_length = sdu.length(); @@ -69,10 +53,10 @@ void pdcp_tx_window::add_sdu(uint32_t count, byte_buffer sdu, unique_timer disca void pdcp_tx_window::remove_sdu(uint32_t count) { - if (tx_window->has_sn(count)) { - sdu_bytes -= (*tx_window)[count].sdu_length; + if (tx_window.has_sn(count)) { + sdu_bytes -= tx_window[count].sdu_length; nof_sdus--; - tx_window->remove_sn(count); + tx_window.remove_sn(count); } } @@ -80,7 +64,7 @@ void pdcp_tx_window::clear() { sdu_bytes = 0; nof_sdus = 0; - tx_window->clear(); + tx_window.clear(); } uint32_t pdcp_tx_window::get_sdu_bytes() const diff --git a/lib/pdcp/pdcp_tx_window.h b/lib/pdcp/pdcp_tx_window.h index 2d4c0643a2..86129e7ca4 100644 --- a/lib/pdcp/pdcp_tx_window.h +++ b/lib/pdcp/pdcp_tx_window.h @@ -34,7 +34,7 @@ class pdcp_tx_window public: pdcp_tx_window(pdcp_rb_type rb_type_, pdcp_rlc_mode rlc_mode_, pdcp_sn_size sn_size_, pdcp_bearer_logger logger_); - bool has_sn(uint32_t count); + bool has_sn(uint32_t count) const; /// \brief Remove SDU from TX window /// This method removes an SDU from the TX window. It will keep track of the PDU bytes in the window @@ -57,21 +57,22 @@ class pdcp_tx_window uint32_t get_pdu_bytes(security::integrity_enabled integrity) const; private: + pdcp_bearer_logger logger; + /// \brief Tx window. /// This container is used to store discard timers of transmitted SDUs and, only for AM, a copy of the SDU for data /// recovery procedure. Upon expiry of a discard timer, the PDCP Tx entity instructs the lower layers to discard the /// associated PDCP PDU. See section 5.2.1 and 7.3 of TS 38.323. - std::unique_ptr> tx_window; + sdu_window tx_window; /// Creates the tx_window according to sn_size /// \param sn_size Size of the sequence number (SN) /// \return unique pointer to tx_window instance void create_tx_window(); - pdcp_rb_type rb_type; - pdcp_rlc_mode rlc_mode; - pdcp_sn_size sn_size; - pdcp_bearer_logger logger; + pdcp_rb_type rb_type; + pdcp_rlc_mode rlc_mode; + pdcp_sn_size sn_size; uint32_t sdu_bytes = 0; uint32_t nof_sdus = 0; diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index ca72239859..d28ed51b47 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -9,7 +9,6 @@ */ #include "rlc_rx_am_entity.h" -#include "../support/sdu_window_impl.h" #include "srsran/adt/scope_exit.h" #include "srsran/instrumentation/traces/up_traces.h" #include "srsran/support/format/fmt_optional.h" @@ -29,7 +28,7 @@ rlc_rx_am_entity::rlc_rx_am_entity(gnb_du_id_t gnb_du_id, cfg(config), mod(cardinality(to_number(cfg.sn_field_length))), am_window_size(window_size(to_number(cfg.sn_field_length))), - rx_window(create_rx_window(cfg.sn_field_length)), + rx_window(logger, window_size(to_number(cfg.sn_field_length))), status_buf({rlc_am_status_pdu(cfg.sn_field_length), rlc_am_status_pdu(cfg.sn_field_length), rlc_am_status_pdu(cfg.sn_field_length)}), @@ -167,7 +166,7 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) } // Section 5.2.3.2.2, discard duplicate PDUs - if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) { + if (rx_window.has_sn(header.sn) && rx_window[header.sn].fully_received) { logger.log_debug("Discarded PDU duplicate. sn={}", header.sn); return; } @@ -195,12 +194,12 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) /* * - if all bytes of the RLC SDU with SN = x are received: */ - if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) { + if (rx_window.has_sn(header.sn) && rx_window[header.sn].fully_received) { /* * - reassemble the RLC SDU from AMD PDU(s) with SN = x, remove RLC headers when doing so and deliver * the reassembled RLC SDU to upper layer; */ - rlc_rx_am_sdu_info& sdu_info = (*rx_window)[header.sn]; + rlc_rx_am_sdu_info& sdu_info = rx_window[header.sn]; expected sdu = reassemble_sdu(sdu_info, header.sn); if (!sdu) { logger.log_error("Dropped SDU, failed to reassemble. sn={}", header.sn); @@ -226,8 +225,8 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) uint32_t sn_upd = 0; for (sn_upd = (st.rx_highest_status + 1) % mod; rx_mod_base(sn_upd) < rx_mod_base(st.rx_next_highest); sn_upd = (sn_upd + 1) % mod) { - if (rx_window->has_sn(sn_upd)) { - if (not(*rx_window)[sn_upd].fully_received) { + if (rx_window.has_sn(sn_upd)) { + if (not rx_window[sn_upd].fully_received) { break; // first SDU not fully received } } else { @@ -249,13 +248,13 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) // move rx_next forward and remove all fully received SDUs from rx_window for (sn_upd = (st.rx_next) % mod; rx_mod_base(sn_upd) < rx_mod_base(st.rx_next_highest); sn_upd = (sn_upd + 1) % mod) { - if (rx_window->has_sn(sn_upd)) { - if (not(*rx_window)[sn_upd].fully_received) { + if (rx_window.has_sn(sn_upd)) { + if (not rx_window[sn_upd].fully_received) { break; // first SDU not fully received } // RX_Next serves as the lower edge of the receiving window // As such, we remove any SDU from the window if we update this value - rx_window->remove_sn(sn_upd); + rx_window.remove_sn(sn_upd); } else { break; // first SDU not fully received } @@ -282,7 +281,7 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) stop_reassembly_timer = true; } if (rx_mod_base(st.rx_next_status_trigger) == rx_mod_base(st.rx_next + 1)) { - if (not(*rx_window)[st.rx_next].has_gap) { + if (not rx_window[st.rx_next].has_gap) { stop_reassembly_timer = true; } } @@ -309,7 +308,7 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) restart_reassembly_timer = true; } if (rx_mod_base(st.rx_next_highest) == rx_mod_base(st.rx_next + 1)) { - if (rx_window->has_sn(st.rx_next) && (*rx_window)[st.rx_next].has_gap) { + if (rx_window.has_sn(st.rx_next) && rx_window[st.rx_next].has_gap) { restart_reassembly_timer = true; } } @@ -332,8 +331,8 @@ bool rlc_rx_am_entity::handle_full_data_sdu(const rlc_am_pdu_header& header, byt logger.log_debug("RX SDU. payload_len={} {}", payload.length(), header); // Add new SN to RX window if no segments have been received yet - rlc_rx_am_sdu_info& rx_sdu = rx_window->has_sn(header.sn) ? (*rx_window)[header.sn] : ([&]() -> rlc_rx_am_sdu_info& { - rlc_rx_am_sdu_info& sdu = rx_window->add_sn(header.sn); + rlc_rx_am_sdu_info& rx_sdu = rx_window.has_sn(header.sn) ? rx_window[header.sn] : ([&]() -> rlc_rx_am_sdu_info& { + rlc_rx_am_sdu_info& sdu = rx_window.add_sn(header.sn); sdu.time_of_arrival = std::chrono::steady_clock::now(); return sdu; })(); @@ -356,8 +355,8 @@ bool rlc_rx_am_entity::handle_segment_data_sdu(const rlc_am_pdu_header& header, logger.log_debug("RX SDU segment. payload_len={} {}", payload.length(), header); // Add new SN to RX window if no segments have been received yet - rlc_rx_am_sdu_info& rx_sdu = rx_window->has_sn(header.sn) ? (*rx_window)[header.sn] : ([&]() -> rlc_rx_am_sdu_info& { - rlc_rx_am_sdu_info& sdu = rx_window->add_sn(header.sn); + rlc_rx_am_sdu_info& rx_sdu = rx_window.has_sn(header.sn) ? rx_window[header.sn] : ([&]() -> rlc_rx_am_sdu_info& { + rlc_rx_am_sdu_info& sdu = rx_window.add_sn(header.sn); sdu.time_of_arrival = std::chrono::steady_clock::now(); return sdu; })(); @@ -550,22 +549,22 @@ void rlc_rx_am_entity::refresh_status_report() logger.log_debug( "Generating status PDU. rx_next={} rx_highest_status={} stop_sn={}", st.rx_next, st.rx_highest_status, stop_sn); for (uint32_t i = st.rx_next; rx_mod_base(i) < rx_mod_base(stop_sn); i = (i + 1) % mod) { - if ((rx_window->has_sn(i) && (*rx_window)[i].fully_received)) { + if ((rx_window.has_sn(i) && rx_window[i].fully_received)) { logger.log_debug("SDU complete. sn={}", i); } else { - if (not rx_window->has_sn(i)) { + if (not rx_window.has_sn(i)) { // No segment received, NACK the whole SDU rlc_am_status_nack nack; nack.nack_sn = i; nack.has_so = false; logger.log_debug("Adding nack={}.", nack); status_builder->push_nack(nack); - } else if (not(*rx_window)[i].fully_received) { - srsran_assert(std::holds_alternative((*rx_window)[i].sdu_data), + } else if (not rx_window[i].fully_received) { + srsran_assert(std::holds_alternative(rx_window[i].sdu_data), "Invalid sdu_data variant of incomplete SDU in rx_window. sn={}", i); rlc_rx_am_sdu_info::segment_set_t& segments = - std::get((*rx_window)[i].sdu_data); + std::get(rx_window[i].sdu_data); // Some segments were received, but not all. // NACK non consecutive missing bytes uint32_t last_so = 0; @@ -665,26 +664,6 @@ void rlc_rx_am_entity::notify_status_report_changed() } } -std::unique_ptr> rlc_rx_am_entity::create_rx_window(rlc_am_sn_size sn_size) -{ - std::unique_ptr> rx_window_; - switch (sn_size) { - case rlc_am_sn_size::size12bits: - rx_window_ = std::make_unique< - sdu_window_impl>( - logger); - break; - case rlc_am_sn_size::size18bits: - rx_window_ = std::make_unique< - sdu_window_impl>( - logger); - break; - default: - srsran_assertion_failure("Cannot create rx_window for unsupported sn_size={}.", to_number(sn_size)); - } - return rx_window_; -} - /* * Timer handling functions */ @@ -722,7 +701,7 @@ void rlc_rx_am_entity::on_expired_reassembly_timer() */ uint32_t sn_upd = st.rx_next_status_trigger; for (; rx_mod_base(sn_upd) < rx_mod_base(st.rx_next_highest); sn_upd = (sn_upd + 1) % mod) { - if (not rx_window->has_sn(sn_upd) || (rx_window->has_sn(sn_upd) && not(*rx_window)[sn_upd].fully_received)) { + if (not rx_window.has_sn(sn_upd) || (rx_window.has_sn(sn_upd) && not rx_window[sn_upd].fully_received)) { break; } } @@ -737,7 +716,7 @@ void rlc_rx_am_entity::on_expired_reassembly_timer() restart_reassembly_timer = true; } if (rx_mod_base(st.rx_next_highest) == rx_mod_base(st.rx_highest_status + 1)) { - if (rx_window->has_sn(st.rx_highest_status) && (*rx_window)[st.rx_highest_status].has_gap) { + if (rx_window.has_sn(st.rx_highest_status) && rx_window[st.rx_highest_status].has_gap) { restart_reassembly_timer = true; } } @@ -757,6 +736,5 @@ void rlc_rx_am_entity::on_expired_reassembly_timer() notify_status_report_changed(); log_state(srslog::basic_levels::debug); - logger.log_debug("RX window state: nof_sdus={}", rx_window->size()); - return; + logger.log_debug("RX window state: nof_sdus={}", rx_window.size()); } diff --git a/lib/rlc/rlc_rx_am_entity.h b/lib/rlc/rlc_rx_am_entity.h index f9660d55e5..f9a997ec74 100644 --- a/lib/rlc/rlc_rx_am_entity.h +++ b/lib/rlc/rlc_rx_am_entity.h @@ -98,7 +98,7 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider const uint32_t am_window_size; /// Rx window - std::unique_ptr> rx_window; + sdu_window rx_window; /// Indicates the rx_window has not been changed, i.e. no need to rebuild status report. static const bool rx_window_not_changed = false; /// Indicates the rx_window has been changed, i.e. need to rebuild status report. @@ -159,7 +159,7 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider reassembly_timer.stop(); stopped = true; } - }; + } // Rx/Tx interconnect void set_status_handler(rlc_tx_am_status_handler* status_handler_) { status_handler = status_handler_; } @@ -304,11 +304,6 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider /// \param timeout_id The timer ID void on_expired_reassembly_timer(); - /// Creates the rx_window according to sn_size - /// \param sn_size Size of the sequence number (SN) - /// \return unique pointer to rx_window instance - std::unique_ptr> create_rx_window(rlc_am_sn_size sn_size); - void log_state(srslog::basic_levels level) { logger.log(level, "RX entity state. {}", st); } }; diff --git a/lib/rlc/rlc_rx_um_entity.cpp b/lib/rlc/rlc_rx_um_entity.cpp index 2205aafa95..bdabcd855c 100644 --- a/lib/rlc/rlc_rx_um_entity.cpp +++ b/lib/rlc/rlc_rx_um_entity.cpp @@ -9,7 +9,6 @@ */ #include "rlc_rx_um_entity.h" -#include "../support/sdu_window_impl.h" using namespace srsran; @@ -26,7 +25,7 @@ rlc_rx_um_entity::rlc_rx_um_entity(gnb_du_id_t gnb_du_id, cfg(config), mod(cardinality(to_number(cfg.sn_field_length))), um_window_size(window_size(to_number(cfg.sn_field_length))), - rx_window(create_rx_window(cfg.sn_field_length)), + rx_window(logger, window_size(to_number(cfg.sn_field_length))), reassembly_timer(ue_timer_factory.create_timer()), pcap_context(ue_index, rb_id, config) { @@ -104,12 +103,12 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) /* * - if all byte segments with SN = x are received: */ - if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) { + if (rx_window.has_sn(header.sn) && rx_window[header.sn].fully_received) { /* * - reassemble the RLC SDU from all byte segments with SN = x, remove RLC headers and deliver the reassembled * RLC SDU to upper layer; */ - rlc_rx_um_sdu_info& sdu_info = (*rx_window)[header.sn]; + rlc_rx_um_sdu_info& sdu_info = rx_window[header.sn]; expected sdu = reassemble_sdu(sdu_info, header.sn); if (!sdu) { logger.log_error("Dropped SDU, failed to reassemble. sn={}", header.sn); @@ -138,13 +137,13 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) // move rx_next_reassembly forward and remove all fully received SDUs from rx_window for (sn_upd = (st.rx_next_reassembly) % mod; rx_mod_base(sn_upd) < rx_mod_base(st.rx_next_highest); sn_upd = (sn_upd + 1) % mod) { - if (rx_window->has_sn(sn_upd)) { - if (not(*rx_window)[sn_upd].fully_received) { + if (rx_window.has_sn(sn_upd)) { + if (not rx_window[sn_upd].fully_received) { break; // first SDU not fully received } // rx_next_reassembly serves as the lower edge of the receiving window // As such, we remove any SDU from the window if we update this value - rx_window->remove_sn(sn_upd); + rx_window.remove_sn(sn_upd); } else { break; // first SDU not fully received } @@ -173,13 +172,13 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) (st.rx_next_highest - um_window_size) % mod, st.rx_next_highest, sn_upd); - if (rx_window->has_sn(sn_upd)) { - if (not(*rx_window)[sn_upd].fully_received) { + if (rx_window.has_sn(sn_upd)) { + if (not rx_window[sn_upd].fully_received) { // count incomplete SDUs as lost logger.log_info("Discarding incomplete SDU. sn={}", sn_upd); metrics.metrics_add_lost_pdus(1); } - rx_window->remove_sn(sn_upd); + rx_window.remove_sn(sn_upd); } else { // count non-existing SDUs as lost logger.log_info("Discarding SDU. sn={}", sn_upd); @@ -194,10 +193,10 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) // Since sn_upd just entered the reassembly window in the previous loop (and everything below was cleaned), // we continue (and clean) until we face any SN that is not fully received for (; rx_mod_base(sn_upd) < rx_mod_base(st.rx_next_highest); sn_upd = (sn_upd + 1) % mod) { - if (rx_window->has_sn(sn_upd) && (*rx_window)[sn_upd].fully_received) { + if (rx_window.has_sn(sn_upd) && rx_window[sn_upd].fully_received) { // rx_next_reassembly serves as the lower edge of the receiving window // As such, we remove any SDU from the window if we update this value - rx_window->remove_sn(sn_upd); + rx_window.remove_sn(sn_upd); } else { break; // first SDU not fully received } @@ -229,7 +228,7 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) stop_reassembly_timer = true; } if (st.rx_next_highest == st.rx_next_reassembly + 1) { - if (rx_window->has_sn(st.rx_next_highest) && not(*rx_window)[st.rx_next_highest].has_gap) { + if (rx_window.has_sn(st.rx_next_highest) && not rx_window[st.rx_next_highest].has_gap) { stop_reassembly_timer = true; } } @@ -255,7 +254,7 @@ void rlc_rx_um_entity::handle_pdu(byte_buffer_slice buf) restart_reassembly_timer = true; } if (rx_mod_base(st.rx_next_highest) == rx_mod_base(st.rx_next_reassembly + 1)) { - if (rx_window->has_sn(st.rx_next_highest) && (*rx_window)[st.rx_next_highest].has_gap) { + if (rx_window.has_sn(st.rx_next_highest) && rx_window[st.rx_next_highest].has_gap) { restart_reassembly_timer = true; } } @@ -279,8 +278,8 @@ bool rlc_rx_um_entity::handle_segment_data_sdu(const rlc_um_pdu_header& header, logger.log_debug("RX SDU segment. payload_len={} {}", payload.length(), header); // Add new SN to RX window if no segments have been received yet - rlc_rx_um_sdu_info& rx_sdu = rx_window->has_sn(header.sn) ? (*rx_window)[header.sn] : ([&]() -> rlc_rx_um_sdu_info& { - rlc_rx_um_sdu_info& sdu = rx_window->add_sn(header.sn); + rlc_rx_um_sdu_info& rx_sdu = rx_window.has_sn(header.sn) ? rx_window[header.sn] : ([&]() -> rlc_rx_um_sdu_info& { + rlc_rx_um_sdu_info& sdu = rx_window.add_sn(header.sn); sdu.time_of_arrival = std::chrono::steady_clock::now(); return sdu; })(); @@ -449,13 +448,13 @@ void rlc_rx_um_entity::on_expired_reassembly_timer() for (; rx_mod_base(sn_upd) < rx_mod_base(st.rx_next_highest); sn_upd = (sn_upd + 1) % mod) { if (rx_mod_base(sn_upd) < rx_mod_base(st.rx_timer_trigger)) { // remove anything below rx_timer_trigger - if (rx_window->has_sn(sn_upd)) { - if (not(*rx_window)[sn_upd].fully_received) { + if (rx_window.has_sn(sn_upd)) { + if (not rx_window[sn_upd].fully_received) { // count incomplete SDUs as lost logger.log_info("Discarding incomplete SDU. sn={}", sn_upd); metrics.metrics_add_lost_pdus(1); } - rx_window->remove_sn(sn_upd); + rx_window.remove_sn(sn_upd); } else { // count non-existing SDUs as lost logger.log_info("Discarding SDU. sn={}", sn_upd); @@ -463,8 +462,8 @@ void rlc_rx_um_entity::on_expired_reassembly_timer() } } else { // continue removing fully received SDUs starting from rx_timer_trigger; stop at first incomplete or unseen SDU. - if (rx_window->has_sn(sn_upd) && (*rx_window)[sn_upd].fully_received) { - rx_window->remove_sn(sn_upd); + if (rx_window.has_sn(sn_upd) && rx_window[sn_upd].fully_received) { + rx_window.remove_sn(sn_upd); } else { break; // first SDU not fully received } @@ -485,7 +484,7 @@ void rlc_rx_um_entity::on_expired_reassembly_timer() restart_reassembly_timer = true; } if (rx_mod_base(st.rx_next_highest) == rx_mod_base(st.rx_next_reassembly + 1)) { - if (rx_window->has_sn(st.rx_next_highest) && (*rx_window)[st.rx_next_highest].has_gap) { + if (rx_window.has_sn(st.rx_next_highest) && rx_window[st.rx_next_highest].has_gap) { restart_reassembly_timer = true; } } @@ -512,23 +511,3 @@ bool rlc_rx_um_entity::sn_invalid_for_rx_buffer(const uint32_t sn) return (rx_mod_base(st.rx_next_highest - um_window_size) <= rx_mod_base(sn) && rx_mod_base(sn) < rx_mod_base(st.rx_next_reassembly)); } - -std::unique_ptr> rlc_rx_um_entity::create_rx_window(rlc_um_sn_size sn_size) -{ - std::unique_ptr> rx_window_; - switch (sn_size) { - case rlc_um_sn_size::size6bits: - rx_window_ = std::make_unique< - sdu_window_impl>( - logger); - break; - case rlc_um_sn_size::size12bits: - rx_window_ = std::make_unique< - sdu_window_impl>( - logger); - break; - default: - srsran_assertion_failure("Cannot create rx_window for unsupported sn_size={}.", to_number(sn_size)); - } - return rx_window_; -} diff --git a/lib/rlc/rlc_rx_um_entity.h b/lib/rlc/rlc_rx_um_entity.h index e49a651063..4d0579b648 100644 --- a/lib/rlc/rlc_rx_um_entity.h +++ b/lib/rlc/rlc_rx_um_entity.h @@ -80,7 +80,7 @@ class rlc_rx_um_entity : public rlc_rx_entity const uint32_t um_window_size; /// Rx window - std::unique_ptr> rx_window; + sdu_window rx_window; /// \brief t-Reassembly /// This timer is used by [...] the receiving side of an UM RLC entity in order to detect loss of RLC PDUs at lower @@ -106,7 +106,7 @@ class rlc_rx_um_entity : public rlc_rx_entity { // Stop all timers. Any queued handlers of timers that just expired before this call are canceled automatically reassembly_timer.stop(); - }; + } void on_expired_reassembly_timer(); @@ -143,11 +143,6 @@ class rlc_rx_um_entity : public rlc_rx_entity /// \return The reassembled SDU in case of success, default_error_t{} otherwise. expected reassemble_sdu(rlc_rx_um_sdu_info& sdu_info, uint32_t sn); - /// Creates the rx_window according to sn_size - /// \param sn_size Size of the sequence number (SN) - /// \return unique pointer to rx_window instance - std::unique_ptr> create_rx_window(rlc_um_sn_size sn_size); - bool sn_in_reassembly_window(const uint32_t sn); bool sn_invalid_for_rx_buffer(const uint32_t sn); diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index f85cd4710a..2d736a0260 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -9,7 +9,6 @@ */ #include "rlc_tx_am_entity.h" -#include "../support/sdu_window_impl.h" #include "srsran/adt/scope_exit.h" #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/pdcp/pdcp_sn_util.h" @@ -48,7 +47,7 @@ rlc_tx_am_entity::rlc_tx_am_entity(gnb_du_id_t gnb_du_i retx_queue(window_size(to_number(cfg.sn_field_length))), mod(cardinality(to_number(cfg.sn_field_length))), am_window_size(window_size(to_number(cfg.sn_field_length))), - tx_window(create_tx_window(cfg.sn_field_length)), + tx_window(logger, window_size(to_number(cfg.sn_field_length))), pdu_recycler(window_size(to_number(cfg.sn_field_length)), logger), head_min_size(rlc_am_pdu_header_min_size(cfg.sn_field_length)), head_max_size(rlc_am_pdu_header_max_size(cfg.sn_field_length)), @@ -144,7 +143,7 @@ size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) SRSRAN_RTSAN_NONBLO } const size_t grant_len = rlc_pdu_buf.size(); - logger.log_debug("MAC opportunity. grant_len={} tx_window_size={}", grant_len, tx_window->size()); + logger.log_debug("MAC opportunity. grant_len={} tx_window_size={}", grant_len, tx_window.size()); // TX STATUS if requested if (status_provider->status_report_required()) { @@ -203,8 +202,8 @@ size_t rlc_tx_am_entity::pull_pdu(span rlc_pdu_buf) SRSRAN_RTSAN_NONBLO // Send remaining segment, if it exists if (sn_under_segmentation != INVALID_RLC_SN) { - if (tx_window->has_sn(sn_under_segmentation)) { - size_t pdu_len = build_continued_sdu_segment(rlc_pdu_buf, (*tx_window)[sn_under_segmentation]); + if (tx_window.has_sn(sn_under_segmentation)) { + size_t pdu_len = build_continued_sdu_segment(rlc_pdu_buf, tx_window[sn_under_segmentation]); pcap.push_pdu(pcap_context, rlc_pdu_buf.subspan(0, pdu_len)); return pdu_len; } @@ -256,7 +255,7 @@ size_t rlc_tx_am_entity::build_new_pdu(span rlc_pdu_buf) // insert newly assigned SN into window and use reference for in-place operations // NOTE: from now on, we can't return from this function anymore before increasing tx_next - rlc_tx_am_sdu_info& sdu_info = tx_window->add_sn(st.tx_next); + rlc_tx_am_sdu_info& sdu_info = tx_window.add_sn(st.tx_next); sdu_info.sdu = std::move(sdu.buf); // Move SDU into TX window SDU info sdu_info.is_retx = sdu.is_retx; sdu_info.pdcp_sn = sdu.pdcp_sn; @@ -499,7 +498,7 @@ size_t rlc_tx_am_entity::build_retx_pdu(span rlc_pdu_buf) } // Sanity check - drop any retx SNs not present in tx_window - while (not tx_window->has_sn(retx_queue.front().sn)) { + while (not tx_window.has_sn(retx_queue.front().sn)) { logger.log_info("Could not find sn={} in tx window, dropping RETX.", retx_queue.front().sn); retx_queue.pop(); if (retx_queue.empty()) { @@ -513,7 +512,7 @@ size_t rlc_tx_am_entity::build_retx_pdu(span rlc_pdu_buf) retx_sn = retx.sn; // Get sdu_info info from tx_window - rlc_tx_am_sdu_info& sdu_info = (*tx_window)[retx.sn]; + rlc_tx_am_sdu_info& sdu_info = tx_window[retx.sn]; // Check RETX boundaries if (retx.so + retx.length > sdu_info.sdu.length()) { @@ -568,7 +567,7 @@ size_t rlc_tx_am_entity::build_retx_pdu(span rlc_pdu_buf) // the polling bit, to make sure the poll bit is calculated correctly if (retx_complete) { // Check if this SN triggered max_retx - if ((*tx_window)[retx.sn].retx_count == cfg.max_retx_thresh) { + if (tx_window[retx.sn].retx_count == cfg.max_retx_thresh) { max_retx_reached = true; } // remove RETX from queue @@ -714,7 +713,7 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_ * retransmission. */ // Process ACKs - uint32_t stop_sn = status.get_nacks().size() == 0 + uint32_t stop_sn = status.get_nacks().empty() ? status.ack_sn : status.get_nacks()[0].nack_sn; // Stop processing ACKs at the first NACK, if it exists. @@ -722,13 +721,13 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_ std::optional max_deliv_retx_pdcp_sn = {}; // initialize with not value set bool recycle_bin_full = false; for (uint32_t sn = st.tx_next_ack; tx_mod_base(sn) < tx_mod_base(stop_sn); sn = (sn + 1) % mod) { - if (tx_window->has_sn(sn)) { - rlc_tx_am_sdu_info& sdu_info = (*tx_window)[sn]; + if (tx_window.has_sn(sn)) { + rlc_tx_am_sdu_info& sdu_info = tx_window[sn]; if (sdu_info.pdcp_sn.has_value()) { if (sdu_info.is_retx) { - max_deliv_retx_pdcp_sn = (*tx_window)[sn].pdcp_sn; + max_deliv_retx_pdcp_sn = tx_window[sn].pdcp_sn; } else { - max_deliv_pdcp_sn = (*tx_window)[sn].pdcp_sn; + max_deliv_pdcp_sn = tx_window[sn].pdcp_sn; } } // move the PDU's byte_buffer from tx_window into pdu_recycler (if possible) for deletion off the critical path. @@ -736,7 +735,7 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_ // recycle bin is full and the PDU was deleted on the spot, which may slow down this worker. Warn later. recycle_bin_full = true; } - tx_window->remove_sn(sn); // remove the from tx_window + tx_window.remove_sn(sn); // remove the from tx_window st.tx_next_ack = (sn + 1) % mod; } else { logger.log_error("Could not find ACK'ed sn={} in TX window.", sn); @@ -758,7 +757,7 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) SRSRAN_RTSAN_ while (!retx_queue.empty()) { const rlc_tx_amd_retx& retx = retx_queue.front(); if (retx_sn != retx.sn) { - if (tx_window->has_sn(retx.sn)) { + if (tx_window.has_sn(retx.sn)) { decrement_retx_count(retx.sn); } retx_sn = retx.sn; @@ -844,7 +843,7 @@ bool rlc_tx_am_entity::handle_nack(rlc_am_status_nack nack) return false; } - const rlc_tx_am_sdu_info& sdu_info = (*tx_window)[nack.nack_sn]; + const rlc_tx_am_sdu_info& sdu_info = tx_window[nack.nack_sn]; uint32_t sdu_length = sdu_info.sdu.length(); // Convert NACK for full SDUs into NACK with segment offset and length @@ -926,7 +925,7 @@ bool rlc_tx_am_entity::handle_nack(rlc_am_status_nack nack) void rlc_tx_am_entity::increment_retx_count(uint32_t sn) { - auto& pdu = (*tx_window)[sn]; + auto& pdu = tx_window[sn]; // Increment retx_count if (pdu.retx_count == RETX_COUNT_NOT_STARTED) { // Set retx_count = 0 on first RE-transmission of associated SDU (38.322 Sec. 5.3.2) @@ -942,7 +941,7 @@ void rlc_tx_am_entity::increment_retx_count(uint32_t sn) void rlc_tx_am_entity::decrement_retx_count(uint32_t sn) { - auto& pdu = (*tx_window)[sn]; + auto& pdu = tx_window[sn]; if (pdu.retx_count == RETX_COUNT_NOT_STARTED) { return; } @@ -955,8 +954,8 @@ void rlc_tx_am_entity::decrement_retx_count(uint32_t sn) void rlc_tx_am_entity::check_sn_reached_max_retx(uint32_t sn) { - if ((*tx_window)[sn].retx_count == cfg.max_retx_thresh) { - logger.log_warning("Reached maximum number of RETX. sn={} retx_count={}", sn, (*tx_window)[sn].retx_count); + if (tx_window[sn].retx_count == cfg.max_retx_thresh) { + logger.log_warning("Reached maximum number of RETX. sn={} retx_count={}", sn, tx_window[sn].retx_count); upper_cn.on_max_retx(); } } @@ -1000,8 +999,8 @@ uint32_t rlc_tx_am_entity::get_buffer_state() // minimum bytes needed to tx SDU under segmentation + header (if applicable) uint32_t segment_bytes = 0; if (sn_under_segmentation != INVALID_RLC_SN) { - if (tx_window->has_sn(sn_under_segmentation)) { - rlc_tx_am_sdu_info& sdu_info = (*tx_window)[sn_under_segmentation]; + if (tx_window.has_sn(sn_under_segmentation)) { + rlc_tx_am_sdu_info& sdu_info = tx_window[sn_under_segmentation]; segment_bytes = sdu_info.sdu.length() - sdu_info.next_so + head_max_size; } else { logger.log_info("Buffer state ignores SDU under segmentation. sn={} not in tx_window.", sn_under_segmentation); @@ -1121,15 +1120,15 @@ void rlc_tx_am_entity::on_expired_poll_retransmit_timer() * - consider any RLC SDU which has not been positively acknowledged for retransmission. */ if ((sdu_queue.is_empty() && retx_queue.empty() && sn_under_segmentation == INVALID_RLC_SN) || is_tx_window_full()) { - if (tx_window->empty()) { + if (tx_window.empty()) { logger.log_info( - "Poll retransmit timer expired, but the TX window is empty. {} tx_window_size={}", st, tx_window->size()); + "Poll retransmit timer expired, but the TX window is empty. {} tx_window_size={}", st, tx_window.size()); return; } - if (not tx_window->has_sn(st.tx_next_ack)) { + if (not tx_window.has_sn(st.tx_next_ack)) { logger.log_info("Poll retransmit timer expired, but tx_next_ack is not in the TX window. {} tx_window_size={}", st, - tx_window->size()); + tx_window.size()); return; } // RETX first RLC SDU that has not been ACKed @@ -1138,7 +1137,7 @@ void rlc_tx_am_entity::on_expired_poll_retransmit_timer() rlc_tx_amd_retx retx = {}; retx.so = 0; retx.sn = st.tx_next_ack; - retx.length = (*tx_window)[st.tx_next_ack].sdu.length(); + retx.length = tx_window[st.tx_next_ack].sdu.length(); bool retx_enqueued = retx_queue.try_push(retx); // // TODO: Revise this: shall we send a minimum-sized segment instead? @@ -1163,26 +1162,6 @@ void rlc_tx_am_entity::on_expired_poll_retransmit_timer() is_poll_retransmit_timer_expired.store(true, std::memory_order_relaxed); } -std::unique_ptr> rlc_tx_am_entity::create_tx_window(rlc_am_sn_size sn_size) -{ - std::unique_ptr> tx_window_; - switch (sn_size) { - case rlc_am_sn_size::size12bits: - tx_window_ = std::make_unique< - sdu_window_impl>( - logger); - break; - case rlc_am_sn_size::size18bits: - tx_window_ = std::make_unique< - sdu_window_impl>( - logger); - break; - default: - srsran_assertion_failure("Cannot create tx_window for unsupported sn_size={}.", to_number(sn_size)); - } - return tx_window_; -} - bool rlc_tx_am_entity::inside_tx_window(uint32_t sn) const { // TX_Next_Ack <= SN < TX_Next_Ack + AM_Window_Size @@ -1192,7 +1171,7 @@ bool rlc_tx_am_entity::inside_tx_window(uint32_t sn) const bool rlc_tx_am_entity::is_tx_window_full() const { // TX window is full, or we reached our virtual max window size - return tx_window->full() || (cfg.max_window != 0 && tx_mod_base(st.tx_next) > cfg.max_window); + return tx_window.full() || (cfg.max_window != 0 && tx_mod_base(st.tx_next) > cfg.max_window); } bool rlc_tx_am_entity::valid_ack_sn(uint32_t sn) const diff --git a/lib/rlc/rlc_tx_am_entity.h b/lib/rlc/rlc_tx_am_entity.h index cf52de6b06..bd7b5e96ac 100644 --- a/lib/rlc/rlc_tx_am_entity.h +++ b/lib/rlc/rlc_tx_am_entity.h @@ -26,7 +26,7 @@ namespace srsran { /// Container to hold a SDU for transmission, the progress in case of segmentation, and associated meta data struct rlc_tx_am_sdu_info { - byte_buffer sdu = {}; ///< SDU buffer + byte_buffer sdu; ///< SDU buffer bool is_retx = false; ///< Determines whether this SDU is a PDCP retransmission std::optional pdcp_sn; ///< Optional PDCP sequence number std::chrono::system_clock::time_point time_of_arrival; @@ -93,7 +93,7 @@ class rlc_tx_am_entity : public rlc_tx_entity, public rlc_tx_am_status_handler, const uint32_t am_window_size; /// TX window - std::unique_ptr> tx_window; + sdu_window tx_window; /// Recycler for discarded PDUs (from tx_window) that shall be deleted by a different executor off the critical path rlc_pdu_recycler pdu_recycler; @@ -338,11 +338,6 @@ class rlc_tx_am_entity : public rlc_tx_entity, public rlc_tx_am_status_handler, /// \param force_notify forces a notification of the lower layer regardless of the current/previous buffer state. void update_mac_buffer_state(bool force_notify); - /// Creates the tx_window according to sn_size - /// \param sn_size Size of the sequence number (SN) - /// \return unique pointer to tx_window instance - std::unique_ptr> create_tx_window(rlc_am_sn_size sn_size); - void log_state(srslog::basic_levels level) { if (sn_under_segmentation == INVALID_RLC_SN) { diff --git a/lib/support/sdu_window_impl.h b/lib/support/sdu_window_impl.h deleted file mode 100644 index 2fb955ec88..0000000000 --- a/lib/support/sdu_window_impl.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#pragma once - -#include "srsran/adt/circular_map.h" -#include "srsran/support/sdu_window.h" -#include "srsran/support/srsran_assert.h" - -namespace srsran { - -/// \brief This class provides a container for the Tx/Rx windows holding SDU info objects that are indexed by -/// Sequence Numbers (SN) -/// @tparam T storage type -/// @tparam WINDOW_SIZE size of the window -/// @tparam PREFIXED_LOGGER an implementation of a prefixed_logger for logging -template -class sdu_window_impl final : public sdu_window -{ -public: - sdu_window_impl(PREFIXED_LOGGER& logger_) : logger(logger_) {} - ~sdu_window_impl() = default; - - T& add_sn(size_t sn) override - { - if (has_sn(sn)) { - logger.log_error("sn={} already present in window, overwriting.", sn); - srsran_assertion_failure("sn={} already present in window.", sn); - } else { - logger.log_debug("Adding sn={} to window.", sn); - } - window.overwrite(sn, T()); - return window[sn]; - } - void remove_sn(size_t sn) override - { - if (not has_sn(sn)) { - logger.log_error("Cannot remove sn={} because not contained in the window.", sn); - srsran_assertion_failure("Cannot remove sn={} because not contained in the window.", sn); - return; - } - logger.log_debug("Removing sn={} from window", sn); - window.erase(sn); - } - T& operator[](size_t sn) override { return window[sn]; } - size_t size() const override { return window.size(); } - bool full() const override { return window.full(); } - bool empty() const override { return window.empty(); } - void clear() override { window.clear(); } - - bool has_sn(uint32_t sn) const override { return window.contains(sn); } - -private: - PREFIXED_LOGGER& logger; - static_circular_map window; -}; - -} // namespace srsran From dd818fcbaf13f427c68272a3483cd0c4dd5a1e6c Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 30 Oct 2024 18:01:12 +0100 Subject: [PATCH 44/72] cu_cp,ngap: lower log level of pdu session setup timer expiration to info and improve log message --- lib/ngap/ngap_impl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 90414fd9b5..1c24d459d6 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -1067,8 +1067,8 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { // AMF never responded to InitialUEMessage, so we only remove the UE from the DU - ue_ctxt.logger.log_warning("PDU session setup timer expired after {}ms. Releasing UE from DU", - ue_ctxt.pdu_session_setup_timer.duration().count()); + ue_ctxt.logger.log_info("UE did not request a PDU session after {}ms. Releasing UE from DU", + ue_ctxt.pdu_session_setup_timer.duration().count()); ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); @@ -1077,8 +1077,8 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) CORO_RETURN(); })); } else { - ue_ctxt.logger.log_warning("PDU session setup timer expired after {}ms. Requesting UE release", - ue_ctxt.pdu_session_setup_timer.duration().count()); + ue_ctxt.logger.log_info("UE did not request a PDU session after {}ms. Requesting UE release", + ue_ctxt.pdu_session_setup_timer.duration().count()); // Request UE release ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { From 886ddf4edf0723ea4c5962d796e61328c615869a Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 7 Nov 2024 12:27:10 +0100 Subject: [PATCH 45/72] cu_cp,ngap: improve naming of pdu_session_setup_timeout --- apps/units/cu_cp/cu_cp_config_translators.cpp | 2 +- apps/units/cu_cp/cu_cp_unit_config.h | 4 +-- .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 8 +++--- .../cu_cp/cu_cp_unit_config_yaml_writer.cpp | 12 ++++---- include/srsran/cu_cp/ue_configuration.h | 4 +-- include/srsran/ngap/ngap_configuration.h | 2 +- include/srsran/ngap/ngap_context.h | 4 +-- lib/cu_cp/ngap_repository.cpp | 2 +- lib/ngap/ngap_impl.cpp | 28 +++++++++---------- lib/ngap/ngap_impl.h | 4 +-- lib/ngap/ue_context/ngap_ue_context.h | 4 +-- tests/e2e/tests/test_mode/config_ue.yml | 2 +- .../ngap/ngap_integration_test.cpp | 8 +++--- .../cu_cp/cu_cp_test_environment.cpp | 2 +- .../unittests/ngap/ngap_nas_message_test.cpp | 4 +-- ..._session_resource_setup_procedure_test.cpp | 4 +-- tests/unittests/ngap/ngap_test_helpers.cpp | 8 +++--- tests/unittests/ngap/ngap_validators_test.cpp | 2 +- 18 files changed, 52 insertions(+), 52 deletions(-) diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index 85aed9223e..9ef096f381 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -385,7 +385,7 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co // Timers out_cfg.ue.inactivity_timer = std::chrono::seconds{cu_cfg.inactivity_timer}; - out_cfg.ue.pdu_session_setup_timeout = std::chrono::seconds{cu_cfg.pdu_session_setup_timeout}; + out_cfg.ue.request_pdu_session_timeout = std::chrono::seconds{cu_cfg.request_pdu_session_timeout}; out_cfg.metrics.statistics_report_period = std::chrono::seconds{cu_cfg.metrics.cu_cp_statistics_report_period}; // Mobility diff --git a/apps/units/cu_cp/cu_cp_unit_config.h b/apps/units/cu_cp/cu_cp_unit_config.h index abf2a74bc7..52afbd7c7d 100644 --- a/apps/units/cu_cp/cu_cp_unit_config.h +++ b/apps/units/cu_cp/cu_cp_unit_config.h @@ -269,8 +269,8 @@ struct cu_cp_unit_config { uint8_t max_nof_drbs_per_ue = 8; /// Inactivity timer in seconds. int inactivity_timer = 120; - /// PDU session setup timeout in seconds (must be larger than T310). - unsigned pdu_session_setup_timeout = 3; + /// PDU session request timeout in seconds (must be larger than T310). + unsigned request_pdu_session_timeout = 3; /// Loggers configuration. cu_cp_unit_logger_config loggers; /// PCAPs configuration. diff --git a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp index 2ad46b610b..e45d7dec85 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -376,10 +376,10 @@ static void configure_cli11_cu_cp_args(CLI::App& app, cu_cp_unit_config& cu_cp_p ->check(CLI::Range(1, 7200)); add_option(app, - "--pdu_session_setup_timeout", - cu_cp_params.pdu_session_setup_timeout, - "Timeout for the setup of a PDU session after an InitialUeMessage was sent to the core, in " - "seconds. The timeout must be larger than T310. If the value is reached, the UE will be released") + "--request_pdu_session_timeout", + cu_cp_params.request_pdu_session_timeout, + "Timeout for requesting a PDU session after the InitialUeMessage was sent to the core, in " + "seconds. The timeout must be larger than T310. If the value is reached, the UE will be released.") ->capture_default_str(); CLI::App* amf_subcmd = app.add_subcommand("amf", "AMF configuration"); diff --git a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp index 58cb2f291a..8cd00c91cb 100644 --- a/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp +++ b/apps/units/cu_cp/cu_cp_unit_config_yaml_writer.cpp @@ -231,12 +231,12 @@ static YAML::Node build_cu_cp_section(const cu_cp_unit_config& config) { YAML::Node node; - node["max_nof_dus"] = config.max_nof_dus; - node["max_nof_cu_ups"] = config.max_nof_cu_ups; - node["max_nof_ues"] = config.max_nof_ues; - node["max_nof_drbs_per_ue"] = static_cast(config.max_nof_drbs_per_ue); - node["inactivity_timer"] = config.inactivity_timer; - node["pdu_session_setup_timeout"] = config.pdu_session_setup_timeout; + node["max_nof_dus"] = config.max_nof_dus; + node["max_nof_cu_ups"] = config.max_nof_cu_ups; + node["max_nof_ues"] = config.max_nof_ues; + node["max_nof_drbs_per_ue"] = static_cast(config.max_nof_drbs_per_ue); + node["inactivity_timer"] = config.inactivity_timer; + node["request_pdu_session_timeout"] = config.request_pdu_session_timeout; node["amf"] = build_cu_cp_amf_section(config.amf_config); if (!config.extra_amfs.empty()) { diff --git a/include/srsran/cu_cp/ue_configuration.h b/include/srsran/cu_cp/ue_configuration.h index 6cb61e9972..a34a960922 100644 --- a/include/srsran/cu_cp/ue_configuration.h +++ b/include/srsran/cu_cp/ue_configuration.h @@ -18,8 +18,8 @@ namespace srs_cu_cp { /// UE configuration passed to CU-CP struct ue_configuration { std::chrono::seconds inactivity_timer{7200}; - /// Timeout for PDU session to be setup in seconds, before the UE is released. - std::chrono::seconds pdu_session_setup_timeout = std::chrono::seconds{2}; + /// Timeout for requesting a PDU session in seconds, before the UE is released. + std::chrono::seconds request_pdu_session_timeout = std::chrono::seconds{2}; }; } // namespace srs_cu_cp diff --git a/include/srsran/ngap/ngap_configuration.h b/include/srsran/ngap/ngap_configuration.h index da40b53861..840b310c7b 100644 --- a/include/srsran/ngap/ngap_configuration.h +++ b/include/srsran/ngap/ngap_configuration.h @@ -26,7 +26,7 @@ struct ngap_configuration { gnb_id_t gnb_id{0, 22}; std::string ran_node_name; std::vector supported_tas; - std::chrono::seconds pdu_session_setup_timeout; // timeout for pdu session setup in seconds + std::chrono::seconds request_pdu_session_timeout; // timeout for requesting a pdu session in seconds }; } // namespace srs_cu_cp diff --git a/include/srsran/ngap/ngap_context.h b/include/srsran/ngap/ngap_context.h index 20cba188f6..a83fea3d6d 100644 --- a/include/srsran/ngap/ngap_context.h +++ b/include/srsran/ngap/ngap_context.h @@ -27,8 +27,8 @@ struct ngap_context_t { std::string ran_node_name; std::vector supported_tas; std::vector served_guami_list; - uint16_t default_paging_drx = 256; // default paging drx - std::chrono::seconds pdu_session_setup_timeout; // timeout for PDU context setup in seconds + uint16_t default_paging_drx = 256; // default paging drx + std::chrono::seconds request_pdu_session_timeout; // timeout for requesting a PDU session in seconds std::vector get_supported_plmns() const { diff --git a/lib/cu_cp/ngap_repository.cpp b/lib/cu_cp/ngap_repository.cpp index 70c9320a4f..f652438b44 100644 --- a/lib/cu_cp/ngap_repository.cpp +++ b/lib/cu_cp/ngap_repository.cpp @@ -36,7 +36,7 @@ ngap_interface* ngap_repository::add_ngap(amf_index_t amf_index, const cu_cp_con ngap_configuration ngap_cfg = {cfg.cu_cp.node.gnb_id, cfg.cu_cp.node.ran_node_name, config.supported_tas, - cfg.cu_cp.ue.pdu_session_setup_timeout}; + cfg.cu_cp.ue.request_pdu_session_timeout}; std::unique_ptr ngap_entity = create_ngap(ngap_cfg, ngap_ctxt.ngap_to_cu_cp_notifier, *config.n2_gw, diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 1c24d459d6..6834b0b05c 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -47,10 +47,10 @@ ngap_impl::ngap_impl(const ngap_configuration& ngap_cfg_, ev_mng(timer_factory{timers, ctrl_exec}), conn_handler(n2_gateway, *this, cu_cp_notifier, ctrl_exec) { - context.gnb_id = ngap_cfg_.gnb_id; - context.ran_node_name = ngap_cfg_.ran_node_name; - context.supported_tas = ngap_cfg_.supported_tas; - context.pdu_session_setup_timeout = ngap_cfg_.pdu_session_setup_timeout; + context.gnb_id = ngap_cfg_.gnb_id; + context.ran_node_name = ngap_cfg_.ran_node_name; + context.supported_tas = ngap_cfg_.supported_tas; + context.request_pdu_session_timeout = ngap_cfg_.request_pdu_session_timeout; } // Note: For fwd declaration of member types, dtor cannot be trivial. @@ -182,13 +182,13 @@ void ngap_impl::handle_initial_ue_message(const cu_cp_initial_ue_message& msg) fill_asn1_initial_ue_message(init_ue_msg, msg, context); // Start PDU session setup timer - ue_ctxt.pdu_session_setup_timer.set(context.pdu_session_setup_timeout, [this, msg](timer_id_t /*tid*/) { - on_pdu_session_setup_timer_expired(msg.ue_index); + ue_ctxt.request_pdu_session_timer.set(context.request_pdu_session_timeout, [this, msg](timer_id_t /*tid*/) { + on_request_pdu_session_timer_expired(msg.ue_index); }); - ue_ctxt.pdu_session_setup_timer.run(); + ue_ctxt.request_pdu_session_timer.run(); ue_ctxt.logger.log_debug("Starting PDU session creation timer (timeout={}ms)...", - ue_ctxt.pdu_session_setup_timer.duration().count()); + ue_ctxt.request_pdu_session_timer.duration().count()); // Forward message to AMF tx_pdu_notifier->on_new_message(ngap_msg); @@ -424,7 +424,7 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont // If InitialContextSetupRequest contains PDU Session Setup list, stop pdu session setup timer if (request->pdu_session_res_setup_list_cxt_req_present) { - ue_ctxt.pdu_session_setup_timer.stop(); + ue_ctxt.request_pdu_session_timer.stop(); } // Update AMF ID and use the one from this Context Setup as per TS 38.413 v16.2 page 38 @@ -490,7 +490,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ ue_ctxt.ue_ids.amf_ue_id); // Stop PDU session setup timer - ue_ctxt.pdu_session_setup_timer.stop(); + ue_ctxt.request_pdu_session_timer.stop(); if (!ue->is_security_enabled()) { ue_ctxt.logger.log_warning("Dropping PduSessionResourceSetupRequest. Security context does not exist"); @@ -918,7 +918,7 @@ async_task ngap_impl::handle_ue_context_release_request(const cu_cp_ue_con ngap_ue_context& ue_ctxt = ue_ctxt_list[msg.ue_index]; // Stop PDU session setup timer - ue_ctxt.pdu_session_setup_timer.stop(); + ue_ctxt.request_pdu_session_timer.stop(); if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { ue_ctxt.logger.log_debug("Ignoring UeContextReleaseRequest. UE does not have an AMF UE ID"); @@ -1053,7 +1053,7 @@ void ngap_impl::schedule_error_indication(ue_index_t ue_index, ngap_cause_t caus })); } -void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) +void ngap_impl::on_request_pdu_session_timer_expired(ue_index_t ue_index) { if (ue_ctxt_list.contains(ue_index)) { ngap_ue_context& ue_ctxt = ue_ctxt_list[ue_index]; @@ -1068,7 +1068,7 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) if (ue_ctxt.ue_ids.amf_ue_id == amf_ue_id_t::invalid) { // AMF never responded to InitialUEMessage, so we only remove the UE from the DU ue_ctxt.logger.log_info("UE did not request a PDU session after {}ms. Releasing UE from DU", - ue_ctxt.pdu_session_setup_timer.duration().count()); + ue_ctxt.request_pdu_session_timer.duration().count()); ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); @@ -1078,7 +1078,7 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) })); } else { ue_ctxt.logger.log_info("UE did not request a PDU session after {}ms. Requesting UE release", - ue_ctxt.pdu_session_setup_timer.duration().count()); + ue_ctxt.request_pdu_session_timer.duration().count()); // Request UE release ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { diff --git a/lib/ngap/ngap_impl.h b/lib/ngap/ngap_impl.h index e2407f26d4..0587ec0ed8 100644 --- a/lib/ngap/ngap_impl.h +++ b/lib/ngap/ngap_impl.h @@ -159,8 +159,8 @@ class ngap_impl final : public ngap_interface /// \param[in] amf_ue_id The AMF UE ID. void schedule_error_indication(ue_index_t ue_index, ngap_cause_t cause, std::optional amf_ue_id = {}); - /// \brief Callback for the PDU Session Setup Timer expiration. Triggers the release of the UE. - void on_pdu_session_setup_timer_expired(ue_index_t ue_index); + /// \brief Callback for the PDU Session Request Timer expiration. Triggers the release of the UE. + void on_request_pdu_session_timer_expired(ue_index_t ue_index); /// \brief Log NGAP RX PDU. void log_rx_pdu(const ngap_message& msg); diff --git a/lib/ngap/ue_context/ngap_ue_context.h b/lib/ngap/ue_context/ngap_ue_context.h index e520787c69..8fb89db9f3 100644 --- a/lib/ngap/ue_context/ngap_ue_context.h +++ b/lib/ngap/ue_context/ngap_ue_context.h @@ -30,7 +30,7 @@ struct ngap_ue_context { ngap_cu_cp_ue_notifier* ue = nullptr; guami_t serving_guami; uint64_t aggregate_maximum_bit_rate_dl = 0; - unique_timer pdu_session_setup_timer = {}; + unique_timer request_pdu_session_timer = {}; bool release_requested = false; bool release_scheduled = false; byte_buffer last_pdu_session_resource_modify_request; // To check if a received modify request is a duplicate @@ -43,7 +43,7 @@ struct ngap_ue_context { task_executor& task_exec_) : ue_ids({ue_index_, ran_ue_id_}), ue(&ue_notifier_), logger("NGAP", {ue_index_, ran_ue_id_}) { - pdu_session_setup_timer = timers_.create_unique_timer(task_exec_); + request_pdu_session_timer = timers_.create_unique_timer(task_exec_); } [[nodiscard]] ngap_cu_cp_ue_notifier* get_cu_cp_ue() const { return ue; } diff --git a/tests/e2e/tests/test_mode/config_ue.yml b/tests/e2e/tests/test_mode/config_ue.yml index b1fe7108d9..80a51b6a7f 100644 --- a/tests/e2e/tests/test_mode/config_ue.yml +++ b/tests/e2e/tests/test_mode/config_ue.yml @@ -10,7 +10,7 @@ cu_up: warn_on_drop: False cu_cp: - pdu_session_setup_timeout: 5 + request_pdu_session_timeout: 5 inactivity_timer: 3 rrc: force_reestablishment_fallback: false diff --git a/tests/integrationtests/ngap/ngap_integration_test.cpp b/tests/integrationtests/ngap/ngap_integration_test.cpp index 007c309a85..3e039b3560 100644 --- a/tests/integrationtests/ngap/ngap_integration_test.cpp +++ b/tests/integrationtests/ngap/ngap_integration_test.cpp @@ -126,10 +126,10 @@ class ngap_integration_test : public ::testing::Test return cucfg; }()) { - cfg.gnb_id = cu_cp_cfg.node.gnb_id; - cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; - cfg.supported_tas = cu_cp_cfg.ngaps.front().supported_tas; - cfg.pdu_session_setup_timeout = cu_cp_cfg.ue.pdu_session_setup_timeout; + cfg.gnb_id = cu_cp_cfg.node.gnb_id; + cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; + cfg.supported_tas = cu_cp_cfg.ngaps.front().supported_tas; + cfg.request_pdu_session_timeout = cu_cp_cfg.ue.request_pdu_session_timeout; } void SetUp() override diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index 852cddb272..c0a1aef43e 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -201,7 +201,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : cu_cp_cfg.f1ap.proc_timeout = std::chrono::milliseconds(10000); // procedure timeouts should only occur intentionally // > UE config - cu_cp_cfg.ue.pdu_session_setup_timeout = + cu_cp_cfg.ue.request_pdu_session_timeout = std::chrono::seconds(10); // procedure timeouts should only occur intentionally // create CU-CP instance. diff --git a/tests/unittests/ngap/ngap_nas_message_test.cpp b/tests/unittests/ngap/ngap_nas_message_test.cpp index cadff55433..a22c3df3d8 100644 --- a/tests/unittests/ngap/ngap_nas_message_test.cpp +++ b/tests/unittests/ngap/ngap_nas_message_test.cpp @@ -89,8 +89,8 @@ TEST_F(ngap_nas_message_routine_test, when_initial_context_setup_request_is_not_ ASSERT_EQ(ngap->get_nof_ues(), 1); // tick timers - // Status: NGAP does not receive new Initial Context Setup Request until pdu_session_setup_timer has ended. - for (unsigned msec_elapsed = 0; msec_elapsed < cu_cp_cfg.ue.pdu_session_setup_timeout.count() * 1000; + // Status: NGAP does not receive new Initial Context Setup Request until request_pdu_session_timer has ended. + for (unsigned msec_elapsed = 0; msec_elapsed < cu_cp_cfg.ue.request_pdu_session_timeout.count() * 1000; ++msec_elapsed) { this->tick(); } diff --git a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp index a08b30574a..0a43943e05 100644 --- a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp @@ -111,8 +111,8 @@ TEST_F(ngap_pdu_session_resource_setup_procedure_test, ASSERT_EQ(ngap->get_nof_ues(), 1); // tick timers - // Status: NGAP does not receive new PDU Session Resource Setup Request until pdu_session_setup_timer has ended. - for (unsigned msec_elapsed = 0; msec_elapsed < cu_cp_cfg.ue.pdu_session_setup_timeout.count() * 1000; + // Status: NGAP does not receive new PDU Session Resource Setup Request until request_pdu_session_timer has ended. + for (unsigned msec_elapsed = 0; msec_elapsed < cu_cp_cfg.ue.request_pdu_session_timeout.count() * 1000; ++msec_elapsed) { this->tick(); } diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index 6c560fff3a..d12ce3cc46 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -41,10 +41,10 @@ ngap_test::ngap_test() : srslog::init(); ngap_configuration ngap_cfg{}; - ngap_cfg.gnb_id = cu_cp_cfg.node.gnb_id; - ngap_cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; - ngap_cfg.supported_tas = cu_cp_cfg.ngaps.front().supported_tas; - ngap_cfg.pdu_session_setup_timeout = cu_cp_cfg.ue.pdu_session_setup_timeout; + ngap_cfg.gnb_id = cu_cp_cfg.node.gnb_id; + ngap_cfg.ran_node_name = cu_cp_cfg.node.ran_node_name; + ngap_cfg.supported_tas = cu_cp_cfg.ngaps.front().supported_tas; + ngap_cfg.request_pdu_session_timeout = cu_cp_cfg.ue.request_pdu_session_timeout; ngap = create_ngap(ngap_cfg, cu_cp_notifier, *cu_cp_cfg.ngaps.front().n2_gw, timers, ctrl_worker); cu_cp_notifier.connect_ngap(ngap->get_ngap_ue_context_removal_handler()); diff --git a/tests/unittests/ngap/ngap_validators_test.cpp b/tests/unittests/ngap/ngap_validators_test.cpp index 78d0823a38..51c4992a6f 100644 --- a/tests/unittests/ngap/ngap_validators_test.cpp +++ b/tests/unittests/ngap/ngap_validators_test.cpp @@ -249,7 +249,7 @@ TEST_F(ngap_validator_test, when_unique_and_duplicate_pdu_session_id_then_pdu_se // Test handling of PduSessionResourceSetupRequest with non-GBR QoS flows but no PDU Session Aggregate Maximum Bit Rate TEST_F( ngap_validator_test, - when_pdu_session_request_contains_non_gbr_qos_flows_but_no_aggregate_maximum_bitrate_then_pdu_session_setup_fails) + when_request_pdu_session_contains_non_gbr_qos_flows_but_no_aggregate_maximum_bitrate_then_pdu_session_setup_fails) { pdu_session_id_t psi = uint_to_pdu_session_id(1); ue_index_t ue_index = uint_to_ue_index(0); From 72758dbd62c1909f912f62ab228cd5322d4d583a Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Thu, 7 Nov 2024 11:04:00 +0100 Subject: [PATCH 46/72] tests, srs_estimator: new test vectors In the old test vectors, some values were represented with extreme precision that caused mismatches between vectors generated with different machines. --- .../srs/srs_estimator_test_data.h | 116 +++++++++--------- .../srs/srs_estimator_test_data.tar.gz | 4 +- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h index d64bdb3da6..a07f39cbff 100644 --- a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h +++ b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 05-11-2024 (seed 0): +// This file was generated using the following MATLAB class on 07-11-2024 (seed 0): // + "srsSRSEstimatorUnittest.m" #include "srsran/phy/upper/signal_processors/srs/srs_estimator_configuration.h" @@ -31,78 +31,78 @@ struct test_case_t { static const std::vector srs_estimator_test_data = { // clang-format off - {{{{0, 130, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 12, 17, 647, 2, srs_resource_configuration::comb_size_enum(2), 1, 1, 66, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.681653, -0.188013), cf_t(-0.704124, 0.064883)}}, 1, 2}, -1.4465e-15, 0, {0.000000313}}}, {"test_data/srs_estimator_test_input0.dat"}}, - {{{{0, 937, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 11, 2, 982, 3, srs_resource_configuration::comb_size_enum(4), 3, 9, 50, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.551089, 0.443059), cf_t(-0.395695, -0.586025)}}, 1, 2}, -3.3751e-15, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input1.dat"}}, - {{{{0, 283, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 99, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 25, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.068830, -0.703749), cf_t(0.273171, 0.652210), cf_t(0.198129, -0.678782), cf_t(-0.705645, 0.045444)}}, 2, 2}, -3.8573e-15, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input2.dat"}}, - {{{{0, 772, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 3, 10, 696, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 39, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.115826, 0.697556), cf_t(-0.022633, 0.706744), cf_t(0.005629, -0.707084), cf_t(-0.706612, -0.026460)}}, 2, 2}, 2.893e-15, 0, {0.000000207}}}, {"test_data/srs_estimator_test_input3.dat"}}, - {{{{0, 560, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 58, 152, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 38, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.628305, 0.324397), cf_t(-0.693909, -0.135978), cf_t(0.647192, -0.284854), cf_t(-0.642017, -0.296334), cf_t(0.666869, 0.235130), cf_t(0.128862, -0.695266), cf_t(0.484352, 0.515173), cf_t(-0.694070, 0.135157)}}, 4, 2}, 5.786e-15, 0, {-0.000000508}}}, {"test_data/srs_estimator_test_input4.dat"}}, - {{{{0, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 38, 541, 1, srs_resource_configuration::comb_size_enum(4), 2, 8, 30, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.611285, 0.355430), cf_t(0.604843, -0.366285), cf_t(0.324250, -0.628381), cf_t(0.706898, -0.017171), cf_t(0.093131, 0.700947), cf_t(0.407033, 0.578207), cf_t(-0.686686, -0.168708), cf_t(0.623507, 0.333526)}}, 4, 2}, 9.6433e-16, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input5.dat"}}, + {{{{0, 130, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 12, 17, 647, 2, srs_resource_configuration::comb_size_enum(2), 1, 1, 66, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.681653, -0.188013), cf_t(-0.704124, 0.064883)}}, 1, 2}, 0, 0, {0.000000313}}}, {"test_data/srs_estimator_test_input0.dat"}}, + {{{{0, 937, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 11, 2, 982, 3, srs_resource_configuration::comb_size_enum(4), 3, 9, 50, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.551089, 0.443059), cf_t(-0.395695, -0.586025)}}, 1, 2}, 0, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input1.dat"}}, + {{{{0, 283, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 99, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 25, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.068830, -0.703749), cf_t(0.273171, 0.652210), cf_t(0.198129, -0.678782), cf_t(-0.705645, 0.045444)}}, 2, 2}, 0, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input2.dat"}}, + {{{{0, 772, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 3, 10, 696, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 39, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.115826, 0.697556), cf_t(-0.022633, 0.706744), cf_t(0.005629, -0.707084), cf_t(-0.706612, -0.026460)}}, 2, 2}, 0, 0, {0.000000207}}}, {"test_data/srs_estimator_test_input3.dat"}}, + {{{{0, 560, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 58, 152, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 38, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.628305, 0.324397), cf_t(-0.693909, -0.135978), cf_t(0.647192, -0.284854), cf_t(-0.642017, -0.296334), cf_t(0.666869, 0.235130), cf_t(0.128862, -0.695266), cf_t(0.484352, 0.515173), cf_t(-0.694070, 0.135157)}}, 4, 2}, 0, 0, {-0.000000508}}}, {"test_data/srs_estimator_test_input4.dat"}}, + {{{{0, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 38, 541, 1, srs_resource_configuration::comb_size_enum(4), 2, 8, 30, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.611285, 0.355430), cf_t(0.604843, -0.366285), cf_t(0.324250, -0.628381), cf_t(0.706898, -0.017171), cf_t(0.093131, 0.700947), cf_t(0.407033, 0.578207), cf_t(-0.686686, -0.168708), cf_t(0.623507, 0.333526)}}, 4, 2}, 0, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input5.dat"}}, {{{{0, 4, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 5, 836, 1, srs_resource_configuration::comb_size_enum(2), 0, 5, 61, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.293626, 0.643260), cf_t(-0.061248, 0.704449)}}, 1, 2}, 0, 0, {-0.000000369}}}, {"test_data/srs_estimator_test_input6.dat"}}, - {{{{0, 593, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 39, 148, 1, srs_resource_configuration::comb_size_enum(4), 2, 0, 16, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.505253, 0.494691), cf_t(0.285273, 0.647008)}}, 1, 2}, -4.8216e-16, 0, {-0.000000271}}}, {"test_data/srs_estimator_test_input7.dat"}}, - {{{{0, 924, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 12, 15, 502, 1, srs_resource_configuration::comb_size_enum(2), 1, 0, 11, 0, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.418800, -0.569743), cf_t(-0.423687, -0.566118), cf_t(-0.081027, -0.702449), cf_t(-0.673755, 0.214601)}}, 2, 2}, 1.9287e-15, 0, {0.000000049}}}, {"test_data/srs_estimator_test_input8.dat"}}, - {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 8, 40, 187, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.650456, 0.277321), cf_t(-0.245156, 0.663248), cf_t(-0.667946, 0.232053), cf_t(-0.706097, -0.037785)}}, 2, 2}, -4.8216e-16, 0, {0.000000011}}}, {"test_data/srs_estimator_test_input9.dat"}}, - {{{{0, 659, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 22, 831, 3, srs_resource_configuration::comb_size_enum(2), 1, 7, 39, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.185548, 0.682328), cf_t(-0.695339, 0.128467), cf_t(0.394909, -0.586555), cf_t(0.106569, 0.699030), cf_t(-0.223768, 0.670767), cf_t(0.086472, 0.701800), cf_t(0.240509, 0.664948), cf_t(0.337891, 0.621152)}}, 4, 2}, -4.8216e-16, 0, {-0.000000284}}}, {"test_data/srs_estimator_test_input10.dat"}}, - {{{{0, 945, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 62, 189, 1, srs_resource_configuration::comb_size_enum(4), 0, 4, 40, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.054202, 0.705026), cf_t(-0.170613, -0.686215), cf_t(0.523244, 0.475621), cf_t(-0.296151, 0.642102), cf_t(-0.564546, -0.425779), cf_t(0.124868, 0.695994), cf_t(-0.204416, 0.676915), cf_t(-0.628347, 0.324314)}}, 4, 2}, 1.2536e-14, 0, {0.000000008}}}, {"test_data/srs_estimator_test_input11.dat"}}, - {{{{0, 820, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 14, 951, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 24, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.705092, -0.053344), cf_t(0.687321, 0.166103)}}, 1, 2}, 9.6433e-16, 0, {0.000000401}}}, {"test_data/srs_estimator_test_input12.dat"}}, - {{{{0, 101, 9, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 2, 8, 343, 2, srs_resource_configuration::comb_size_enum(4), 0, 5, 52, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.154090, -0.690113), cf_t(0.581620, -0.402142)}}, 1, 2}, -1.4465e-15, 0, {0.000000407}}}, {"test_data/srs_estimator_test_input13.dat"}}, - {{{{0, 202, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 11, 761, 0, srs_resource_configuration::comb_size_enum(2), 1, 5, 11, 6, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.700772, -0.094436), cf_t(-0.707104, -0.002095), cf_t(-0.164231, -0.687771), cf_t(-0.695472, 0.127746)}}, 2, 2}, 9.6433e-16, 0, {-0.000000459}}}, {"test_data/srs_estimator_test_input14.dat"}}, + {{{{0, 593, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 39, 148, 1, srs_resource_configuration::comb_size_enum(4), 2, 0, 16, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.505253, 0.494691), cf_t(0.285273, 0.647008)}}, 1, 2}, 0, 0, {-0.000000271}}}, {"test_data/srs_estimator_test_input7.dat"}}, + {{{{0, 924, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 12, 15, 502, 1, srs_resource_configuration::comb_size_enum(2), 1, 0, 11, 0, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.418800, -0.569743), cf_t(-0.423687, -0.566118), cf_t(-0.081027, -0.702449), cf_t(-0.673755, 0.214601)}}, 2, 2}, 0, 0, {0.000000049}}}, {"test_data/srs_estimator_test_input8.dat"}}, + {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 8, 40, 187, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.650456, 0.277321), cf_t(-0.245156, 0.663248), cf_t(-0.667946, 0.232053), cf_t(-0.706097, -0.037785)}}, 2, 2}, 0, 0, {0.000000011}}}, {"test_data/srs_estimator_test_input9.dat"}}, + {{{{0, 659, 8, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 22, 831, 3, srs_resource_configuration::comb_size_enum(2), 1, 7, 39, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.185548, 0.682328), cf_t(-0.695339, 0.128467), cf_t(0.394909, -0.586555), cf_t(0.106569, 0.699030), cf_t(-0.223768, 0.670767), cf_t(0.086472, 0.701800), cf_t(0.240509, 0.664948), cf_t(0.337891, 0.621152)}}, 4, 2}, 0, 0, {-0.000000284}}}, {"test_data/srs_estimator_test_input10.dat"}}, + {{{{0, 945, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 62, 189, 1, srs_resource_configuration::comb_size_enum(4), 0, 4, 40, 9, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.054202, 0.705026), cf_t(-0.170613, -0.686215), cf_t(0.523244, 0.475621), cf_t(-0.296151, 0.642102), cf_t(-0.564546, -0.425779), cf_t(0.124868, 0.695994), cf_t(-0.204416, 0.676915), cf_t(-0.628347, 0.324314)}}, 4, 2}, 0, 0, {0.000000008}}}, {"test_data/srs_estimator_test_input11.dat"}}, + {{{{0, 820, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 14, 951, 1, srs_resource_configuration::comb_size_enum(2), 1, 4, 24, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.705092, -0.053344), cf_t(0.687321, 0.166103)}}, 1, 2}, 0, 0, {0.000000401}}}, {"test_data/srs_estimator_test_input12.dat"}}, + {{{{0, 101, 9, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 2, 8, 343, 2, srs_resource_configuration::comb_size_enum(4), 0, 5, 52, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.154090, -0.690113), cf_t(0.581620, -0.402142)}}, 1, 2}, 0, 0, {0.000000407}}}, {"test_data/srs_estimator_test_input13.dat"}}, + {{{{0, 202, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 11, 761, 0, srs_resource_configuration::comb_size_enum(2), 1, 5, 11, 6, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.700772, -0.094436), cf_t(-0.707104, -0.002095), cf_t(-0.164231, -0.687771), cf_t(-0.695472, 0.127746)}}, 2, 2}, 0, 0, {-0.000000459}}}, {"test_data/srs_estimator_test_input14.dat"}}, {{{{0, 73, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 5, 52, 99, 2, srs_resource_configuration::comb_size_enum(4), 0, 6, 66, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.419244, -0.569416), cf_t(-0.677521, 0.202400), cf_t(0.219904, -0.672043), cf_t(-0.644261, 0.291424)}}, 2, 2}, 0, 0, {0.000000339}}}, {"test_data/srs_estimator_test_input15.dat"}}, - {{{{0, 177, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 4, 3, 851, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 42, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.184375, 0.682646), cf_t(0.703762, 0.068699), cf_t(0.351621, 0.613484), cf_t(-0.491797, 0.508071), cf_t(-0.642898, 0.294418), cf_t(0.703565, -0.070685), cf_t(0.555395, 0.437648), cf_t(0.226443, 0.669868)}}, 4, 2}, -4.8216e-16, 0, {-0.000000011}}}, {"test_data/srs_estimator_test_input16.dat"}}, - {{{{0, 942, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 27, 755, 2, srs_resource_configuration::comb_size_enum(4), 3, 11, 20, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.213860, -0.673991), cf_t(-0.685847, -0.172089), cf_t(-0.354087, -0.612064), cf_t(0.490441, 0.509380), cf_t(-0.354814, -0.611643), cf_t(-0.226497, -0.669850), cf_t(0.308558, 0.636233), cf_t(0.707095, -0.004086)}}, 4, 2}, -1.9287e-15, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input17.dat"}}, - {{{{0, 903, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 29, 195, 3, srs_resource_configuration::comb_size_enum(2), 0, 7, 25, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.256483, 0.658951), cf_t(-0.636466, 0.308076), cf_t(-0.702600, 0.079704), cf_t(0.513595, 0.486025)}}, 1, 4}, -1.4465e-15, 0, {0.000000093}}}, {"test_data/srs_estimator_test_input18.dat"}}, - {{{{0, 596, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 16, 297, 3, srs_resource_configuration::comb_size_enum(4), 3, 4, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.389686, 0.313280), cf_t(0.415836, -0.277633), cf_t(0.363739, -0.343066), cf_t(0.206503, -0.455364)}}, 1, 4}, 9.6433e-16, 0, {-0.000000249}}}, {"test_data/srs_estimator_test_input19.dat"}}, - {{{{0, 435, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 2, 165, 0, srs_resource_configuration::comb_size_enum(2), 0, 7, 27, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.300996, -0.639845), cf_t(-0.321596, 0.629743), cf_t(-0.139653, -0.693179), cf_t(0.557006, 0.435596), cf_t(0.693433, -0.138388), cf_t(-0.542110, -0.454000), cf_t(-0.693447, -0.138315), cf_t(0.127268, -0.695559)}}, 2, 4}, -3.3751e-15, 0, {-0.000000080}}}, {"test_data/srs_estimator_test_input20.dat"}}, - {{{{0, 157, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 29, 450, 3, srs_resource_configuration::comb_size_enum(4), 2, 7, 65, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.041264, 0.705902), cf_t(-0.238936, -0.665514), cf_t(-0.316569, -0.632285), cf_t(0.643555, 0.292979), cf_t(-0.171822, 0.685913), cf_t(-0.021279, 0.706787), cf_t(-0.333590, -0.623472), cf_t(0.114826, 0.697721)}}, 2, 4}, 9.6433e-16, 0, {0.000000175}}}, {"test_data/srs_estimator_test_input21.dat"}}, - {{{{0, 799, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 24, 6, 3, srs_resource_configuration::comb_size_enum(2), 0, 5, 31, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.089328, -0.701442), cf_t(0.689330, 0.157556), cf_t(0.405786, 0.579084), cf_t(-0.051373, -0.705238), cf_t(-0.310971, 0.635056), cf_t(0.317553, 0.631791), cf_t(-0.383096, 0.594338), cf_t(0.031758, 0.706393), cf_t(0.153120, -0.690329), cf_t(-0.124818, -0.696003), cf_t(-0.552155, -0.441729), cf_t(0.614049, -0.350634), cf_t(-0.695687, 0.126571), cf_t(-0.697317, 0.117255), cf_t(0.253078, 0.660266), cf_t(-0.084486, 0.702041)}}, 4, 4}, -4.8216e-16, 0, {0.000000277}}}, {"test_data/srs_estimator_test_input22.dat"}}, - {{{{0, 93, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 8, 27, 699, 2, srs_resource_configuration::comb_size_enum(4), 2, 7, 64, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.180430, 0.683700), cf_t(-0.552392, -0.441433), cf_t(0.089882, -0.701371), cf_t(0.386095, -0.592394), cf_t(-0.178940, -0.684091), cf_t(-0.672687, 0.217926), cf_t(-0.416410, 0.571492), cf_t(0.351950, -0.613296), cf_t(0.061100, 0.704462), cf_t(-0.683462, 0.181329), cf_t(-0.371318, -0.601766), cf_t(-0.028609, 0.706528), cf_t(0.517291, 0.482089), cf_t(-0.371563, -0.601615), cf_t(-0.611241, 0.355506), cf_t(-0.534906, -0.462466)}}, 4, 4}, 1.9287e-15, 0, {0.000000086}}}, {"test_data/srs_estimator_test_input23.dat"}}, - {{{{0, 271, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 4, 41, 122, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 36, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.127928, -0.695438), cf_t(-0.700055, -0.099612), cf_t(0.706554, -0.027962), cf_t(0.138269, 0.693456)}}, 1, 4}, -3.3751e-15, 0, {-0.000000411}}}, {"test_data/srs_estimator_test_input24.dat"}}, + {{{{0, 177, 0, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 4, 3, 851, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 42, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.184375, 0.682646), cf_t(0.703762, 0.068699), cf_t(0.351621, 0.613484), cf_t(-0.491797, 0.508071), cf_t(-0.642898, 0.294418), cf_t(0.703565, -0.070685), cf_t(0.555395, 0.437648), cf_t(0.226443, 0.669868)}}, 4, 2}, 0, 0, {-0.000000011}}}, {"test_data/srs_estimator_test_input16.dat"}}, + {{{{0, 942, 3, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 27, 755, 2, srs_resource_configuration::comb_size_enum(4), 3, 11, 20, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.213860, -0.673991), cf_t(-0.685847, -0.172089), cf_t(-0.354087, -0.612064), cf_t(0.490441, 0.509380), cf_t(-0.354814, -0.611643), cf_t(-0.226497, -0.669850), cf_t(0.308558, 0.636233), cf_t(0.707095, -0.004086)}}, 4, 2}, 0, 0, {-0.000000343}}}, {"test_data/srs_estimator_test_input17.dat"}}, + {{{{0, 903, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 29, 195, 3, srs_resource_configuration::comb_size_enum(2), 0, 7, 25, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.256483, 0.658951), cf_t(-0.636466, 0.308076), cf_t(-0.702600, 0.079704), cf_t(0.513595, 0.486025)}}, 1, 4}, 0, 0, {0.000000093}}}, {"test_data/srs_estimator_test_input18.dat"}}, + {{{{0, 596, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 16, 297, 3, srs_resource_configuration::comb_size_enum(4), 3, 4, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.389686, 0.313280), cf_t(0.415836, -0.277633), cf_t(0.363739, -0.343066), cf_t(0.206503, -0.455364)}}, 1, 4}, 0, 0, {-0.000000249}}}, {"test_data/srs_estimator_test_input19.dat"}}, + {{{{0, 435, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 2, 165, 0, srs_resource_configuration::comb_size_enum(2), 0, 7, 27, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.300996, -0.639845), cf_t(-0.321596, 0.629743), cf_t(-0.139653, -0.693179), cf_t(0.557006, 0.435596), cf_t(0.693433, -0.138388), cf_t(-0.542110, -0.454000), cf_t(-0.693447, -0.138315), cf_t(0.127268, -0.695559)}}, 2, 4}, 0, 0, {-0.000000080}}}, {"test_data/srs_estimator_test_input20.dat"}}, + {{{{0, 157, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 3, 29, 450, 3, srs_resource_configuration::comb_size_enum(4), 2, 7, 65, 5, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.041264, 0.705902), cf_t(-0.238936, -0.665514), cf_t(-0.316569, -0.632285), cf_t(0.643555, 0.292979), cf_t(-0.171822, 0.685913), cf_t(-0.021279, 0.706787), cf_t(-0.333590, -0.623472), cf_t(0.114826, 0.697721)}}, 2, 4}, 0, 0, {0.000000175}}}, {"test_data/srs_estimator_test_input21.dat"}}, + {{{{0, 799, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 9, 24, 6, 3, srs_resource_configuration::comb_size_enum(2), 0, 5, 31, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.089328, -0.701442), cf_t(0.689330, 0.157556), cf_t(0.405786, 0.579084), cf_t(-0.051373, -0.705238), cf_t(-0.310971, 0.635056), cf_t(0.317553, 0.631791), cf_t(-0.383096, 0.594338), cf_t(0.031758, 0.706393), cf_t(0.153120, -0.690329), cf_t(-0.124818, -0.696003), cf_t(-0.552155, -0.441729), cf_t(0.614049, -0.350634), cf_t(-0.695687, 0.126571), cf_t(-0.697317, 0.117255), cf_t(0.253078, 0.660266), cf_t(-0.084486, 0.702041)}}, 4, 4}, 0, 0, {0.000000277}}}, {"test_data/srs_estimator_test_input22.dat"}}, + {{{{0, 93, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 8, 27, 699, 2, srs_resource_configuration::comb_size_enum(4), 2, 7, 64, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.180430, 0.683700), cf_t(-0.552392, -0.441433), cf_t(0.089882, -0.701371), cf_t(0.386095, -0.592394), cf_t(-0.178940, -0.684091), cf_t(-0.672687, 0.217926), cf_t(-0.416410, 0.571492), cf_t(0.351950, -0.613296), cf_t(0.061100, 0.704462), cf_t(-0.683462, 0.181329), cf_t(-0.371318, -0.601766), cf_t(-0.028609, 0.706528), cf_t(0.517291, 0.482089), cf_t(-0.371563, -0.601615), cf_t(-0.611241, 0.355506), cf_t(-0.534906, -0.462466)}}, 4, 4}, 0, 0, {0.000000086}}}, {"test_data/srs_estimator_test_input23.dat"}}, + {{{{0, 271, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 4, 41, 122, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 36, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.127928, -0.695438), cf_t(-0.700055, -0.099612), cf_t(0.706554, -0.027962), cf_t(0.138269, 0.693456)}}, 1, 4}, 0, 0, {-0.000000411}}}, {"test_data/srs_estimator_test_input24.dat"}}, {{{{0, 414, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 40, 374, 3, srs_resource_configuration::comb_size_enum(4), 3, 2, 9, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.165621, -0.471773), cf_t(0.415613, 0.277968), cf_t(-0.493644, -0.079472), cf_t(-0.490940, -0.094753)}}, 1, 4}, 0, 0, {0.000000376}}}, {"test_data/srs_estimator_test_input25.dat"}}, - {{{{0, 687, 4, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 9, 1, 532, 1, srs_resource_configuration::comb_size_enum(2), 0, 2, 55, 4, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.452308, 0.213113), cf_t(-0.398502, 0.301987), cf_t(0.380755, -0.324076), cf_t(0.179714, -0.466586), cf_t(-0.387615, 0.315840), cf_t(0.015947, -0.499746), cf_t(0.059905, -0.496398), cf_t(-0.358835, 0.348192)}}, 2, 4}, 9.6433e-16, 0, {-0.000000296}}}, {"test_data/srs_estimator_test_input26.dat"}}, - {{{{0, 335, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 49, 449, 0, srs_resource_configuration::comb_size_enum(4), 3, 6, 60, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.601683, -0.371453), cf_t(-0.005750, -0.707083), cf_t(0.398363, 0.584215), cf_t(0.323329, -0.628855), cf_t(0.219088, 0.672310), cf_t(0.175691, -0.684933), cf_t(-0.589672, 0.390240), cf_t(-0.295126, 0.642573)}}, 2, 4}, -2.4108e-15, 0, {0.000000035}}}, {"test_data/srs_estimator_test_input27.dat"}}, - {{{{0, 139, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 31, 507, 0, srs_resource_configuration::comb_size_enum(2), 0, 6, 63, 2, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.232542, -0.667776), cf_t(0.705391, -0.049225), cf_t(0.705698, -0.044620), cf_t(0.098124, 0.700265), cf_t(-0.613574, -0.351464), cf_t(0.707103, 0.002321), cf_t(-0.696439, -0.122360), cf_t(-0.707056, 0.008467), cf_t(0.282445, -0.648248), cf_t(0.469078, -0.529118), cf_t(-0.701262, 0.090724), cf_t(0.574279, -0.412557), cf_t(0.512450, -0.487232), cf_t(-0.537496, -0.459454), cf_t(0.224194, -0.670624), cf_t(-0.630719, -0.319678)}}, 4, 4}, 9.6433e-16, 0, {0.000000360}}}, {"test_data/srs_estimator_test_input28.dat"}}, + {{{{0, 687, 4, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 9, 1, 532, 1, srs_resource_configuration::comb_size_enum(2), 0, 2, 55, 4, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.452308, 0.213113), cf_t(-0.398502, 0.301987), cf_t(0.380755, -0.324076), cf_t(0.179714, -0.466586), cf_t(-0.387615, 0.315840), cf_t(0.015947, -0.499746), cf_t(0.059905, -0.496398), cf_t(-0.358835, 0.348192)}}, 2, 4}, 0, 0, {-0.000000296}}}, {"test_data/srs_estimator_test_input26.dat"}}, + {{{{0, 335, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 49, 449, 0, srs_resource_configuration::comb_size_enum(4), 3, 6, 60, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.601683, -0.371453), cf_t(-0.005750, -0.707083), cf_t(0.398363, 0.584215), cf_t(0.323329, -0.628855), cf_t(0.219088, 0.672310), cf_t(0.175691, -0.684933), cf_t(-0.589672, 0.390240), cf_t(-0.295126, 0.642573)}}, 2, 4}, 0, 0, {0.000000035}}}, {"test_data/srs_estimator_test_input27.dat"}}, + {{{{0, 139, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 31, 507, 0, srs_resource_configuration::comb_size_enum(2), 0, 6, 63, 2, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.232542, -0.667776), cf_t(0.705391, -0.049225), cf_t(0.705698, -0.044620), cf_t(0.098124, 0.700265), cf_t(-0.613574, -0.351464), cf_t(0.707103, 0.002321), cf_t(-0.696439, -0.122360), cf_t(-0.707056, 0.008467), cf_t(0.282445, -0.648248), cf_t(0.469078, -0.529118), cf_t(-0.701262, 0.090724), cf_t(0.574279, -0.412557), cf_t(0.512450, -0.487232), cf_t(-0.537496, -0.459454), cf_t(0.224194, -0.670624), cf_t(-0.630719, -0.319678)}}, 4, 4}, 0, 0, {0.000000360}}}, {"test_data/srs_estimator_test_input28.dat"}}, {{{{0, 252, 7, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 42, 85, 2, srs_resource_configuration::comb_size_enum(4), 3, 9, 39, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.636582, -0.307836), cf_t(0.459941, -0.537080), cf_t(-0.669283, -0.228167), cf_t(-0.458930, 0.537944), cf_t(-0.619449, -0.341003), cf_t(-0.703668, 0.069656), cf_t(-0.484425, -0.515104), cf_t(0.673137, 0.216532), cf_t(0.703085, 0.075310), cf_t(0.396922, -0.585194), cf_t(0.692870, 0.141177), cf_t(-0.705589, 0.046306), cf_t(0.512837, 0.486825), cf_t(0.178409, 0.684230), cf_t(-0.531250, -0.466662), cf_t(0.249901, 0.661475)}}, 4, 4}, 0, 0, {-0.000000393}}}, {"test_data/srs_estimator_test_input29.dat"}}, {{{{0, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 34, 650, 2, srs_resource_configuration::comb_size_enum(2), 0, 5, 8, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.705809, 0.042815), cf_t(0.426329, -0.564131), cf_t(0.496619, -0.503358), cf_t(-0.089921, 0.701366)}}, 1, 4}, 0, 0, {-0.000000304}}}, {"test_data/srs_estimator_test_input30.dat"}}, - {{{{0, 427, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 2, 6, 970, 0, srs_resource_configuration::comb_size_enum(4), 0, 6, 3, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.642064, -0.296233), cf_t(-0.094520, -0.700761), cf_t(-0.053966, -0.705044), cf_t(0.651733, 0.274306)}}, 1, 4}, 1.9287e-15, 0, {0.000000375}}}, {"test_data/srs_estimator_test_input31.dat"}}, - {{{{0, 879, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 25, 525, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.248919, 0.433635), cf_t(0.273741, -0.418409), cf_t(-0.489335, 0.102722), cf_t(-0.465999, -0.181233), cf_t(-0.298453, -0.401156), cf_t(0.304214, -0.396804), cf_t(0.493732, 0.078925), cf_t(-0.288476, 0.408389)}}, 2, 4}, -9.6433e-16, 0, {-0.000000056}}}, {"test_data/srs_estimator_test_input32.dat"}}, - {{{{0, 678, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 3, 63, 920, 2, srs_resource_configuration::comb_size_enum(4), 2, 3, 28, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.487848, 0.109562), cf_t(0.218227, 0.449863), cf_t(0.043791, -0.498079), cf_t(-0.317827, 0.385987), cf_t(0.207771, -0.454787), cf_t(0.468599, 0.174398), cf_t(0.404099, 0.294455), cf_t(-0.495280, -0.068539)}}, 2, 4}, -4.8216e-16, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input33.dat"}}, - {{{{0, 926, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 6, 479, 2, srs_resource_configuration::comb_size_enum(2), 1, 2, 40, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.154320, 0.475589), cf_t(0.450451, 0.217010), cf_t(0.498260, 0.041682), cf_t(-0.176346, 0.467870), cf_t(0.332718, 0.373228), cf_t(0.023595, 0.499443), cf_t(0.399259, -0.300985), cf_t(-0.481063, 0.136302), cf_t(0.116412, 0.486259), cf_t(0.471752, 0.165682), cf_t(0.164458, 0.472179), cf_t(0.401404, 0.298119), cf_t(0.394965, -0.306598), cf_t(-0.466853, 0.179022), cf_t(0.416396, 0.276793), cf_t(0.499790, -0.014482)}}, 4, 4}, 9.6433e-16, 0, {-0.000000175}}}, {"test_data/srs_estimator_test_input34.dat"}}, - {{{{0, 305, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 40, 517, 0, srs_resource_configuration::comb_size_enum(4), 0, 10, 36, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.547223, 0.447825), cf_t(-0.016378, -0.706917), cf_t(-0.562870, -0.427992), cf_t(0.138503, -0.693410), cf_t(0.324218, -0.628397), cf_t(0.705616, 0.045892), cf_t(-0.697618, -0.115451), cf_t(-0.167131, 0.687072), cf_t(-0.371724, 0.601516), cf_t(0.674598, 0.211937), cf_t(-0.089905, -0.701368), cf_t(-0.249812, -0.661509), cf_t(-0.192891, 0.680289), cf_t(-0.348735, -0.615129), cf_t(-0.187643, -0.681755), cf_t(-0.662754, -0.246491)}}, 4, 4}, -4.3395e-15, 0, {-0.000000108}}}, {"test_data/srs_estimator_test_input35.dat"}}, - {{{{1, 345, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 8, 7, 759, 0, srs_resource_configuration::comb_size_enum(2), 1, 7, 50, 7, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.612700, -0.352985), cf_t(-0.044256, -0.705720)}}, 1, 2}, 4.8216e-15, 0, {-0.000000138}}}, {"test_data/srs_estimator_test_input36.dat"}}, + {{{{0, 427, 5, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 2, 6, 970, 0, srs_resource_configuration::comb_size_enum(4), 0, 6, 3, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.642064, -0.296233), cf_t(-0.094520, -0.700761), cf_t(-0.053966, -0.705044), cf_t(0.651733, 0.274306)}}, 1, 4}, 0, 0, {0.000000375}}}, {"test_data/srs_estimator_test_input31.dat"}}, + {{{{0, 879, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 25, 525, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.248919, 0.433635), cf_t(0.273741, -0.418409), cf_t(-0.489335, 0.102722), cf_t(-0.465999, -0.181233), cf_t(-0.298453, -0.401156), cf_t(0.304214, -0.396804), cf_t(0.493732, 0.078925), cf_t(-0.288476, 0.408389)}}, 2, 4}, 0, 0, {-0.000000056}}}, {"test_data/srs_estimator_test_input32.dat"}}, + {{{{0, 678, 0, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 3, 63, 920, 2, srs_resource_configuration::comb_size_enum(4), 2, 3, 28, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.487848, 0.109562), cf_t(0.218227, 0.449863), cf_t(0.043791, -0.498079), cf_t(-0.317827, 0.385987), cf_t(0.207771, -0.454787), cf_t(0.468599, 0.174398), cf_t(0.404099, 0.294455), cf_t(-0.495280, -0.068539)}}, 2, 4}, 0, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input33.dat"}}, + {{{{0, 926, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 6, 479, 2, srs_resource_configuration::comb_size_enum(2), 1, 2, 40, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.154320, 0.475589), cf_t(0.450451, 0.217010), cf_t(0.498260, 0.041682), cf_t(-0.176346, 0.467870), cf_t(0.332718, 0.373228), cf_t(0.023595, 0.499443), cf_t(0.399259, -0.300985), cf_t(-0.481063, 0.136302), cf_t(0.116412, 0.486259), cf_t(0.471752, 0.165682), cf_t(0.164458, 0.472179), cf_t(0.401404, 0.298119), cf_t(0.394965, -0.306598), cf_t(-0.466853, 0.179022), cf_t(0.416396, 0.276793), cf_t(0.499790, -0.014482)}}, 4, 4}, 0, 0, {-0.000000175}}}, {"test_data/srs_estimator_test_input34.dat"}}, + {{{{0, 305, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 40, 517, 0, srs_resource_configuration::comb_size_enum(4), 0, 10, 36, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.547223, 0.447825), cf_t(-0.016378, -0.706917), cf_t(-0.562870, -0.427992), cf_t(0.138503, -0.693410), cf_t(0.324218, -0.628397), cf_t(0.705616, 0.045892), cf_t(-0.697618, -0.115451), cf_t(-0.167131, 0.687072), cf_t(-0.371724, 0.601516), cf_t(0.674598, 0.211937), cf_t(-0.089905, -0.701368), cf_t(-0.249812, -0.661509), cf_t(-0.192891, 0.680289), cf_t(-0.348735, -0.615129), cf_t(-0.187643, -0.681755), cf_t(-0.662754, -0.246491)}}, 4, 4}, 0, 0, {-0.000000108}}}, {"test_data/srs_estimator_test_input35.dat"}}, + {{{{1, 345, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 8, 7, 759, 0, srs_resource_configuration::comb_size_enum(2), 1, 7, 50, 7, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.612700, -0.352985), cf_t(-0.044256, -0.705720)}}, 1, 2}, 0, 0, {-0.000000138}}}, {"test_data/srs_estimator_test_input36.dat"}}, {{{{1, 887, 7, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 1, 43, 375, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 5, 4, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.097142, -0.700402), cf_t(0.194397, 0.679860)}}, 1, 2}, 0, 0, {-0.000000058}}}, {"test_data/srs_estimator_test_input37.dat"}}, - {{{{1, 657, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 6, 6, 155, 1, srs_resource_configuration::comb_size_enum(2), 0, 1, 27, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.559142, 0.432851), cf_t(0.151769, -0.690627), cf_t(0.538311, 0.458499), cf_t(-0.182599, 0.683123)}}, 2, 2}, 9.6433e-16, 0, {0.000000054}}}, {"test_data/srs_estimator_test_input38.dat"}}, + {{{{1, 657, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 6, 6, 155, 1, srs_resource_configuration::comb_size_enum(2), 0, 1, 27, 8, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.559142, 0.432851), cf_t(0.151769, -0.690627), cf_t(0.538311, 0.458499), cf_t(-0.182599, 0.683123)}}, 2, 2}, 0, 0, {0.000000054}}}, {"test_data/srs_estimator_test_input38.dat"}}, {{{{1, 711, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 10, 7, 443, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 33, 7, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.084030, -0.702096), cf_t(-0.101562, 0.699775), cf_t(-0.561454, 0.429848), cf_t(0.687844, 0.163924)}}, 2, 2}, 0, 0, {0.000000090}}}, {"test_data/srs_estimator_test_input39.dat"}}, - {{{{1, 624, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 323, 0, srs_resource_configuration::comb_size_enum(2), 0, 0, 28, 8, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.395344, -0.586262), cf_t(-0.693555, -0.137772), cf_t(-0.478297, -0.520799), cf_t(0.469935, 0.528357), cf_t(-0.119723, -0.696898), cf_t(0.548168, 0.446668), cf_t(0.495266, 0.504690), cf_t(0.575711, 0.410557)}}, 4, 2}, -2.2662e-14, 0, {-0.000000186}}}, {"test_data/srs_estimator_test_input40.dat"}}, - {{{{1, 325, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 57, 222, 2, srs_resource_configuration::comb_size_enum(4), 2, 2, 5, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.605906, -0.364524), cf_t(-0.661004, -0.251145), cf_t(0.355334, 0.611341), cf_t(0.705076, -0.053553), cf_t(-0.189947, -0.681117), cf_t(-0.274407, 0.651691), cf_t(-0.507800, -0.492076), cf_t(0.338968, 0.620565)}}, 4, 2}, -4.8216e-16, 0, {-0.000000126}}}, {"test_data/srs_estimator_test_input41.dat"}}, - {{{{1, 700, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 43, 1006, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 22, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.215231, 0.673555), cf_t(-0.675969, 0.207525)}}, 1, 2}, -3.8573e-15, 0, {-0.000000040}}}, {"test_data/srs_estimator_test_input42.dat"}}, - {{{{1, 760, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 1, 439, 1, srs_resource_configuration::comb_size_enum(4), 1, 11, 63, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.682496, 0.184930), cf_t(0.042278, 0.705842)}}, 1, 2}, -1.4465e-15, 0, {0.000000137}}}, {"test_data/srs_estimator_test_input43.dat"}}, - {{{{1, 761, 7, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 1, 13, 697, 0, srs_resource_configuration::comb_size_enum(2), 1, 1, 45, 5, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.557057, -0.435531), cf_t(-0.207059, -0.676111), cf_t(-0.703283, -0.073434), cf_t(0.402617, 0.581291)}}, 2, 2}, -1.3501e-14, 0, {0.000000236}}}, {"test_data/srs_estimator_test_input44.dat"}}, - {{{{1, 37, 5, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 33, 766, 1, srs_resource_configuration::comb_size_enum(4), 2, 4, 12, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.023928, 0.706702), cf_t(0.627344, -0.326251), cf_t(0.701229, 0.090985), cf_t(-0.402217, -0.581568)}}, 2, 2}, -2.0733e-14, 0, {0.000000225}}}, {"test_data/srs_estimator_test_input45.dat"}}, - {{{{1, 813, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 32, 450, 2, srs_resource_configuration::comb_size_enum(2), 1, 0, 58, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.480184, -0.519060), cf_t(0.706981, -0.013313), cf_t(-0.406768, -0.578394), cf_t(-0.536953, 0.460089), cf_t(-0.433649, 0.558523), cf_t(0.114250, 0.697816), cf_t(-0.558749, -0.433358), cf_t(0.443197, 0.550978)}}, 4, 2}, 9.6433e-16, 0, {-0.000000247}}}, {"test_data/srs_estimator_test_input46.dat"}}, - {{{{1, 743, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 36, 861, 0, srs_resource_configuration::comb_size_enum(4), 3, 11, 15, 8, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.495468, 0.504492), cf_t(-0.450328, -0.545165), cf_t(0.678967, 0.197495), cf_t(-0.406363, 0.578678), cf_t(0.602907, 0.369464), cf_t(0.298589, 0.640971), cf_t(-0.118624, -0.697086), cf_t(-0.376570, -0.598494)}}, 4, 2}, -8.6789e-15, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input47.dat"}}, - {{{{1, 932, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 8, 24, 763, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 16, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.674713, 0.211572), cf_t(0.098696, 0.700185)}}, 1, 2}, 7.7146e-15, 0, {0.000000159}}}, {"test_data/srs_estimator_test_input48.dat"}}, - {{{{1, 548, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 4, 821, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 36, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.531463, -0.466419), cf_t(0.569452, -0.419196)}}, 1, 2}, -4.8216e-16, 0, {0.000000066}}}, {"test_data/srs_estimator_test_input49.dat"}}, + {{{{1, 624, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 0, 44, 323, 0, srs_resource_configuration::comb_size_enum(2), 0, 0, 28, 8, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.395344, -0.586262), cf_t(-0.693555, -0.137772), cf_t(-0.478297, -0.520799), cf_t(0.469935, 0.528357), cf_t(-0.119723, -0.696898), cf_t(0.548168, 0.446668), cf_t(0.495266, 0.504690), cf_t(0.575711, 0.410557)}}, 4, 2}, 0, 0, {-0.000000186}}}, {"test_data/srs_estimator_test_input40.dat"}}, + {{{{1, 325, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(1), 4, 57, 222, 2, srs_resource_configuration::comb_size_enum(4), 2, 2, 5, 2, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.605906, -0.364524), cf_t(-0.661004, -0.251145), cf_t(0.355334, 0.611341), cf_t(0.705076, -0.053553), cf_t(-0.189947, -0.681117), cf_t(-0.274407, 0.651691), cf_t(-0.507800, -0.492076), cf_t(0.338968, 0.620565)}}, 4, 2}, 0, 0, {-0.000000126}}}, {"test_data/srs_estimator_test_input41.dat"}}, + {{{{1, 700, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 43, 1006, 1, srs_resource_configuration::comb_size_enum(2), 1, 7, 22, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.215231, 0.673555), cf_t(-0.675969, 0.207525)}}, 1, 2}, 0, 0, {-0.000000040}}}, {"test_data/srs_estimator_test_input42.dat"}}, + {{{{1, 760, 3, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 5, 1, 439, 1, srs_resource_configuration::comb_size_enum(4), 1, 11, 63, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.682496, 0.184930), cf_t(0.042278, 0.705842)}}, 1, 2}, 0, 0, {0.000000137}}}, {"test_data/srs_estimator_test_input43.dat"}}, + {{{{1, 761, 7, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 1, 13, 697, 0, srs_resource_configuration::comb_size_enum(2), 1, 1, 45, 5, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.557057, -0.435531), cf_t(-0.207059, -0.676111), cf_t(-0.703283, -0.073434), cf_t(0.402617, 0.581291)}}, 2, 2}, 0, 0, {0.000000236}}}, {"test_data/srs_estimator_test_input44.dat"}}, + {{{{1, 37, 5, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 10, 33, 766, 1, srs_resource_configuration::comb_size_enum(4), 2, 4, 12, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.023928, 0.706702), cf_t(0.627344, -0.326251), cf_t(0.701229, 0.090985), cf_t(-0.402217, -0.581568)}}, 2, 2}, 0, 0, {0.000000225}}}, {"test_data/srs_estimator_test_input45.dat"}}, + {{{{1, 813, 1, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 7, 32, 450, 2, srs_resource_configuration::comb_size_enum(2), 1, 0, 58, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.480184, -0.519060), cf_t(0.706981, -0.013313), cf_t(-0.406768, -0.578394), cf_t(-0.536953, 0.460089), cf_t(-0.433649, 0.558523), cf_t(0.114250, 0.697816), cf_t(-0.558749, -0.433358), cf_t(0.443197, 0.550978)}}, 4, 2}, 0, 0, {-0.000000247}}}, {"test_data/srs_estimator_test_input46.dat"}}, + {{{{1, 743, 4, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(2), 4, 36, 861, 0, srs_resource_configuration::comb_size_enum(4), 3, 11, 15, 8, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.495468, 0.504492), cf_t(-0.450328, -0.545165), cf_t(0.678967, 0.197495), cf_t(-0.406363, 0.578678), cf_t(0.602907, 0.369464), cf_t(0.298589, 0.640971), cf_t(-0.118624, -0.697086), cf_t(-0.376570, -0.598494)}}, 4, 2}, 0, 0, {-0.000000060}}}, {"test_data/srs_estimator_test_input47.dat"}}, + {{{{1, 932, 6, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 8, 24, 763, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 16, 8, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.674713, 0.211572), cf_t(0.098696, 0.700185)}}, 1, 2}, 0, 0, {0.000000159}}}, {"test_data/srs_estimator_test_input48.dat"}}, + {{{{1, 548, 9, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 4, 821, 3, srs_resource_configuration::comb_size_enum(4), 0, 9, 36, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.531463, -0.466419), cf_t(0.569452, -0.419196)}}, 1, 2}, 0, 0, {0.000000066}}}, {"test_data/srs_estimator_test_input49.dat"}}, {{{{1, 186, 1, 0}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 49, 109, 1, srs_resource_configuration::comb_size_enum(2), 1, 3, 46, 10, 1, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.696311, -0.123090), cf_t(-0.565094, -0.425052), cf_t(-0.600794, 0.372890), cf_t(0.002311, -0.707103)}}, 2, 2}, 0, 0, {0.000000044}}}, {"test_data/srs_estimator_test_input50.dat"}}, - {{{{1, 524, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 22, 736, 3, srs_resource_configuration::comb_size_enum(4), 1, 5, 28, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.142382, 0.692623), cf_t(-0.255814, 0.659211), cf_t(0.497939, 0.502052), cf_t(-0.105767, -0.699152)}}, 2, 2}, 9.6433e-16, 0, {0.000000147}}}, {"test_data/srs_estimator_test_input51.dat"}}, + {{{{1, 524, 5, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 0, 22, 736, 3, srs_resource_configuration::comb_size_enum(4), 1, 5, 28, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.142382, 0.692623), cf_t(-0.255814, 0.659211), cf_t(0.497939, 0.502052), cf_t(-0.105767, -0.699152)}}, 2, 2}, 0, 0, {0.000000147}}}, {"test_data/srs_estimator_test_input51.dat"}}, {{{{1, 863, 6, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 10, 24, 789, 2, srs_resource_configuration::comb_size_enum(2), 1, 3, 45, 0, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.700048, 0.099667), cf_t(0.060151, 0.704544), cf_t(0.339262, -0.620404), cf_t(0.648026, -0.282952), cf_t(-0.504016, -0.495951), cf_t(0.312584, 0.634264), cf_t(0.075039, -0.703114), cf_t(0.550766, 0.443460)}}, 4, 2}, 0, 0, {-0.000000166}}}, {"test_data/srs_estimator_test_input52.dat"}}, {{{{1, 197, 0, 1}, {srs_resource_configuration::one_two_four_enum(2), srs_resource_configuration::one_two_four_enum(4), 9, 35, 101, 3, srs_resource_configuration::comb_size_enum(4), 1, 4, 14, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.705669, -0.045076), cf_t(-0.487522, -0.512174), cf_t(-0.547248, 0.447794), cf_t(-0.707084, -0.005700), cf_t(0.588220, -0.392425), cf_t(0.568029, 0.421121), cf_t(0.665878, 0.237921), cf_t(-0.643028, 0.294135)}}, 4, 2}, 0, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input53.dat"}}, - {{{{1, 915, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 62, 399, 2, srs_resource_configuration::comb_size_enum(2), 0, 4, 51, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.606136, 0.364142), cf_t(-0.706289, 0.033997), cf_t(-0.240597, -0.664916), cf_t(0.696755, -0.120548)}}, 1, 4}, -4.8216e-16, 0, {-0.000000090}}}, {"test_data/srs_estimator_test_input54.dat"}}, - {{{{1, 977, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 18, 365, 0, srs_resource_configuration::comb_size_enum(4), 2, 7, 44, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.675776, 0.208150), cf_t(-0.411247, 0.575218), cf_t(-0.674315, 0.212836), cf_t(0.040386, 0.705953)}}, 1, 4}, 6.7503e-15, 0, {0.000000112}}}, {"test_data/srs_estimator_test_input55.dat"}}, - {{{{1, 748, 8, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 37, 856, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 59, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.426838, 0.563746), cf_t(0.696925, -0.119566), cf_t(-0.671730, 0.220858), cf_t(0.263577, 0.656146), cf_t(0.688624, -0.160616), cf_t(-0.351807, -0.613378), cf_t(0.682282, 0.185720), cf_t(-0.605356, -0.365437)}}, 2, 4}, -3.3751e-15, 0, {0.000000091}}}, {"test_data/srs_estimator_test_input56.dat"}}, - {{{{1, 830, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 41, 85, 0, srs_resource_configuration::comb_size_enum(4), 1, 3, 17, 10, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.245448, 0.435609), cf_t(0.373291, -0.332647), cf_t(0.288186, 0.408594), cf_t(0.414810, 0.279164), cf_t(-0.288806, 0.408156), cf_t(0.452468, -0.212774), cf_t(0.360898, 0.346053), cf_t(-0.402691, 0.296378)}}, 2, 4}, -2.893e-15, 0, {-0.000000236}}}, {"test_data/srs_estimator_test_input57.dat"}}, - {{{{1, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 7, 37, 702, 0, srs_resource_configuration::comb_size_enum(2), 1, 3, 36, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.497714, -0.047754), cf_t(-0.491508, 0.091762), cf_t(-0.499851, -0.012213), cf_t(-0.494123, 0.076439), cf_t(-0.106992, -0.488419), cf_t(-0.464059, -0.186144), cf_t(-0.301942, -0.398536), cf_t(-0.324627, 0.380286), cf_t(0.265175, -0.423890), cf_t(-0.059834, 0.496407), cf_t(-0.177459, 0.467449), cf_t(0.118596, -0.485731), cf_t(-0.456680, 0.203577), cf_t(-0.003084, -0.499990), cf_t(0.321789, 0.382690), cf_t(0.094603, -0.490969)}}, 4, 4}, -1.9287e-15, 0, {0.000000088}}}, {"test_data/srs_estimator_test_input58.dat"}}, + {{{{1, 915, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 62, 399, 2, srs_resource_configuration::comb_size_enum(2), 0, 4, 51, 6, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.606136, 0.364142), cf_t(-0.706289, 0.033997), cf_t(-0.240597, -0.664916), cf_t(0.696755, -0.120548)}}, 1, 4}, 0, 0, {-0.000000090}}}, {"test_data/srs_estimator_test_input54.dat"}}, + {{{{1, 977, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 18, 365, 0, srs_resource_configuration::comb_size_enum(4), 2, 7, 44, 7, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.675776, 0.208150), cf_t(-0.411247, 0.575218), cf_t(-0.674315, 0.212836), cf_t(0.040386, 0.705953)}}, 1, 4}, 0, 0, {0.000000112}}}, {"test_data/srs_estimator_test_input55.dat"}}, + {{{{1, 748, 8, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 1, 37, 856, 1, srs_resource_configuration::comb_size_enum(2), 1, 5, 59, 1, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.426838, 0.563746), cf_t(0.696925, -0.119566), cf_t(-0.671730, 0.220858), cf_t(0.263577, 0.656146), cf_t(0.688624, -0.160616), cf_t(-0.351807, -0.613378), cf_t(0.682282, 0.185720), cf_t(-0.605356, -0.365437)}}, 2, 4}, 0, 0, {0.000000091}}}, {"test_data/srs_estimator_test_input56.dat"}}, + {{{{1, 830, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 0, 41, 85, 0, srs_resource_configuration::comb_size_enum(4), 1, 3, 17, 10, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.245448, 0.435609), cf_t(0.373291, -0.332647), cf_t(0.288186, 0.408594), cf_t(0.414810, 0.279164), cf_t(-0.288806, 0.408156), cf_t(0.452468, -0.212774), cf_t(0.360898, 0.346053), cf_t(-0.402691, 0.296378)}}, 2, 4}, 0, 0, {-0.000000236}}}, {"test_data/srs_estimator_test_input57.dat"}}, + {{{{1, 813, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 7, 37, 702, 0, srs_resource_configuration::comb_size_enum(2), 1, 3, 36, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.497714, -0.047754), cf_t(-0.491508, 0.091762), cf_t(-0.499851, -0.012213), cf_t(-0.494123, 0.076439), cf_t(-0.106992, -0.488419), cf_t(-0.464059, -0.186144), cf_t(-0.301942, -0.398536), cf_t(-0.324627, 0.380286), cf_t(0.265175, -0.423890), cf_t(-0.059834, 0.496407), cf_t(-0.177459, 0.467449), cf_t(0.118596, -0.485731), cf_t(-0.456680, 0.203577), cf_t(-0.003084, -0.499990), cf_t(0.321789, 0.382690), cf_t(0.094603, -0.490969)}}, 4, 4}, 0, 0, {0.000000088}}}, {"test_data/srs_estimator_test_input58.dat"}}, {{{{1, 573, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(1), 4, 18, 961, 3, srs_resource_configuration::comb_size_enum(4), 3, 10, 64, 10, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.673645, -0.214948), cf_t(-0.667576, 0.233113), cf_t(0.652659, -0.272097), cf_t(-0.589330, -0.390756), cf_t(-0.095730, -0.700597), cf_t(-0.428806, -0.562251), cf_t(0.338831, -0.620640), cf_t(0.492252, -0.507629), cf_t(-0.626452, -0.327960), cf_t(-0.700841, -0.093924), cf_t(0.412333, -0.574440), cf_t(0.646278, -0.286923), cf_t(0.697795, 0.114377), cf_t(-0.491487, 0.508371), cf_t(-0.492194, 0.507686), cf_t(-0.346614, -0.616327)}}, 4, 4}, 0, 0, {-0.000000153}}}, {"test_data/srs_estimator_test_input59.dat"}}, {{{{1, 416, 6, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 8, 18, 956, 2, srs_resource_configuration::comb_size_enum(2), 1, 4, 18, 9, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.147002, -0.691658), cf_t(-0.147238, 0.691608), cf_t(0.561973, -0.429170), cf_t(0.327254, -0.626821)}}, 1, 4}, 0, 0, {-0.000000057}}}, {"test_data/srs_estimator_test_input60.dat"}}, - {{{{1, 854, 4, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 29, 588, 2, srs_resource_configuration::comb_size_enum(4), 3, 0, 45, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.463143, 0.188410), cf_t(-0.462324, 0.190412), cf_t(0.370793, 0.335429), cf_t(0.197656, -0.459274)}}, 1, 4}, -3.3751e-15, 0, {-0.000000091}}}, {"test_data/srs_estimator_test_input61.dat"}}, - {{{{1, 384, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 8, 575, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 9, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.498654, 0.036664), cf_t(-0.339651, -0.366929), cf_t(-0.484366, -0.124056), cf_t(0.317064, -0.386614), cf_t(0.412881, 0.282009), cf_t(0.493456, -0.080631), cf_t(0.302679, 0.397976), cf_t(-0.451286, -0.215270)}}, 2, 4}, 9.6433e-16, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input62.dat"}}, - {{{{1, 338, 5, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 56, 503, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 41, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.209018, -0.454215), cf_t(-0.026949, 0.499273), cf_t(0.377610, -0.327736), cf_t(0.400531, -0.299291), cf_t(0.453889, -0.209725), cf_t(-0.416411, -0.276770), cf_t(0.181768, 0.465790), cf_t(-0.499854, -0.012063)}}, 2, 4}, -1.9287e-15, 0, {0.000000059}}}, {"test_data/srs_estimator_test_input63.dat"}}, + {{{{1, 854, 4, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 29, 588, 2, srs_resource_configuration::comb_size_enum(4), 3, 0, 45, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.463143, 0.188410), cf_t(-0.462324, 0.190412), cf_t(0.370793, 0.335429), cf_t(0.197656, -0.459274)}}, 1, 4}, 0, 0, {-0.000000091}}}, {"test_data/srs_estimator_test_input61.dat"}}, + {{{{1, 384, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 7, 8, 575, 0, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 9, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.498654, 0.036664), cf_t(-0.339651, -0.366929), cf_t(-0.484366, -0.124056), cf_t(0.317064, -0.386614), cf_t(0.412881, 0.282009), cf_t(0.493456, -0.080631), cf_t(0.302679, 0.397976), cf_t(-0.451286, -0.215270)}}, 2, 4}, 0, 0, {0.000000259}}}, {"test_data/srs_estimator_test_input62.dat"}}, + {{{{1, 338, 5, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 56, 503, 0, srs_resource_configuration::comb_size_enum(4), 1, 4, 41, 0, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(0.209018, -0.454215), cf_t(-0.026949, 0.499273), cf_t(0.377610, -0.327736), cf_t(0.400531, -0.299291), cf_t(0.453889, -0.209725), cf_t(-0.416411, -0.276770), cf_t(0.181768, 0.465790), cf_t(-0.499854, -0.012063)}}, 2, 4}, 0, 0, {0.000000059}}}, {"test_data/srs_estimator_test_input63.dat"}}, {{{{1, 206, 8, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 5, 39, 438, 2, srs_resource_configuration::comb_size_enum(2), 1, 6, 37, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.391941, 0.588542), cf_t(0.364793, -0.605744), cf_t(-0.534472, 0.462968), cf_t(-0.244731, -0.663405), cf_t(-0.654034, -0.268775), cf_t(-0.082507, -0.702277), cf_t(0.113049, -0.698011), cf_t(0.665624, -0.238631), cf_t(-0.240346, -0.665007), cf_t(-0.450833, 0.544747), cf_t(-0.069768, -0.703656), cf_t(0.150921, -0.690813), cf_t(-0.632946, 0.315244), cf_t(-0.678046, 0.200634), cf_t(-0.640334, 0.299954), cf_t(-0.194835, -0.679735)}}, 4, 4}, 0, 0, {-0.000000203}}}, {"test_data/srs_estimator_test_input64.dat"}}, {{{{1, 470, 3, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(2), 0, 1, 234, 3, srs_resource_configuration::comb_size_enum(4), 0, 6, 14, 9, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.636720, -0.307551), cf_t(0.663822, 0.243600), cf_t(-0.649260, 0.280110), cf_t(0.463834, -0.533720), cf_t(0.508752, 0.491092), cf_t(0.663258, 0.245129), cf_t(0.349267, -0.614827), cf_t(0.578013, 0.407309), cf_t(-0.336102, -0.622122), cf_t(0.406588, 0.578521), cf_t(-0.523326, -0.475531), cf_t(0.592348, -0.386165), cf_t(-0.573142, -0.414136), cf_t(0.701740, 0.086953), cf_t(-0.701459, -0.089194), cf_t(0.550409, 0.443903)}}, 4, 4}, 0, 0, {0.000000009}}}, {"test_data/srs_estimator_test_input65.dat"}}, {{{{1, 4, 1, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 8, 63, 869, 2, srs_resource_configuration::comb_size_enum(2), 0, 6, 39, 10, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(0.057193, -0.704790), cf_t(0.613194, 0.352126), cf_t(-0.372880, -0.600800), cf_t(-0.703087, -0.075293)}}, 1, 4}, 0, 0, {-0.000000171}}}, {"test_data/srs_estimator_test_input66.dat"}}, - {{{{1, 451, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 10, 53, 671, 2, srs_resource_configuration::comb_size_enum(4), 2, 4, 16, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.439773, -0.237908), cf_t(0.335080, -0.371109), cf_t(-0.416652, 0.276408), cf_t(0.379968, 0.324999)}}, 1, 4}, -5.3038e-15, 0, {-0.000000029}}}, {"test_data/srs_estimator_test_input67.dat"}}, - {{{{1, 853, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 4, 8, 399, 1, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 3, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.445301, 0.227391), cf_t(0.020184, 0.499592), cf_t(0.366185, 0.340454), cf_t(0.109286, -0.487910), cf_t(-0.499760, 0.015495), cf_t(0.446794, 0.224443), cf_t(-0.135245, -0.481361), cf_t(-0.392918, 0.309218)}}, 2, 4}, -4.8216e-16, 0, {-0.000000259}}}, {"test_data/srs_estimator_test_input68.dat"}}, - {{{{1, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 1, 8, 274, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 32, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.355792, 0.351300), cf_t(-0.460517, 0.194741), cf_t(-0.494429, -0.074430), cf_t(0.230200, 0.443856), cf_t(-0.046656, 0.497818), cf_t(0.493288, 0.081651), cf_t(0.454587, 0.208209), cf_t(0.479864, -0.140466)}}, 2, 4}, 9.6433e-16, 0, {-0.000000036}}}, {"test_data/srs_estimator_test_input69.dat"}}, - {{{{1, 7, 9, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 35, 722, 0, srs_resource_configuration::comb_size_enum(2), 1, 4, 60, 7, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.438208, -0.554954), cf_t(0.597494, -0.378154), cf_t(0.426561, -0.563955), cf_t(-0.692481, -0.143072), cf_t(-0.578349, 0.406832), cf_t(0.594874, -0.382264), cf_t(-0.661298, 0.250369), cf_t(-0.147752, -0.691498), cf_t(-0.293085, 0.643507), cf_t(-0.593204, -0.384849), cf_t(0.583220, -0.399818), cf_t(0.303875, 0.638482), cf_t(-0.548680, -0.446039), cf_t(-0.350618, 0.614058), cf_t(0.691797, 0.146347), cf_t(-0.365792, 0.605141)}}, 4, 4}, -4.8216e-16, 0, {-0.000000163}}}, {"test_data/srs_estimator_test_input70.dat"}}, - {{{{1, 561, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 15, 565, 0, srs_resource_configuration::comb_size_enum(4), 0, 11, 55, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.096280, -0.700521), cf_t(0.707087, 0.005324), cf_t(-0.681382, -0.188994), cf_t(0.051253, -0.705247), cf_t(0.317802, 0.631666), cf_t(-0.286603, 0.646420), cf_t(-0.655865, 0.264276), cf_t(0.055072, -0.704959), cf_t(-0.451996, 0.543783), cf_t(-0.220126, -0.671971), cf_t(-0.164757, 0.687645), cf_t(-0.627893, -0.325193), cf_t(0.265294, 0.655453), cf_t(-0.499198, -0.500801), cf_t(-0.707068, -0.007371), cf_t(-0.010383, -0.707031)}}, 4, 4}, 9.6433e-16, 0, {0.000000076}}}, {"test_data/srs_estimator_test_input71.dat"}}, + {{{{1, 451, 9, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 10, 53, 671, 2, srs_resource_configuration::comb_size_enum(4), 2, 4, 16, 4, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0}}, {{{{cf_t(-0.439773, -0.237908), cf_t(0.335080, -0.371109), cf_t(-0.416652, 0.276408), cf_t(0.379968, 0.324999)}}, 1, 4}, 0, 0, {-0.000000029}}}, {"test_data/srs_estimator_test_input67.dat"}}, + {{{{1, 853, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 4, 8, 399, 1, srs_resource_configuration::comb_size_enum(2), 0, 3, 20, 3, 2, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.445301, 0.227391), cf_t(0.020184, 0.499592), cf_t(0.366185, 0.340454), cf_t(0.109286, -0.487910), cf_t(-0.499760, 0.015495), cf_t(0.446794, 0.224443), cf_t(-0.135245, -0.481361), cf_t(-0.392918, 0.309218)}}, 2, 4}, 0, 0, {-0.000000259}}}, {"test_data/srs_estimator_test_input68.dat"}}, + {{{{1, 193, 2, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 1, 8, 274, 2, srs_resource_configuration::comb_size_enum(4), 3, 2, 32, 1, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1}}, {{{{cf_t(-0.355792, 0.351300), cf_t(-0.460517, 0.194741), cf_t(-0.494429, -0.074430), cf_t(0.230200, 0.443856), cf_t(-0.046656, 0.497818), cf_t(0.493288, 0.081651), cf_t(0.454587, 0.208209), cf_t(0.479864, -0.140466)}}, 2, 4}, 0, 0, {-0.000000036}}}, {"test_data/srs_estimator_test_input69.dat"}}, + {{{{1, 7, 9, 1}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 7, 35, 722, 0, srs_resource_configuration::comb_size_enum(2), 1, 4, 60, 7, 0, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(0.438208, -0.554954), cf_t(0.597494, -0.378154), cf_t(0.426561, -0.563955), cf_t(-0.692481, -0.143072), cf_t(-0.578349, 0.406832), cf_t(0.594874, -0.382264), cf_t(-0.661298, 0.250369), cf_t(-0.147752, -0.691498), cf_t(-0.293085, 0.643507), cf_t(-0.593204, -0.384849), cf_t(0.583220, -0.399818), cf_t(0.303875, 0.638482), cf_t(-0.548680, -0.446039), cf_t(-0.350618, 0.614058), cf_t(0.691797, 0.146347), cf_t(-0.365792, 0.605141)}}, 4, 4}, 0, 0, {-0.000000163}}}, {"test_data/srs_estimator_test_input70.dat"}}, + {{{{1, 561, 3, 0}, {srs_resource_configuration::one_two_four_enum(4), srs_resource_configuration::one_two_four_enum(4), 0, 15, 565, 0, srs_resource_configuration::comb_size_enum(4), 0, 11, 55, 3, 3, srs_resource_configuration::group_or_sequence_hopping_enum::neither, {}}, {0, 1, 2, 3}}, {{{{cf_t(-0.096280, -0.700521), cf_t(0.707087, 0.005324), cf_t(-0.681382, -0.188994), cf_t(0.051253, -0.705247), cf_t(0.317802, 0.631666), cf_t(-0.286603, 0.646420), cf_t(-0.655865, 0.264276), cf_t(0.055072, -0.704959), cf_t(-0.451996, 0.543783), cf_t(-0.220126, -0.671971), cf_t(-0.164757, 0.687645), cf_t(-0.627893, -0.325193), cf_t(0.265294, 0.655453), cf_t(-0.499198, -0.500801), cf_t(-0.707068, -0.007371), cf_t(-0.010383, -0.707031)}}, 4, 4}, 0, 0, {0.000000076}}}, {"test_data/srs_estimator_test_input71.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz index 476fbe56a7..09d8956c9c 100644 --- a/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz +++ b/tests/unittests/phy/upper/signal_processors/srs/srs_estimator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f2f48e56d05ff2ade31310b4fb58d1c1be7b04eb576802be265b45ae24f1cd7 -size 643092 +oid sha256:baacf9243bd59dc252c3b851d23e2d22be3cb9ccaaad4d4f098798e840bd2afd +size 643093 From b3c6d79de43828fb88859f1b46edeff13e42a1d7 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Tue, 5 Nov 2024 12:56:32 +0100 Subject: [PATCH 47/72] services: added HAL folder to services to extract the common parsing of the HAL section. Extracted the E2 application configuration and E2 CLI11 schema to the E2 service folder. --- apps/cu/cu_appconfig_validator.cpp | 6 +++ apps/du/du_appconfig.h | 3 +- apps/du/du_appconfig_cli11_schema.cpp | 47 +++++++------------ apps/du/du_appconfig_cli11_schema.h | 2 +- apps/du/du_appconfig_translators.cpp | 30 ------------ apps/du/du_appconfig_translators.h | 7 --- apps/du/du_appconfig_validators.cpp | 6 +++ apps/gnb/gnb_appconfig.h | 7 +-- apps/gnb/gnb_appconfig_cli11_schema.cpp | 41 +++------------- apps/gnb/gnb_appconfig_translators.cpp | 31 ------------ apps/gnb/gnb_appconfig_translators.h | 19 -------- apps/services/CMakeLists.txt | 8 +++- apps/services/e2/CMakeLists.txt | 14 ++++++ apps/services/e2/e2_appconfig_translators.cpp | 43 +++++++++++++++++ apps/services/e2/e2_appconfig_translators.h | 22 +++++++++ apps/services/e2/e2_cli11_schema.cpp | 41 ++++++++++++++++ apps/services/e2/e2_cli11_schema.h | 22 +++++++++ apps/services/hal/CMakeLists.txt | 13 +++++ apps/services/hal/hal_appconfig.h | 23 +++++++++ apps/services/hal/hal_cli11_schema.cpp | 32 +++++++++++++ apps/services/hal/hal_cli11_schema.h | 25 ++++++++++ apps/services/worker_manager/CMakeLists.txt | 6 +-- include/srsran/support/cli11_utils.h | 1 + 23 files changed, 283 insertions(+), 166 deletions(-) create mode 100644 apps/services/e2/CMakeLists.txt create mode 100644 apps/services/e2/e2_appconfig_translators.cpp create mode 100644 apps/services/e2/e2_appconfig_translators.h create mode 100644 apps/services/e2/e2_cli11_schema.cpp create mode 100644 apps/services/e2/e2_cli11_schema.h create mode 100644 apps/services/hal/CMakeLists.txt create mode 100644 apps/services/hal/hal_appconfig.h create mode 100644 apps/services/hal/hal_cli11_schema.cpp create mode 100644 apps/services/hal/hal_cli11_schema.h diff --git a/apps/cu/cu_appconfig_validator.cpp b/apps/cu/cu_appconfig_validator.cpp index 407a0615f3..8a95e85565 100644 --- a/apps/cu/cu_appconfig_validator.cpp +++ b/apps/cu/cu_appconfig_validator.cpp @@ -16,5 +16,11 @@ using namespace srsran; bool srsran::validate_cu_appconfig(const cu_appconfig& config) { + if (config.e2_cfg.enable_du_e2) { + fmt::print("CU application cannot enable DU E2 agent\n"); + + return false; + } + return validate_logger_appconfig(config.log_cfg); } diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index 5f2e36872b..6965bfdc38 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -10,8 +10,9 @@ #pragma once -#include "../gnb/gnb_appconfig.h" // TODO: Remove #include "apps/services/buffer_pool/buffer_pool_appconfig.h" +#include "apps/services/e2/e2_appconfig.h" +#include "apps/services/hal/hal_appconfig.h" #include "apps/services/logger/logger_appconfig.h" #include "apps/services/worker_manager/worker_manager_appconfig.h" #include diff --git a/apps/du/du_appconfig_cli11_schema.cpp b/apps/du/du_appconfig_cli11_schema.cpp index d6664c9ee0..b7de6ce1b9 100644 --- a/apps/du/du_appconfig_cli11_schema.cpp +++ b/apps/du/du_appconfig_cli11_schema.cpp @@ -10,6 +10,8 @@ #include "du_appconfig_cli11_schema.h" #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" +#include "apps/services/e2/e2_cli11_schema.h" +#include "apps/services/hal/hal_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" #include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "du_appconfig.h" @@ -26,25 +28,6 @@ static void configure_cli11_metrics_args(CLI::App& app, srs_du::metrics_appconfi ->check(CLI::Range(0, 65535)); } -static void configure_cli11_e2_args(CLI::App& app, e2_appconfig& e2_params) -{ - add_option(app, "--enable_du_e2", e2_params.enable_du_e2, "Enable DU E2 agent")->capture_default_str(); - add_option(app, "--addr", e2_params.ip_addr, "RIC IP address")->capture_default_str(); - add_option(app, "--port", e2_params.port, "RIC port")->capture_default_str()->check(CLI::Range(20000, 40000)); - add_option(app, "--bind_addr", e2_params.bind_addr, "Local IP address to bind for RIC connection") - ->capture_default_str() - ->check(CLI::ValidIPV4); - add_option(app, "--sctp_rto_initial", e2_params.sctp_rto_initial, "SCTP initial RTO value")->capture_default_str(); - add_option(app, "--sctp_rto_min", e2_params.sctp_rto_min, "SCTP RTO min")->capture_default_str(); - add_option(app, "--sctp_rto_max", e2_params.sctp_rto_max, "SCTP RTO max")->capture_default_str(); - add_option(app, "--sctp_init_max_attempts", e2_params.sctp_init_max_attempts, "SCTP init max attempts") - ->capture_default_str(); - add_option(app, "--sctp_max_init_timeo", e2_params.sctp_max_init_timeo, "SCTP max init timeout") - ->capture_default_str(); - add_option(app, "--e2sm_kpm_enabled", e2_params.e2sm_kpm_enabled, "Enable KPM service module")->capture_default_str(); - add_option(app, "--e2sm_rc_enabled", e2_params.e2sm_rc_enabled, "Enable RC service module")->capture_default_str(); -} - static void configure_cli11_f1ap_args(CLI::App& app, srs_du::f1ap_appconfig& f1c_params) { app.add_option("--cu_cp_addr", f1c_params.cu_cp_address, "CU-CP F1-C address to connect to")->capture_default_str(); @@ -67,13 +50,6 @@ static void configure_cli11_f1u_args(CLI::App& app, srs_du::nru_appconfig& f1u_p ->capture_default_str(); } -static void configure_cli11_hal_args(CLI::App& app, std::optional& config) -{ - config.emplace(); - - add_option(app, "--eal_args", config->eal_args, "EAL configuration parameters used to initialize DPDK"); -} - void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfig& du_cfg) { add_option(app, "--du_multicell_enabled", du_cfg.du_multicell_enabled, "DU multicell enabled flag") @@ -101,12 +77,21 @@ void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfi configure_cli11_metrics_args(*metrics_subcmd, du_cfg.metrics_cfg); // E2 section. - CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); - configure_cli11_e2_args(*e2_subcmd, du_cfg.e2_cfg); + configure_cli11_with_e2_appconfig_schema(app, du_cfg.e2_cfg); // HAL section. - CLI::App* hal_subcmd = add_subcommand(app, "hal", "HAL configuration")->configurable(); - configure_cli11_hal_args(*hal_subcmd, du_cfg.hal_config); + du_cfg.hal_config.emplace(); + configure_cli11_with_hal_appconfig_schema(app, *du_cfg.hal_config); } -void srsran::autoderive_du_parameters_after_parsing(CLI::App& app, du_appconfig& parsed_cfg) {} +static void manage_hal_optional(CLI::App& app, du_appconfig& du_cfg) +{ + if (!is_hal_section_present(app)) { + du_cfg.hal_config.reset(); + } +} + +void srsran::autoderive_du_parameters_after_parsing(CLI::App& app, du_appconfig& du_cfg) +{ + manage_hal_optional(app, du_cfg); +} diff --git a/apps/du/du_appconfig_cli11_schema.h b/apps/du/du_appconfig_cli11_schema.h index 59b9773bd5..35463ea362 100644 --- a/apps/du/du_appconfig_cli11_schema.h +++ b/apps/du/du_appconfig_cli11_schema.h @@ -20,6 +20,6 @@ struct du_appconfig; void configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfig& parsed_cfg); /// Auto derive DU parameters after the parsing. -void autoderive_du_parameters_after_parsing(CLI::App& app, du_appconfig& parsed_cfg); +void autoderive_du_parameters_after_parsing(CLI::App& app, du_appconfig& du_cfg); } // namespace srsran diff --git a/apps/du/du_appconfig_translators.cpp b/apps/du/du_appconfig_translators.cpp index 94bbf83c91..8fbb7396d2 100644 --- a/apps/du/du_appconfig_translators.cpp +++ b/apps/du/du_appconfig_translators.cpp @@ -15,36 +15,6 @@ using namespace srsran; using namespace std::chrono_literals; -// TODO: refactor. -srsran::sctp_network_connector_config srsran::generate_e2ap_nw_config(const e2_appconfig& config, int ppid) -{ - srsran::sctp_network_connector_config out_cfg; - out_cfg.dest_name = "NearRT-RIC"; - out_cfg.if_name = "E2"; - out_cfg.connect_address = config.ip_addr; - out_cfg.connect_port = config.port; - out_cfg.bind_address = config.bind_addr; - out_cfg.ppid = ppid; - - if (config.sctp_rto_initial >= 0) { - out_cfg.rto_initial = config.sctp_rto_initial; - } - if (config.sctp_rto_min >= 0) { - out_cfg.rto_min = config.sctp_rto_min; - } - if (config.sctp_rto_max >= 0) { - out_cfg.rto_max = config.sctp_rto_max; - } - if (config.sctp_init_max_attempts >= 0) { - out_cfg.init_max_attempts = config.sctp_init_max_attempts; - } - if (config.sctp_max_init_timeo >= 0) { - out_cfg.max_init_timeo = config.sctp_max_init_timeo; - } - - return out_cfg; -} - void srsran::fill_du_worker_manager_config(worker_manager_config& config, const du_appconfig& unit_cfg) { srsran_assert(config.du_hi_cfg, "DU high worker config does not exist"); diff --git a/apps/du/du_appconfig_translators.h b/apps/du/du_appconfig_translators.h index 299534b252..3bfbac9061 100644 --- a/apps/du/du_appconfig_translators.h +++ b/apps/du/du_appconfig_translators.h @@ -10,17 +10,10 @@ #pragma once -#include "srsran/e2/e2ap_configuration.h" -#include "srsran/gateways/sctp_network_gateway.h" - namespace srsran { struct du_appconfig; struct worker_manager_config; -struct e2_appconfig; - -/// Converts and returns the given gnb application configuration to a E2AP Network Gateway configuration. -sctp_network_connector_config generate_e2ap_nw_config(const e2_appconfig& config, int ppid); /// Fills the DU worker manager parameters of the given worker manager configuration. void fill_du_worker_manager_config(worker_manager_config& config, const du_appconfig& unit_cfg); diff --git a/apps/du/du_appconfig_validators.cpp b/apps/du/du_appconfig_validators.cpp index cb832b370c..7f217dc950 100644 --- a/apps/du/du_appconfig_validators.cpp +++ b/apps/du/du_appconfig_validators.cpp @@ -24,5 +24,11 @@ bool srsran::validate_appconfig(const du_appconfig& config) return false; } + if (config.e2_cfg.enable_cu_e2) { + fmt::print("DU application cannot enable CU E2 agent\n"); + + return false; + } + return true; } diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index ba309402a2..9c853d3b63 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -12,6 +12,7 @@ #include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/e2/e2_appconfig.h" +#include "apps/services/hal/hal_appconfig.h" #include "apps/services/logger/logger_appconfig.h" #include "apps/services/worker_manager/worker_manager_appconfig.h" #include "srsran/ran/gnb_id.h" @@ -31,12 +32,6 @@ struct metrics_appconfig { uint16_t port = 55555; }; -/// HAL configuration of the gNB app. -struct hal_appconfig { - /// EAL configuration arguments. - std::string eal_args; -}; - /// Monolithic gnb application configuration. struct gnb_appconfig { /// Default constructor to update the log filename. diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 5c19676956..8332255405 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -10,6 +10,8 @@ #include "gnb_appconfig_cli11_schema.h" #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" +#include "apps/services/e2/e2_cli11_schema.h" +#include "apps/services/hal/hal_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" #include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "gnb_appconfig.h" @@ -26,40 +28,10 @@ static void configure_cli11_metrics_args(CLI::App& app, metrics_appconfig& metri ->check(CLI::Range(0, 65535)); } -static void configure_cli11_e2_args(CLI::App& app, e2_appconfig& e2_params) -{ - add_option(app, "--enable_du_e2", e2_params.enable_du_e2, "Enable DU E2 agent")->capture_default_str(); - add_option(app, "--enable_cu_e2", e2_params.enable_cu_e2, "Enable CU E2 agent")->capture_default_str(); - add_option(app, "--addr", e2_params.ip_addr, "RIC IP address")->capture_default_str(); - add_option(app, "--port", e2_params.port, "RIC port")->check(CLI::Range(20000, 40000))->capture_default_str(); - add_option(app, "--bind_addr", e2_params.bind_addr, "Local IP address to bind for RIC connection") - ->capture_default_str() - ->check(CLI::ValidIPV4); - add_option(app, "--sctp_rto_initial", e2_params.sctp_rto_initial, "SCTP initial RTO value")->capture_default_str(); - add_option(app, "--sctp_rto_min", e2_params.sctp_rto_min, "SCTP RTO min")->capture_default_str(); - add_option(app, "--sctp_rto_max", e2_params.sctp_rto_max, "SCTP RTO max")->capture_default_str(); - add_option(app, "--sctp_init_max_attempts", e2_params.sctp_init_max_attempts, "SCTP init max attempts") - ->capture_default_str(); - add_option(app, "--sctp_max_init_timeo", e2_params.sctp_max_init_timeo, "SCTP max init timeout") - ->capture_default_str(); - add_option(app, "--e2sm_kpm_enabled", e2_params.e2sm_kpm_enabled, "Enable KPM service module")->capture_default_str(); - add_option(app, "--e2sm_rc_enabled", e2_params.e2sm_rc_enabled, "Enable RC service module")->capture_default_str(); -} - -static void configure_cli11_hal_args(CLI::App& app, std::optional& config) -{ - config.emplace(); - - add_option(app, "--eal_args", config->eal_args, "EAL configuration parameters used to initialize DPDK"); -} - static void manage_hal_optional(CLI::App& app, gnb_appconfig& gnb_cfg) { - // Clean the HAL optional. - if (auto subcmd = app.get_subcommand("hal"); subcmd->count_all() == 0) { + if (!is_hal_section_present(app)) { gnb_cfg.hal_config.reset(); - // As HAL configuration is optional, disable the command when it is not present in the configuration. - subcmd->disabled(); } } @@ -89,12 +61,11 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon configure_cli11_metrics_args(*metrics_subcmd, gnb_cfg.metrics_cfg); // E2 section. - CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); - configure_cli11_e2_args(*e2_subcmd, gnb_cfg.e2_cfg); + configure_cli11_with_e2_appconfig_schema(app, gnb_cfg.e2_cfg); // HAL section. - CLI::App* hal_subcmd = add_subcommand(app, "hal", "HAL configuration")->configurable(); - configure_cli11_hal_args(*hal_subcmd, gnb_cfg.hal_config); + gnb_cfg.hal_config.emplace(); + configure_cli11_with_hal_appconfig_schema(app, *gnb_cfg.hal_config); } void srsran::autoderive_gnb_parameters_after_parsing(CLI::App& app, gnb_appconfig& config) diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index 1812d8b571..b2c9b48a13 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -10,42 +10,11 @@ #include "gnb_appconfig_translators.h" #include "apps/services/worker_manager/worker_manager_config.h" -#include "apps/units/cu_cp/cu_cp_unit_config.h" #include "gnb_appconfig.h" -#include "srsran/ran/subcarrier_spacing.h" using namespace srsran; using namespace std::chrono_literals; -srsran::sctp_network_connector_config srsran::generate_e2ap_nw_config(const e2_appconfig& config, int ppid) -{ - srsran::sctp_network_connector_config out_cfg; - out_cfg.dest_name = "NearRT-RIC"; - out_cfg.if_name = "E2"; - out_cfg.connect_address = config.ip_addr; - out_cfg.connect_port = config.port; - out_cfg.bind_address = config.bind_addr; - out_cfg.ppid = ppid; - - if (config.sctp_rto_initial >= 0) { - out_cfg.rto_initial = config.sctp_rto_initial; - } - if (config.sctp_rto_min >= 0) { - out_cfg.rto_min = config.sctp_rto_min; - } - if (config.sctp_rto_max >= 0) { - out_cfg.rto_max = config.sctp_rto_max; - } - if (config.sctp_init_max_attempts >= 0) { - out_cfg.init_max_attempts = config.sctp_init_max_attempts; - } - if (config.sctp_max_init_timeo >= 0) { - out_cfg.max_init_timeo = config.sctp_max_init_timeo; - } - - return out_cfg; -} - void srsran::fill_gnb_worker_manager_config(worker_manager_config& config, const gnb_appconfig& unit_cfg) { srsran_assert(config.cu_up_cfg, "CU-UP worker config does not exist"); diff --git a/apps/gnb/gnb_appconfig_translators.h b/apps/gnb/gnb_appconfig_translators.h index 7c3e440c59..5295016407 100644 --- a/apps/gnb/gnb_appconfig_translators.h +++ b/apps/gnb/gnb_appconfig_translators.h @@ -10,30 +10,11 @@ #pragma once -#include "apps/services/e2/e2_appconfig.h" -#include "srsran/cu_cp/cu_cp_configuration.h" -#include "srsran/gateways/sctp_network_gateway.h" - namespace srsran { struct gnb_appconfig; -struct cu_cp_unit_amf_config; -struct cu_cp_unit_config; -struct cu_up_unit_config; -struct du_high_unit_config; -struct du_high_unit_cell_config; -struct du_low_unit_config; -struct dynamic_du_unit_config; -struct mac_lc_appconfig; -struct rlc_am_appconfig; struct worker_manager_config; -/// Converts and returns the subcarrier spacing. -subcarrier_spacing generate_subcarrier_spacing(unsigned sc_spacing); - -/// Converts and returns the given gnb application configuration to a E2AP Network Gateway configuration. -srsran::sctp_network_connector_config generate_e2ap_nw_config(const e2_appconfig& config, int ppid); - /// Fills the gNB worker manager parameters of the given worker manager configuration. void fill_gnb_worker_manager_config(worker_manager_config& config, const gnb_appconfig& unit_cfg); diff --git a/apps/services/CMakeLists.txt b/apps/services/CMakeLists.txt index 98b5367f9f..db38a580b6 100644 --- a/apps/services/CMakeLists.txt +++ b/apps/services/CMakeLists.txt @@ -7,6 +7,8 @@ # add_subdirectory(buffer_pool) +add_subdirectory(e2) +add_subdirectory(hal) add_subdirectory(logger) add_subdirectory(worker_manager) @@ -16,6 +18,8 @@ set(SOURCES add_library(srsran_app_services STATIC ${SOURCES}) target_include_directories(srsran_app_services PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(srsran_app_services - srsran_logger_app_service srsran_buffer_pool_app_service - srsran_worker_manager_service) + srsran_e2_app_service + srsran_hal_app_service + srsran_logger_app_service + srsran_worker_manager_app_service) diff --git a/apps/services/e2/CMakeLists.txt b/apps/services/e2/CMakeLists.txt new file mode 100644 index 0000000000..16e83118a5 --- /dev/null +++ b/apps/services/e2/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +set(SOURCES + e2_appconfig_translators.cpp + e2_cli11_schema.cpp) + +add_library(srsran_e2_app_service STATIC ${SOURCES}) +target_include_directories(srsran_e2_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/e2/e2_appconfig_translators.cpp b/apps/services/e2/e2_appconfig_translators.cpp new file mode 100644 index 0000000000..c951235353 --- /dev/null +++ b/apps/services/e2/e2_appconfig_translators.cpp @@ -0,0 +1,43 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "e2_appconfig_translators.h" +#include "e2_appconfig.h" + +using namespace srsran; + +sctp_network_connector_config srsran::generate_e2ap_nw_config(const e2_appconfig& config, int ppid) +{ + sctp_network_connector_config out_cfg; + out_cfg.dest_name = "NearRT-RIC"; + out_cfg.if_name = "E2"; + out_cfg.connect_address = config.ip_addr; + out_cfg.connect_port = config.port; + out_cfg.bind_address = config.bind_addr; + out_cfg.ppid = ppid; + + if (config.sctp_rto_initial >= 0) { + out_cfg.rto_initial = config.sctp_rto_initial; + } + if (config.sctp_rto_min >= 0) { + out_cfg.rto_min = config.sctp_rto_min; + } + if (config.sctp_rto_max >= 0) { + out_cfg.rto_max = config.sctp_rto_max; + } + if (config.sctp_init_max_attempts >= 0) { + out_cfg.init_max_attempts = config.sctp_init_max_attempts; + } + if (config.sctp_max_init_timeo >= 0) { + out_cfg.max_init_timeo = config.sctp_max_init_timeo; + } + + return out_cfg; +} diff --git a/apps/services/e2/e2_appconfig_translators.h b/apps/services/e2/e2_appconfig_translators.h new file mode 100644 index 0000000000..4f41ed4c58 --- /dev/null +++ b/apps/services/e2/e2_appconfig_translators.h @@ -0,0 +1,22 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "srsran/gateways/sctp_network_gateway.h" + +namespace srsran { + +struct e2_appconfig; + +/// Converts and returns the given gnb application configuration to a E2AP Network Gateway configuration. +sctp_network_connector_config generate_e2ap_nw_config(const e2_appconfig& config, int ppid); + +} // namespace srsran diff --git a/apps/services/e2/e2_cli11_schema.cpp b/apps/services/e2/e2_cli11_schema.cpp new file mode 100644 index 0000000000..9d36dbca02 --- /dev/null +++ b/apps/services/e2/e2_cli11_schema.cpp @@ -0,0 +1,41 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "e2_cli11_schema.h" +#include "e2_appconfig.h" +#include "srsran/support/cli11_utils.h" + +using namespace srsran; + +static void configure_cli11_e2_args(CLI::App& app, e2_appconfig& e2_params) +{ + add_option(app, "--enable_du_e2", e2_params.enable_du_e2, "Enable DU E2 agent")->capture_default_str(); + add_option(app, "--enable_cu_e2", e2_params.enable_cu_e2, "Enable CU E2 agent")->capture_default_str(); + add_option(app, "--addr", e2_params.ip_addr, "RIC IP address")->capture_default_str(); + add_option(app, "--port", e2_params.port, "RIC port")->check(CLI::Range(20000, 40000))->capture_default_str(); + add_option(app, "--bind_addr", e2_params.bind_addr, "Local IP address to bind for RIC connection") + ->capture_default_str() + ->check(CLI::ValidIPV4); + add_option(app, "--sctp_rto_initial", e2_params.sctp_rto_initial, "SCTP initial RTO value")->capture_default_str(); + add_option(app, "--sctp_rto_min", e2_params.sctp_rto_min, "SCTP RTO min")->capture_default_str(); + add_option(app, "--sctp_rto_max", e2_params.sctp_rto_max, "SCTP RTO max")->capture_default_str(); + add_option(app, "--sctp_init_max_attempts", e2_params.sctp_init_max_attempts, "SCTP init max attempts") + ->capture_default_str(); + add_option(app, "--sctp_max_init_timeo", e2_params.sctp_max_init_timeo, "SCTP max init timeout") + ->capture_default_str(); + add_option(app, "--e2sm_kpm_enabled", e2_params.e2sm_kpm_enabled, "Enable KPM service module")->capture_default_str(); + add_option(app, "--e2sm_rc_enabled", e2_params.e2sm_rc_enabled, "Enable RC service module")->capture_default_str(); +} + +void srsran::configure_cli11_with_e2_appconfig_schema(CLI::App& app, e2_appconfig& config) +{ + CLI::App* e2_subcmd = add_subcommand(app, "e2", "E2 parameters")->configurable(); + configure_cli11_e2_args(*e2_subcmd, config); +} diff --git a/apps/services/e2/e2_cli11_schema.h b/apps/services/e2/e2_cli11_schema.h new file mode 100644 index 0000000000..f3248ecdef --- /dev/null +++ b/apps/services/e2/e2_cli11_schema.h @@ -0,0 +1,22 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "CLI/CLI11.hpp" + +namespace srsran { + +struct e2_appconfig; + +/// Configures the given CLI11 application with the E2 application configuration schema. +void configure_cli11_with_e2_appconfig_schema(CLI::App& app, e2_appconfig& config); + +} // namespace srsran diff --git a/apps/services/hal/CMakeLists.txt b/apps/services/hal/CMakeLists.txt new file mode 100644 index 0000000000..d3d8dea85b --- /dev/null +++ b/apps/services/hal/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +set(SOURCES + hal_cli11_schema.cpp) + +add_library(srsran_hal_app_service STATIC ${SOURCES}) +target_include_directories(srsran_hal_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/hal/hal_appconfig.h b/apps/services/hal/hal_appconfig.h new file mode 100644 index 0000000000..d171fa8429 --- /dev/null +++ b/apps/services/hal/hal_appconfig.h @@ -0,0 +1,23 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include + +namespace srsran { + +/// HAL configuration of the application. +struct hal_appconfig { + /// EAL configuration arguments. + std::string eal_args; +}; + +} // namespace srsran diff --git a/apps/services/hal/hal_cli11_schema.cpp b/apps/services/hal/hal_cli11_schema.cpp new file mode 100644 index 0000000000..9adcd0d864 --- /dev/null +++ b/apps/services/hal/hal_cli11_schema.cpp @@ -0,0 +1,32 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "hal_cli11_schema.h" +#include "hal_appconfig.h" +#include "srsran/support/cli11_utils.h" + +using namespace srsran; + +static void configure_cli11_hal_args(CLI::App& app, hal_appconfig& config) +{ + add_option(app, "--eal_args", config.eal_args, "EAL configuration parameters used to initialize DPDK"); +} + +void srsran::configure_cli11_with_hal_appconfig_schema(CLI::App& app, hal_appconfig& config) +{ + CLI::App* hal_subcmd = add_subcommand(app, "hal", "HAL configuration")->configurable(); + configure_cli11_hal_args(*hal_subcmd, config); +} + +bool srsran::is_hal_section_present(CLI::App& app) +{ + auto subcmd = app.get_subcommand("hal"); + return subcmd->count_all() != 0; +} diff --git a/apps/services/hal/hal_cli11_schema.h b/apps/services/hal/hal_cli11_schema.h new file mode 100644 index 0000000000..5c2939bdd1 --- /dev/null +++ b/apps/services/hal/hal_cli11_schema.h @@ -0,0 +1,25 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#pragma once + +#include "CLI/CLI11.hpp" + +namespace srsran { + +struct hal_appconfig; + +/// Configures the given CLI11 application with the HAL application configuration schema. +void configure_cli11_with_hal_appconfig_schema(CLI::App& app, hal_appconfig& config); + +/// Returns true if the HAL section is present in the given CLI11 application, otherwise false. +bool is_hal_section_present(CLI::App& app); + +} // namespace srsran diff --git a/apps/services/worker_manager/CMakeLists.txt b/apps/services/worker_manager/CMakeLists.txt index 1d5608a063..6efb087451 100644 --- a/apps/services/worker_manager/CMakeLists.txt +++ b/apps/services/worker_manager/CMakeLists.txt @@ -12,9 +12,9 @@ set(SOURCES add_library(srsran_cpu_affinities_helper STATIC cli11_cpu_affinities_parser_helper.cpp) -add_library(srsran_worker_manager_service STATIC ${SOURCES}) -target_include_directories(srsran_worker_manager_service PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_worker_manager_service +add_library(srsran_worker_manager_app_service STATIC ${SOURCES}) +target_include_directories(srsran_worker_manager_app_service PRIVATE ${CMAKE_SOURCE_DIR}) +target_link_libraries(srsran_worker_manager_app_service srsran_cpu_affinities_helper srsran_du_high # TODO: Temp srsran_cu_up) # TODO: Temp diff --git a/include/srsran/support/cli11_utils.h b/include/srsran/support/cli11_utils.h index 17fd49d980..815e7baad1 100644 --- a/include/srsran/support/cli11_utils.h +++ b/include/srsran/support/cli11_utils.h @@ -11,6 +11,7 @@ #pragma once #include "external/CLI/CLI11.hpp" +#include namespace srsran { From 2fb349edf868d048ba5f22b8bb2d035bf1d53a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 7 Nov 2024 11:34:16 +0100 Subject: [PATCH 48/72] ci: only save data in nightly valgrind on failure --- .gitlab/ci/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 537d9bae3d..5d57c80406 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -736,6 +736,7 @@ smoke valgrind update cache: - *build_after_script artifacts: <<: *build_artifacts + when: on_failure cache: - *cache_build_set From 21e8a323f9d23cb5f113dcf31de91f86fff2d1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 7 Nov 2024 11:15:11 +0100 Subject: [PATCH 49/72] ci: increase ephemeral storage in docker jobs --- .gitlab/ci/docker.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index f6e51de22c..89df865e75 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -291,6 +291,8 @@ grafana server image latest: KUBERNETES_CPU_LIMIT: 6 KUBERNETES_MEMORY_REQUEST: 12Gi KUBERNETES_MEMORY_LIMIT: 12Gi + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" REGISTRY_URI: $GITLAB_REGISTRY_URI CONTEXT: ${CI_PROJECT_DIR} DOCKERFILE: docker From 996aad5d2961d8eb2547c51310bb0020a842c79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 7 Nov 2024 11:15:19 +0100 Subject: [PATCH 50/72] ci: limit build cache size --- .gitlab/ci-shared/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab/ci-shared/build.yml b/.gitlab/ci-shared/build.yml index e78efa8cf4..33cc9bd3fb 100644 --- a/.gitlab/ci-shared/build.yml +++ b/.gitlab/ci-shared/build.yml @@ -61,6 +61,8 @@ variables: FORCE_DEBUG_INFO: "" # Empty for cmake default MARCH: "" # Empty for cmake default MTUNE: "" # Empty for cmake default + # CACHE + CCACHE_MAXSIZE: 3G # TEST TEST_EXECUTION_TIMEOUT: 0 # CI From ecd10bf201062bf9d78c7fc7b6775d94a6facd5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 7 Nov 2024 11:33:57 +0100 Subject: [PATCH 51/72] ci: use slowest compression mode in artifacts and cache to generate smaller artifacts --- .gitlab/ci-shared/build.yml | 5 +++++ .gitlab/ci-shared/e2e.yml | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci-shared/build.yml b/.gitlab/ci-shared/build.yml index 33cc9bd3fb..0cd2218e0c 100644 --- a/.gitlab/ci-shared/build.yml +++ b/.gitlab/ci-shared/build.yml @@ -66,6 +66,11 @@ variables: # TEST TEST_EXECUTION_TIMEOUT: 0 # CI + TRANSFER_METER_FREQUENCY: 5s + ARTIFACT_COMPRESSION_LEVEL: slowest + CACHE_COMPRESSION_LEVEL: slowest + CACHE_REQUEST_TIMEOUT: 5 # minutes - 10 by default + # K8 KUBERNETES_CPU_REQUEST: 6 KUBERNETES_CPU_LIMIT: 6 KUBERNETES_MEMORY_REQUEST: 12Gi diff --git a/.gitlab/ci-shared/e2e.yml b/.gitlab/ci-shared/e2e.yml index 2336f3231e..4603254b20 100644 --- a/.gitlab/ci-shared/e2e.yml +++ b/.gitlab/ci-shared/e2e.yml @@ -66,7 +66,9 @@ variables: name: ${RETINA_REGISTRY_PREFIX}/launcher:${RETINA_VERSION} entrypoint: ["/bin/sh", "-c"] variables: - ARTIFACT_COMPRESSION_LEVEL: "slowest" + TRANSFER_METER_FREQUENCY: 5s + ARTIFACT_COMPRESSION_LEVEL: slowest + RUNNER_AFTER_SCRIPT_TIMEOUT: 1m KUBERNETES_CPU_REQUEST: 2 KUBERNETES_CPU_LIMIT: 2 KUBERNETES_MEMORY_REQUEST: 2Gi From 4b752dca7aa2875dab5acf396d0f9fc73fbbcc4d Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 6 Nov 2024 17:47:57 +0100 Subject: [PATCH 52/72] SCHED: Move ue destruction out of the critical section --- include/srsran/adt/slotted_array.h | 17 +++++++++++++++ lib/scheduler/config/sched_config_manager.cpp | 2 +- lib/scheduler/ue_context/ue.cpp | 21 +++++++++++++------ lib/scheduler/ue_context/ue.h | 2 ++ .../ue_scheduling/ue_event_manager.cpp | 8 ++++++- lib/scheduler/ue_scheduling/ue_repository.cpp | 20 +++++++++++++----- lib/scheduler/ue_scheduling/ue_repository.h | 8 +++++++ 7 files changed, 65 insertions(+), 13 deletions(-) diff --git a/include/srsran/adt/slotted_array.h b/include/srsran/adt/slotted_array.h index d92c131c3f..5cf54e1377 100644 --- a/include/srsran/adt/slotted_array.h +++ b/include/srsran/adt/slotted_array.h @@ -293,6 +293,19 @@ class slotted_array return false; } + /// Takes the element out of the container pointed by the given index + /// \param idx Position of the erased element in the array + T take(size_t idx) noexcept + { + srsran_assert(idx < this->vec.size(), "Out-of-bounds access to array: {}>={}", idx, this->vec.size()); + srsran_assert(this->contains(idx), "Empty position in index {}", idx); + + this->nof_elems--; + T obj = std::move(*this->vec[idx]); + this->vec[idx].reset(); + return obj; + } + /// Erase object pointed by the given iterator. Iterator must point to valid element /// \param it container iterator void erase(iterator it) noexcept { erase(this->extract_iterator_index(it)); } @@ -554,6 +567,10 @@ class slotted_id_table : private IdToIntConversion /// \param it container iterator void erase(iterator it) noexcept { sl_ar.erase(it); } + /// Takes the element out of the container pointed by the given index + /// \param id ID of the taken element in the table + T take(key_type id) noexcept { return sl_ar.take(id); } + /// Clear all elements of the container void clear() noexcept { sl_ar.clear(); } diff --git a/lib/scheduler/config/sched_config_manager.cpp b/lib/scheduler/config/sched_config_manager.cpp index 164f5c8fdd..8e468cb869 100644 --- a/lib/scheduler/config/sched_config_manager.cpp +++ b/lib/scheduler/config/sched_config_manager.cpp @@ -260,7 +260,7 @@ void sched_config_manager::flush_ues_to_rem() { // Note: This should be called by a thread outside of the critical path. - // clear the UEs to rem. + // Clear the UEs to rem. while (ues_to_rem.try_pop()) { } } diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 8e24047885..b116067962 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -69,9 +69,18 @@ void ue::deactivate() ul_lc_ch_mgr.deactivate(); // Cancel HARQ retransmissions in all UE cells. - for (unsigned i = 0; i != ue_du_cells.size(); ++i) { - if (ue_du_cells[i] != nullptr) { - ue_du_cells[i]->deactivate(); + for (auto& cell : ue_du_cells) { + if (cell != nullptr) { + cell->deactivate(); + } + } +} + +void ue::release_resources() +{ + for (auto& cell : ue_du_cells) { + if (cell != nullptr) { + cell->harqs.reset(); } } } @@ -87,7 +96,7 @@ void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) // Cell configuration. // Handle removed cells. - for (unsigned i = 0; i != ue_du_cells.size(); ++i) { + for (unsigned i = 0, e = ue_du_cells.size(); i != e; ++i) { if (ue_du_cells[i] != nullptr) { if (not ue_ded_cfg->contains(to_du_cell_index(i))) { // TODO: Handle SCell deletions. @@ -95,7 +104,7 @@ void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) } } // Handle new cell creations or reconfigurations. - for (unsigned ue_cell_index = 0; ue_cell_index != ue_ded_cfg->nof_cells(); ++ue_cell_index) { + for (unsigned ue_cell_index = 0, e = ue_ded_cfg->nof_cells(); ue_cell_index != e; ++ue_cell_index) { du_cell_index_t cell_index = ue_ded_cfg->ue_cell_cfg(to_ue_cell_index(ue_cell_index)).cell_cfg_common.cell_index; auto& ue_cell_inst = ue_du_cells[cell_index]; if (ue_cell_inst == nullptr) { @@ -111,7 +120,7 @@ void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) // Recompute mapping of UE cell indexing to DU cell indexing. ue_cells.resize(ue_ded_cfg->nof_cells(), nullptr); - for (unsigned ue_cell_index = 0; ue_cell_index != ue_ded_cfg->nof_cells(); ++ue_cell_index) { + for (unsigned ue_cell_index = 0, e = ue_ded_cfg->nof_cells(); ue_cell_index != e; ++ue_cell_index) { auto& ue_cell_inst = ue_du_cells[ue_ded_cfg->ue_cell_cfg(to_ue_cell_index(ue_cell_index)).cell_cfg_common.cell_index]; ue_cells[ue_cell_index] = ue_cell_inst.get(); diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index 34674dfebc..3d30815921 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -47,6 +47,8 @@ class ue void deactivate(); + void release_resources(); + ue_cell* find_cell(du_cell_index_t cell_index) { srsran_assert(cell_index < MAX_NOF_DU_CELLS, "Invalid cell_index={}", cell_index); diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index f119608c49..6e1d378907 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -185,7 +185,7 @@ ue_event_manager::ue_event_manager(ue_repository& ue_db_) : { } -ue_event_manager::~ue_event_manager() {} +ue_event_manager::~ue_event_manager() = default; void ue_event_manager::handle_ue_creation(ue_config_update_event ev) { @@ -234,6 +234,9 @@ void ue_event_manager::handle_ue_creation(ue_config_update_event ev) if (not common_events.try_push(common_event_t{INVALID_DU_UE_INDEX, std::move(handle_ue_creation_impl)})) { logger.warning("ue={}: Discarding UE creation. Cause: Event queue is full", ue_idx); } + + // Destroy any pending UEs in the repository outside the critical section. + ue_db.destroy_pending_ues(); } void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) @@ -332,6 +335,9 @@ void ue_event_manager::handle_ue_deletion(ue_config_delete_event ev) if (not common_events.try_push(common_event_t{ue_index, std::move(handle_ue_deletion_impl)})) { logger.warning("ue={}: Discarding UE deletion. Cause: Event queue is full", ue_index); } + + // Destroy any pending UEs in the repository outside the critical section. + ue_db.destroy_pending_ues(); } void ue_event_manager::handle_ue_config_applied(du_ue_index_t ue_idx) diff --git a/lib/scheduler/ue_scheduling/ue_repository.cpp b/lib/scheduler/ue_scheduling/ue_repository.cpp index 642fe488f4..c6281a6289 100644 --- a/lib/scheduler/ue_scheduling/ue_repository.cpp +++ b/lib/scheduler/ue_scheduling/ue_repository.cpp @@ -14,7 +14,7 @@ using namespace srsran; -ue_repository::ue_repository() : logger(srslog::fetch_basic_logger("SCHED")) +ue_repository::ue_repository() : logger(srslog::fetch_basic_logger("SCHED")), ues_to_destroy(MAX_NOF_DU_UES) { rnti_to_ue_index_lookup.reserve(MAX_NOF_DU_UES); } @@ -27,12 +27,12 @@ static bool is_ue_ready_for_removal(ue& u) unsigned nof_ue_cells = u.nof_cells(); for (unsigned cell_idx = 0; cell_idx != nof_ue_cells; ++cell_idx) { const ue_cell& c = u.get_cell((ue_cell_index_t)cell_idx); - for (unsigned i = 0; i != c.harqs.nof_dl_harqs(); ++i) { + for (unsigned i = 0, e = c.harqs.nof_dl_harqs(); i != e; ++i) { if (c.harqs.dl_harq(to_harq_id(i)).has_value()) { return false; } } - for (unsigned i = 0; i != c.harqs.nof_ul_harqs(); ++i) { + for (unsigned i = 0, e = c.harqs.nof_ul_harqs(); i != e; ++i) { if (c.harqs.ul_harq(to_harq_id(i)).has_value()) { return false; } @@ -89,8 +89,12 @@ void ue_repository::slot_indication(slot_point sl_tx) logger.error("ue={} rnti={}: UE with provided c-rnti not found in RNTI-to-UE-index lookup table.", ue_idx, crnti); } - // Remove UE from the repository. - ues.erase(ue_idx); + // Take the UE from the repository and schedule its destruction outside the critical section. + auto ue_ptr = ues.take(ue_idx); + ue_ptr->release_resources(); + if (not ues_to_destroy.try_push(std::move(ue_ptr))) { + logger.warning("Failed to offload UE destruction. Performance may be affected"); + } // Marks UE config removal as complete. rem_ev.reset(); @@ -149,3 +153,9 @@ const ue* ue_repository::find_by_rnti(rnti_t rnti) const auto it = search_rnti(rnti_to_ue_index_lookup, rnti); return it != rnti_to_ue_index_lookup.end() ? ues[it->second].get() : nullptr; } + +void ue_repository::destroy_pending_ues() +{ + while (ues_to_destroy.try_pop()) { + } +} diff --git a/lib/scheduler/ue_scheduling/ue_repository.h b/lib/scheduler/ue_scheduling/ue_repository.h index e102a2b074..44a01b947d 100644 --- a/lib/scheduler/ue_scheduling/ue_repository.h +++ b/lib/scheduler/ue_scheduling/ue_repository.h @@ -62,6 +62,8 @@ class ue_repository const_iterator lower_bound(du_ue_index_t ue_index) const { return ues.lower_bound(ue_index); } + void destroy_pending_ues(); + private: srslog::basic_logger& logger; @@ -77,6 +79,12 @@ class ue_repository // Last slot indication. slot_point last_sl_tx; + + // UE objects pending to be destroyed by a low priority thread. + concurrent_queue, + concurrent_queue_policy::lockfree_mpmc, + concurrent_queue_wait_policy::non_blocking> + ues_to_destroy; }; } // namespace srsran From 61d93a3c432004a1686462ab7cbdc9c9b82618d9 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 7 Nov 2024 14:42:37 +0100 Subject: [PATCH 53/72] ci: increase expected_nof_kos --- tests/e2e/tests/viavi/test_declaration.yml | 24 +++++++++---------- .../tests/viavi/test_declaration_debug.yml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 580055127b..5c807f8d22 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -35,7 +35,7 @@ tests: # test/fail criteria expected_dl_bitrate: 1.2e+9 expected_ul_bitrate: 80.0e+6 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -49,7 +49,7 @@ tests: # test/fail criteria expected_dl_bitrate: 1.2e+9 expected_ul_bitrate: 80.0e+6 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -91,7 +91,7 @@ tests: # test/fail criteria expected_dl_bitrate: 1.0e+9 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -105,7 +105,7 @@ tests: # test/fail criteria expected_dl_bitrate: 1.0e+9 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -147,7 +147,7 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 4 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -161,7 +161,7 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 4 + expected_nof_kos: 10 warning_as_errors: true enable_dddsu: true @@ -176,7 +176,7 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 4 + expected_nof_kos: 10 warning_as_errors: true ul_heavy_7u2d: true @@ -191,7 +191,7 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 4 + expected_nof_kos: 10 warning_as_errors: true ul_heavy_6u3d: true @@ -220,7 +220,7 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -234,7 +234,7 @@ tests: # test/fail criteria expected_dl_bitrate: 14.0e+3 expected_ul_bitrate: 1.0e+3 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: true - campaign_filename: *campaign_filename @@ -248,7 +248,7 @@ tests: # test/fail criteria expected_dl_bitrate: 1.2e+9 expected_ul_bitrate: 80.0e+6 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: false - campaign_filename: *campaign_filename @@ -262,5 +262,5 @@ tests: # test/fail criteria expected_dl_bitrate: 1.2e+9 expected_ul_bitrate: 80.0e+6 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: false diff --git a/tests/e2e/tests/viavi/test_declaration_debug.yml b/tests/e2e/tests/viavi/test_declaration_debug.yml index e89920ca9a..3228a22bad 100644 --- a/tests/e2e/tests/viavi/test_declaration_debug.yml +++ b/tests/e2e/tests/viavi/test_declaration_debug.yml @@ -35,5 +35,5 @@ tests: # test/fail criteria expected_dl_bitrate: 1.2e+9 expected_ul_bitrate: 80.0e+6 - expected_nof_kos: 3 + expected_nof_kos: 10 warning_as_errors: false From f65d8e159a87c04bf78b102f17388128621dc680 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 7 Nov 2024 16:15:41 +0100 Subject: [PATCH 54/72] ci: update viavi tests and retina --- .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/viavi/test_declaration.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index e1e70aaecf..03bbe9f76e 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.54.11 +RETINA_VERSION=0.54.12 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 5c807f8d22..97147a7e73 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -151,7 +151,7 @@ tests: warning_as_errors: true - campaign_filename: *campaign_filename - test_name: "32UE ideal UDP attach-detach with traffic" + test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" id: "32UE ideal UDP attach-detach with traffic DDDSU" @@ -166,7 +166,7 @@ tests: enable_dddsu: true - campaign_filename: *campaign_filename - test_name: "32UE ideal UDP attach-detach with traffic" + test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" id: "32UE ideal UDP attach-detach with traffic UL Heavy 7u2d" @@ -181,7 +181,7 @@ tests: ul_heavy_7u2d: true - campaign_filename: *campaign_filename - test_name: "32UE ideal UDP attach-detach with traffic" + test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" id: "32UE ideal UDP attach-detach with traffic UL Heavy 6u3d" From fdd1c2ca7e6133b3e9cc46d219ae2f433d8d4f3c Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 7 Nov 2024 16:50:32 +0000 Subject: [PATCH 55/72] rlc: fix stale RLC AM status PDU --- lib/rlc/rlc_rx_am_entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index d28ed51b47..8859f353eb 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -115,7 +115,7 @@ void rlc_rx_am_entity::handle_data_pdu(byte_buffer_slice buf) auto on_function_exit = make_scope_exit([&]() { logger.log_debug( "Post-processing for AMD PDU: status_changed={} status_requested={}", status_changed, status_requested); - if (status_changed) { + if (status_changed || status_requested) { refresh_status_report(); } if (status_requested) { From fa149e4fa2481549f31ff6acf20cea0e9bffca75 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 7 Nov 2024 18:36:56 +0100 Subject: [PATCH 56/72] service: changes the CPU architecture info to store a internal object variable instead of a static class member, to avoid initialization problems --- include/srsran/support/cpu_architecture_info.h | 2 +- lib/support/cpu_architecture_info.cpp | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/include/srsran/support/cpu_architecture_info.h b/include/srsran/support/cpu_architecture_info.h index eb40c3de1f..563efa4af9 100644 --- a/include/srsran/support/cpu_architecture_info.h +++ b/include/srsran/support/cpu_architecture_info.h @@ -42,7 +42,7 @@ class cpu_architecture_info static cpu_description discover_cpu_architecture(); /// Stores the CPU description. - static const cpu_description cpu_desc; + const cpu_description cpu_desc{discover_cpu_architecture()}; /// Default constructor. cpu_architecture_info() = default; diff --git a/lib/support/cpu_architecture_info.cpp b/lib/support/cpu_architecture_info.cpp index b11ef036e6..049fc14876 100644 --- a/lib/support/cpu_architecture_info.cpp +++ b/lib/support/cpu_architecture_info.cpp @@ -46,12 +46,6 @@ static interval parse_cpu_range(const std::string& value) return {range[0], range[1]}; } -/// Obtain CPU description at the start of the application. This value is affected by commands or tools like taskset, -/// which limit the number of cores available to the application. However, frameworks (e.g. DPDK) that affect the -/// affinities of the main thread in the main() function will not affect this value. -const cpu_architecture_info::cpu_description cpu_architecture_info::cpu_desc = - cpu_architecture_info::discover_cpu_architecture(); - cpu_architecture_info::cpu_description cpu_architecture_info::discover_cpu_architecture() { // Check if custom cgroups exist in the system (possibly left from a previous run). From 921921d366ee49cb77bea59a690bfae12e5a81a2 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 7 Nov 2024 09:54:10 +0100 Subject: [PATCH 57/72] cu_cp: fix logging --- lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp index 21f4d90b63..bc3c90e2cb 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp @@ -187,14 +187,14 @@ std::optional get_ssb_rsrp(const rrc_meas_result_nr& meas_result) void cell_meas_manager::report_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results) { - logger.debug("ue={} Received measurement result with meas_id={}", ue_index, meas_results.meas_id); + logger.debug("ue={}: Received measurement result with meas_id={}", ue_index, meas_results.meas_id); auto& ue_meas_context = ue_mng.get_measurement_context(ue_index); // Verify meas_id is valid. if (ue_meas_context.meas_id_to_meas_context.find(meas_results.meas_id) == ue_meas_context.meas_id_to_meas_context.end()) { - logger.debug("ue={} Measurement result for unknown meas_id={} received", ue_index, meas_results.meas_id); + logger.debug("ue={}: Measurement result for unknown meas_id={} received", ue_index, meas_results.meas_id); return; } From 524a823655fb95f51e6978efb0d43d69b27b6ffa Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 7 Nov 2024 09:58:13 +0100 Subject: [PATCH 58/72] cu_cp,rrc: reques ue release when rrc reconfiguration after ho fails --- lib/rrc/ue/rrc_ue_message_handlers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 20cc8aa894..91fa168dd3 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -435,8 +435,9 @@ async_task rrc_ue_impl::handle_handover_reconfiguration_complete_expected( context.state = rrc_state::connected; } else { - logger.log_debug("Did not receive RRC Reconfiguration Complete after HO. Cause: {}", + logger.log_debug("Did not receive RRC Reconfiguration Complete after HO. Cause: {}. Requesting UE release", transaction.failure_cause() == protocol_transaction_failure::timeout ? "timeout" : "canceled"); + on_ue_release_required(ngap_cause_radio_network_t::ho_fail_in_target_5_gc_ngran_node_or_target_sys); } CORO_RETURN(procedure_result); From 930db4f8a641eff166ea00d8794b0c015ebfe4db Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 7 Nov 2024 11:39:17 +0100 Subject: [PATCH 59/72] cu_cp: add unit test for intra du handover with failed rrc reconfiguration --- .../cu_cp/cu_cp_intra_du_handover_test.cpp | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/tests/unittests/cu_cp/cu_cp_intra_du_handover_test.cpp b/tests/unittests/cu_cp/cu_cp_intra_du_handover_test.cpp index 148b95a526..e05581ab3f 100644 --- a/tests/unittests/cu_cp/cu_cp_intra_du_handover_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_intra_du_handover_test.cpp @@ -157,6 +157,22 @@ class cu_cp_intra_du_handover_test : public cu_cp_test_environment, public ::tes return true; } + [[nodiscard]] bool timeout_rrc_reconfiguration_and_await_f1ap_ue_context_release_command() + { + // Fail RRC Reconfiguration (UE doesn't respond) and wait for F1AP UE Context Release Command. + if (tick_until( + std::chrono::milliseconds(this->get_cu_cp_cfg().rrc.rrc_procedure_timeout_ms), + [&]() { return false; }, + false)) { + return false; + } + report_fatal_error_if_not(this->wait_for_f1ap_tx_pdu(du_idx, f1ap_pdu), + "Failed to receive UE Context Release Command"); + report_fatal_error_if_not(test_helpers::is_valid_ue_context_release_command(f1ap_pdu), + "Invalid UE Context Release Command"); + return true; + } + [[nodiscard]] bool send_rrc_reconfiguration_complete() { get_du(du_idx).push_ul_pdu(generate_ul_rrc_message_transfer( @@ -226,6 +242,31 @@ TEST_F(cu_cp_intra_du_handover_test, when_bearer_context_modification_fails_then ASSERT_EQ(report.ues.size(), 1) << "UE should be removed"; } +TEST_F(cu_cp_intra_du_handover_test, when_rrc_reconfiguration_fails_then_ho_fails) +{ + // Inject Measurement Report and await F1AP UE Context Setup Request. + ASSERT_TRUE(send_rrc_measurement_report_and_await_ue_context_setup_request()); + + // Inject UE Context Setup Response and await Bearer Context Modification Request. + ASSERT_TRUE(send_ue_context_setup_response_and_await_bearer_context_modification_request()); + + // Inject Bearer Context Modification Response and await UE Context Modification Request. + ASSERT_TRUE(send_bearer_context_modification_response_and_await_ue_context_modification_request()); + + // Inject UE Context Modification Response. + ASSERT_TRUE(send_ue_context_modification_response()); + + // Let the RRC Reconfiguration timeout and await F1AP UE Context Release Command for target UE. + ASSERT_TRUE(timeout_rrc_reconfiguration_and_await_f1ap_ue_context_release_command()); + + // // Inject F1AP UE Context Release Complete for target UE. + ASSERT_TRUE(send_f1ap_ue_context_release_complete(target_cu_ue_id, target_du_ue_id)); + + // STATUS: Target UE should be removed from DU. + auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); + ASSERT_EQ(report.ues.size(), 1) << "Target UE should be removed"; +} + TEST_F(cu_cp_intra_du_handover_test, when_ho_succeeds_then_source_ue_is_removed) { // Inject Measurement Report and await F1AP UE Context Setup Request. @@ -248,5 +289,5 @@ TEST_F(cu_cp_intra_du_handover_test, when_ho_succeeds_then_source_ue_is_removed) // STATUS: Source UE should be removed from DU. auto report = this->get_cu_cp().get_metrics_handler().request_metrics_report(); - ASSERT_EQ(report.ues.size(), 1) << "UE should be removed"; + ASSERT_EQ(report.ues.size(), 1) << "Source UE should be removed"; } From 0ca9f483ee11fd3e17537ec9211616f575297f5c Mon Sep 17 00:00:00 2001 From: faluco Date: Mon, 14 Oct 2024 14:06:16 +0200 Subject: [PATCH 60/72] F1AP: Change the f1ap_ue_ids::du_ue_f1ap_id field to be optional as there are cases where it is not being set. --- lib/f1ap/cu_cp/f1ap_cu_impl.cpp | 5 ++++- .../procedures/ue_context_modification_procedure.cpp | 4 +++- .../cu_cp/procedures/ue_context_release_procedure.cpp | 4 ++-- .../cu_cp/procedures/ue_context_setup_procedure.cpp | 5 +++-- lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.cpp | 5 +++-- lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.h | 2 +- lib/f1ap/cu_cp/ue_context/f1ap_ue_ids.h | 6 +++--- lib/f1ap/cu_cp/ue_context/f1ap_ue_logger.h | 10 +++++++--- 8 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/f1ap/cu_cp/f1ap_cu_impl.cpp b/lib/f1ap/cu_cp/f1ap_cu_impl.cpp index 2fa0e3ddc4..b24cf02df3 100644 --- a/lib/f1ap/cu_cp/f1ap_cu_impl.cpp +++ b/lib/f1ap/cu_cp/f1ap_cu_impl.cpp @@ -108,7 +108,10 @@ bool f1ap_cu_impl::handle_ue_id_update(ue_index_t ue_index, ue_index_t old_ue_in } // Mark that an old gNB-DU UE F1AP ID needs to be sent to the DU in the next DL RRC Message Transfer. - ue_ctxt_list[ue_index].pending_old_ue_id = ue_ctxt_list[old_ue_index].ue_ids.du_ue_f1ap_id; + srsran_assert(ue_ctxt_list[old_ue_index].ue_ids.du_ue_f1ap_id && + ue_ctxt_list[old_ue_index].ue_ids.du_ue_f1ap_id != gnb_du_ue_f1ap_id_t::invalid, + "GNB-DU-UE-F1AP-ID should be valid"); + ue_ctxt_list[ue_index].pending_old_ue_id = *ue_ctxt_list[old_ue_index].ue_ids.du_ue_f1ap_id; return true; } diff --git a/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp index 5598255896..e2a786843c 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_modification_procedure.cpp @@ -77,7 +77,9 @@ void ue_context_modification_procedure::send_ue_context_modification_request() fill_asn1_ue_context_modification_request(ctx_mod, request); - ctx_mod->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(ue_ctxt.ue_ids.du_ue_f1ap_id); + srsran_sanity_check(ue_ctxt.ue_ids.du_ue_f1ap_id && ue_ctxt.ue_ids.du_ue_f1ap_id != gnb_du_ue_f1ap_id_t::invalid, + "Invalid gNB-DU-UE-F1AP-Id"); + ctx_mod->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(*ue_ctxt.ue_ids.du_ue_f1ap_id); ctx_mod->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue_ctxt.ue_ids.cu_ue_f1ap_id); // send UE context modification request message diff --git a/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp index 8f911a9a20..f2f7894800 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_release_procedure.cpp @@ -25,7 +25,7 @@ ue_context_release_procedure::ue_context_release_procedure(const f1ap_configurat f1ap_cfg(f1ap_cfg_), ue_ctxt(ue_ctxt_), f1ap_notifier(f1ap_notif_), logger(srslog::fetch_basic_logger("CU-CP-F1")) { command->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue_ctxt.ue_ids.cu_ue_f1ap_id); - command->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(ue_ctxt.ue_ids.du_ue_f1ap_id); + command->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(*ue_ctxt.ue_ids.du_ue_f1ap_id); command->cause = cause_to_asn1(cmd_.cause); if (!cmd_.rrc_release_pdu.empty()) { command->rrc_container_present = true; @@ -74,7 +74,7 @@ ue_index_t ue_context_release_procedure::create_ue_context_release_complete() { if (transaction_sink.successful()) { gnb_du_ue_f1ap_id_t du_ue_id = int_to_gnb_du_ue_f1ap_id(transaction_sink.response()->gnb_du_ue_f1ap_id); - if (du_ue_id != ue_ctxt.ue_ids.du_ue_f1ap_id) { + if (!ue_ctxt.ue_ids.du_ue_f1ap_id || du_ue_id != *ue_ctxt.ue_ids.du_ue_f1ap_id) { logger.error("{}: Procedure failed. Cause: gNB-DU-UE-F1AP-ID mismatch.", f1ap_ue_log_prefix{ue_ctxt.ue_ids, name()}); return ue_index_t::invalid; diff --git a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp index 6303682363..9fe6354c04 100644 --- a/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp +++ b/lib/f1ap/cu_cp/procedures/ue_context_setup_procedure.cpp @@ -212,9 +212,10 @@ static void fill_asn1_ue_context_setup_request(asn1::f1ap::ue_context_setup_requ { asn1_request->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue_ids.cu_ue_f1ap_id); - asn1_request->gnb_du_ue_f1ap_id_present = ue_ids.du_ue_f1ap_id != gnb_du_ue_f1ap_id_t::invalid; + asn1_request->gnb_du_ue_f1ap_id_present = + ue_ids.du_ue_f1ap_id && ue_ids.du_ue_f1ap_id != gnb_du_ue_f1ap_id_t::invalid; if (asn1_request->gnb_du_ue_f1ap_id_present) { - asn1_request->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(ue_ids.du_ue_f1ap_id); + asn1_request->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(*ue_ids.du_ue_f1ap_id); } asn1_request->sp_cell_id = cgi_to_asn1(request.sp_cell_id); diff --git a/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.cpp b/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.cpp index 2f491a15d4..66c18b6609 100644 --- a/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.cpp +++ b/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.cpp @@ -17,11 +17,12 @@ using namespace srs_cu_cp; void f1ap_ue_context::handle_dl_rrc_message(const f1ap_dl_rrc_message& msg, f1ap_message_notifier& msg_notifier) { - srsran_sanity_check(ue_ids.du_ue_f1ap_id != gnb_du_ue_f1ap_id_t::invalid, "Invalid gNB-DU-UE-F1AP-Id"); + srsran_sanity_check(ue_ids.du_ue_f1ap_id && ue_ids.du_ue_f1ap_id != gnb_du_ue_f1ap_id_t::invalid, + "Invalid gNB-DU-UE-F1AP-Id"); asn1::f1ap::dl_rrc_msg_transfer_s dl_rrc_msg = {}; dl_rrc_msg->gnb_cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_to_uint(ue_ids.cu_ue_f1ap_id); - dl_rrc_msg->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(ue_ids.du_ue_f1ap_id); + dl_rrc_msg->gnb_du_ue_f1ap_id = gnb_du_ue_f1ap_id_to_uint(*ue_ids.du_ue_f1ap_id); dl_rrc_msg->srb_id = static_cast(srb_id_to_uint(msg.srb_id)); dl_rrc_msg->rrc_container = msg.rrc_container.copy(); diff --git a/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.h b/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.h index 251b59d509..a93e40d7e1 100644 --- a/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.h +++ b/lib/f1ap/cu_cp/ue_context/f1ap_cu_ue_context.h @@ -86,7 +86,7 @@ class f1ap_ue_context_list { auto it = std::find_if( ues.begin(), ues.end(), [du_ue_id](const std::pair& u) { - return u.second.ue_ids.du_ue_f1ap_id == du_ue_id; + return u.second.ue_ids.du_ue_f1ap_id && u.second.ue_ids.du_ue_f1ap_id == du_ue_id; }); return it != ues.end() ? &it->second : nullptr; } diff --git a/lib/f1ap/cu_cp/ue_context/f1ap_ue_ids.h b/lib/f1ap/cu_cp/ue_context/f1ap_ue_ids.h index 1069c94299..e815375e6a 100644 --- a/lib/f1ap/cu_cp/ue_context/f1ap_ue_ids.h +++ b/lib/f1ap/cu_cp/ue_context/f1ap_ue_ids.h @@ -18,9 +18,9 @@ namespace srs_cu_cp { /// Identifiers that associate a UE in the F1AP-CU. struct f1ap_ue_ids { - const ue_index_t ue_index = ue_index_t::invalid; - const gnb_cu_ue_f1ap_id_t cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_t::invalid; - gnb_du_ue_f1ap_id_t du_ue_f1ap_id = gnb_du_ue_f1ap_id_t::invalid; + ue_index_t ue_index = ue_index_t::invalid; + gnb_cu_ue_f1ap_id_t cu_ue_f1ap_id = gnb_cu_ue_f1ap_id_t::invalid; + std::optional du_ue_f1ap_id; }; } // namespace srs_cu_cp diff --git a/lib/f1ap/cu_cp/ue_context/f1ap_ue_logger.h b/lib/f1ap/cu_cp/ue_context/f1ap_ue_logger.h index e444253c13..f4db126be2 100644 --- a/lib/f1ap/cu_cp/ue_context/f1ap_ue_logger.h +++ b/lib/f1ap/cu_cp/ue_context/f1ap_ue_logger.h @@ -20,12 +20,16 @@ namespace srs_cu_cp { struct f1ap_ue_log_prefix : public srsran::f1ap_common_log_prefix { using srsran::f1ap_common_log_prefix::f1ap_common_log_prefix; - f1ap_ue_log_prefix(ue_index_t ue_index_, gnb_cu_ue_f1ap_id_t cu_ue_id_, gnb_du_ue_f1ap_id_t du_ue_id_) : - srsran::f1ap_common_log_prefix(du_ue_id_, cu_ue_id_), ue_index(ue_index_) + f1ap_ue_log_prefix(ue_index_t ue_index_, + gnb_cu_ue_f1ap_id_t cu_ue_id_, + std::optional du_ue_id_) : + srsran::f1ap_common_log_prefix(du_ue_id_.value_or(gnb_du_ue_f1ap_id_t::invalid), cu_ue_id_), ue_index(ue_index_) { } f1ap_ue_log_prefix(const f1ap_ue_ids& context_, const char* proc_name_ = nullptr) : - srsran::f1ap_common_log_prefix(context_.du_ue_f1ap_id, context_.cu_ue_f1ap_id, proc_name_), + srsran::f1ap_common_log_prefix(context_.du_ue_f1ap_id.value_or(gnb_du_ue_f1ap_id_t::invalid), + context_.cu_ue_f1ap_id, + proc_name_), ue_index(context_.ue_index) { } From 2c7a5f89baadac338af62edcb6e7d634cf986f7a Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 8 Nov 2024 12:37:16 +0100 Subject: [PATCH 61/72] cu_cp,rrc: log incoming messages in info --- lib/rrc/ue/rrc_ue_message_handlers.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 91fa168dd3..cb89c82af5 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -132,11 +132,9 @@ void rrc_ue_impl::handle_pdu(const srb_id_t srb_id, byte_buffer rrc_pdu) } // Log Rx message - if (logger.get_basic_logger().debug.enabled()) { - fmt::memory_buffer fmtbuf; - fmt::format_to(fmtbuf, "{} DCCH UL", srb_id); - log_rrc_message(logger, Rx, rrc_pdu, ul_dcch_msg, to_c_str(fmtbuf)); - } + fmt::memory_buffer fmtbuf; + fmt::format_to(fmtbuf, "{} DCCH UL", srb_id); + log_rrc_message(logger, Rx, rrc_pdu, ul_dcch_msg, to_c_str(fmtbuf)); switch (ul_dcch_msg.msg.c1().type().value) { case ul_dcch_msg_type_c::c1_c_::types_opts::options::ul_info_transfer: From fc5937e248d9a6a455dae4acda907f83ce437869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Fri, 8 Nov 2024 12:47:35 +0100 Subject: [PATCH 62/72] ci,e2e: allow warnings as errors in parallel reestablishment --- tests/e2e/tests/reestablishment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/reestablishment.py b/tests/e2e/tests/reestablishment.py index 0c74036356..0967d8a71e 100644 --- a/tests/e2e/tests/reestablishment.py +++ b/tests/e2e/tests/reestablishment.py @@ -283,7 +283,7 @@ def test_zmq_reestablishment_parallel( always_download_artifacts=True, noise_spd=noise_spd, log_ip_level="debug", - warning_as_errors=True, + warning_as_errors=False, ) as ue_attach_info_dict: for i in range(number_of_reestablishments): From 90f843848e89bdad667dfc0f3466e554b81d0e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Fri, 8 Nov 2024 13:30:09 +0100 Subject: [PATCH 63/72] ci,e2e: increase timeouts in new zmq attach_detach test --- .gitlab/ci/e2e.yml | 17 +---------------- tests/e2e/tests/attach_detach.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index d531974cfb..fa5f490032 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -210,22 +210,7 @@ amari 8UE: parallel: matrix: - KEYWORDS: - ["reestablishment and sequentially", "handover and sequentially"] - -amari 8UE [attach_detach 2024-03-15]: - extends: .zmq-uesim - variables: - MARKERS: "zmq and not smoke" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - KEYWORDS: "attach_detach" - allow_failure: true - -amari 8UE [attach_detach 2023-09-08]: - extends: .zmq - variables: - MARKERS: "zmq and not smoke" - RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" - KEYWORDS: "attach_detach" + ["reestablishment and sequentially", "handover and sequentially", "attach_detach"] amari 8UE beta: extends: amari 8UE diff --git a/tests/e2e/tests/attach_detach.py b/tests/e2e/tests/attach_detach.py index 9384d0832d..cb4bd06b20 100644 --- a/tests/e2e/tests/attach_detach.py +++ b/tests/e2e/tests/attach_detach.py @@ -10,6 +10,7 @@ Attach / Detach Tests """ import logging +from time import sleep from typing import Optional, Sequence, Tuple, Union from pytest import mark @@ -50,12 +51,12 @@ def test_smoke( common_scs=30, bandwidth=50, sample_rate=None, - iperf_duration=30, bitrate=HIGH_BITRATE, protocol=IPerfProto.UDP, direction=IPerfDir.BIDIRECTIONAL, global_timing_advance=0, time_alignment_calibration=0, + ue_stop_timeout=15, always_download_artifacts=False, ) @@ -111,13 +112,14 @@ def test_zmq( common_scs=common_scs, bandwidth=bandwidth, sample_rate=None, # default from testbed - iperf_duration=30, bitrate=HIGH_BITRATE, protocol=protocol, direction=direction, global_timing_advance=0, time_alignment_calibration=0, always_download_artifacts=True, + ue_stop_timeout=45, + ue_settle_time=45, ) @@ -164,7 +166,6 @@ def test_rf_udp( common_scs=common_scs, bandwidth=bandwidth, sample_rate=None, # default from testbed - iperf_duration=120, protocol=IPerfProto.UDP, bitrate=HIGH_BITRATE, direction=direction, @@ -186,7 +187,6 @@ def _attach_and_detach_multi_ues( common_scs: int, bandwidth: int, sample_rate: Optional[int], - iperf_duration: int, bitrate: int, protocol: IPerfProto, direction: IPerfDir, @@ -196,6 +196,7 @@ def _attach_and_detach_multi_ues( warning_as_errors: bool = True, reattach_count: int = 1, ue_stop_timeout=30, + ue_settle_time=0, ): logging.info("Attach / Detach Test") @@ -220,6 +221,8 @@ def _attach_and_detach_multi_ues( ue_array_to_iperf = ue_array[::2] ue_array_to_attach = ue_array[1::2] + iperf_duration = reattach_count * ((ue_stop_timeout * len(ue_array_to_attach)) + ue_settle_time) + # Starting iperf in half of the UEs iperf_array = [] for ue_stub in ue_array_to_iperf: @@ -241,6 +244,7 @@ def _attach_and_detach_multi_ues( # Stop and attach half of the UEs while the others are connecting and doing iperf for _ in range(reattach_count): ue_stop(ue_array_to_attach, retina_data, ue_stop_timeout=ue_stop_timeout) + sleep(ue_settle_time) ue_attach_info_dict = ue_start_and_attach(ue_array_to_attach, gnb, fivegc) # final stop will be triggered by teardown From 8d175a047bfdd0aceb00a9d190bf92b6324e2c9e Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 7 Nov 2024 17:41:51 +0000 Subject: [PATCH 64/72] rlc: add unit test for stale status reports --- tests/unittests/rlc/rlc_rx_am_test.cpp | 63 +++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/tests/unittests/rlc/rlc_rx_am_test.cpp b/tests/unittests/rlc/rlc_rx_am_test.cpp index 97fff259fe..08f16703e6 100644 --- a/tests/unittests/rlc/rlc_rx_am_test.cpp +++ b/tests/unittests/rlc/rlc_rx_am_test.cpp @@ -400,6 +400,14 @@ class rlc_rx_am_test : public ::testing::Test, public ::testing::WithParamInterf tester->sdu_queue.pop(); } + void tick_all(uint32_t ticks) + { + for (uint i = 0; i < ticks; ++i) { + timers.tick(); + ue_worker.run_pending_tasks(); + } + } + void tick() { timers.tick(); @@ -644,7 +652,7 @@ TEST_P(rlc_rx_am_test, rx_polling_bit_sn_outside_rx_window) /// Verify proper handling of polling bit for PDU duplicates inside the Rx window: The status-required state shall still /// change but the duplicated SDU shall be discarded -TEST_P(rlc_rx_am_test, rx_polling_bit_sdu_duplicate) +TEST_P(rlc_rx_am_test, rx_sdu_duplicate_with_one_polling_bit) { EXPECT_FALSE(rlc->status_report_required()); @@ -680,8 +688,61 @@ TEST_P(rlc_rx_am_test, rx_polling_bit_sdu_duplicate) // Check if polling bit was considered, despite duplicate SN EXPECT_TRUE(rlc->status_report_required()); + auto& status = rlc->get_status_pdu(); + EXPECT_EQ(status.ack_sn, 0); + EXPECT_EQ(tester->status_trigger_counter, 1); + + // Check if duplicate SDU was properly ignored + ASSERT_EQ(tester->sdu_queue.size(), 0); +} + +/// Verify proper handling of polling bit for PDU duplicates inside the Rx window: The status-required state shall still +/// change but the duplicated SDU shall be discarded +TEST_P(rlc_rx_am_test, rx_sdu_duplicate_two_polling_bits) +{ + EXPECT_FALSE(rlc->status_report_required()); + + uint32_t sn_state = 0; // one SDU inside rx window and duplicate will be outside. + uint32_t sdu_size = 4; + + // Create SDU and PDU with full SDU + std::list> pdu_list = {}; + byte_buffer sdu; + ASSERT_NO_FATAL_FAILURE(create_pdus(pdu_list, sdu, sn_state, sdu_size, sdu_size, sn_state)); + sn_state++; + + // Set polling bit of PDUs + *(pdu_list.front().begin()) |= 0b01000000; // set P = 1; + + // Push into RLC + byte_buffer_slice pdu = byte_buffer_slice::create(pdu_list.front()).value(); + rlc->handle_pdu(std::move(pdu)); + + // Check if polling bit has not changed + EXPECT_TRUE(rlc->status_report_required()); + auto& status1 = rlc->get_status_pdu(); + EXPECT_EQ(status1.ack_sn, 1); EXPECT_EQ(tester->status_trigger_counter, 1); + // Check if SDU was properly unpacked and forwarded + ASSERT_EQ(tester->sdu_queue.size(), 1); + EXPECT_EQ(tester->sdu_queue.front().length(), sdu_size); + EXPECT_EQ(tester->sdu_queue.front(), sdu); + tester->sdu_queue.pop(); + + // Let t-StatusProhibit expire + tick_all(config.t_status_prohibit + 1); + + // Push into RLC + pdu = byte_buffer_slice::create(pdu_list.front()).value(); + rlc->handle_pdu(std::move(pdu)); + + // Check if polling bit was considered, despite duplicate SN + EXPECT_TRUE(rlc->status_report_required()); + auto& status2 = rlc->get_status_pdu(); + EXPECT_EQ(status2.ack_sn, 1); // Check the status report is not stale. + EXPECT_EQ(tester->status_trigger_counter, 2); + // Check if duplicate SDU was properly ignored ASSERT_EQ(tester->sdu_queue.size(), 0); } From 2490c56b528571acd2777fc72fd0f94414aea612 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 4 Nov 2024 15:29:20 +0100 Subject: [PATCH 65/72] rlc_rx_am: remove mutex around swap of shared/cached status reports... ...and replace it with atomic exchange --- lib/rlc/rlc_rx_am_entity.cpp | 16 ++++++++-------- lib/rlc/rlc_rx_am_entity.h | 7 ++----- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 8859f353eb..2102846ddb 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -68,9 +68,10 @@ rlc_rx_am_entity::rlc_rx_am_entity(gnb_du_id_t gnb_du_id, max_nof_sn_per_status_report = window_size(to_number(cfg.sn_field_length)); } - // initialize status report - status_cached->ack_sn = st.rx_next_highest; - status_report_size.store(status_cached->get_packed_size(), std::memory_order_relaxed); + // initialize cached status report + rlc_am_status_pdu& init_cached_status = *status_cached.load(std::memory_order_relaxed); + init_cached_status.ack_sn = st.rx_next_highest; + status_report_size.store(init_cached_status.get_packed_size(), std::memory_order_relaxed); logger.log_info("RLC AM configured. {}", cfg); } @@ -626,9 +627,9 @@ void rlc_rx_am_entity::refresh_status_report() void rlc_rx_am_entity::store_status_report() { - std::unique_lock lock(status_report_mutex); - std::swap(status_builder, status_cached); - status_report_size.store(status_cached->get_packed_size(), std::memory_order_relaxed); + // Minor inacurracy between status_report_size and status_cached is tolerated here + status_report_size.store(status_builder->get_packed_size(), std::memory_order_relaxed); + status_builder = status_cached.exchange(status_builder, std::memory_order_relaxed); } rlc_am_status_pdu& rlc_rx_am_entity::get_status_pdu() @@ -640,8 +641,7 @@ rlc_am_status_pdu& rlc_rx_am_entity::get_status_pdu() } status_prohibit_timer_is_running.store(true, std::memory_order_relaxed); } - std::unique_lock lock(status_report_mutex); - std::swap(status_shared, status_cached); + status_shared = status_cached.exchange(status_shared, std::memory_order_relaxed); return *status_shared; } diff --git a/lib/rlc/rlc_rx_am_entity.h b/lib/rlc/rlc_rx_am_entity.h index f9a997ec74..6794cc79fd 100644 --- a/lib/rlc/rlc_rx_am_entity.h +++ b/lib/rlc/rlc_rx_am_entity.h @@ -18,7 +18,7 @@ #include "srsran/support/sdu_window.h" #include "srsran/support/timers.h" #include "fmt/format.h" -#include +#include #include namespace srsran { @@ -110,7 +110,7 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider /// Status report for (re)-building rlc_am_status_pdu* status_builder = &status_buf[0]; /// Status report for caching - rlc_am_status_pdu* status_cached = &status_buf[1]; + std::atomic status_cached = &status_buf[1]; /// Status report for sharing rlc_am_status_pdu* status_shared = &status_buf[2]; @@ -118,9 +118,6 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider std::atomic status_report_size; std::atomic status_prohibit_timer_is_running{false}; - /// Mutex for controlled access to the cached status report, e.g. read by the Tx entity in a different executor - std::mutex status_report_mutex; - /// \brief t-StatusProhibit /// This timer is used by the receiving side of an AM RLC entity in order to prohibit transmission of a STATUS PDU /// (see sub clause 5.3.4). From 153888b00c4621dd23a78d4728321e80afa33c0f Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 5 Nov 2024 06:01:18 +0100 Subject: [PATCH 66/72] rlc_rx_am: assert lock-free atomic pointer to cached status PDU in constructor --- lib/rlc/rlc_rx_am_entity.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 2102846ddb..3dbd1c617c 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -69,6 +69,8 @@ rlc_rx_am_entity::rlc_rx_am_entity(gnb_du_id_t gnb_du_id, } // initialize cached status report + static_assert(std::atomic::is_always_lock_free, + "RLC RX AM: atomic must always be lock free"); rlc_am_status_pdu& init_cached_status = *status_cached.load(std::memory_order_relaxed); init_cached_status.ack_sn = st.rx_next_highest; status_report_size.store(init_cached_status.get_packed_size(), std::memory_order_relaxed); From 32d279b497f69145a2ffe7359f277004b6d3af93 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 8 Nov 2024 13:18:58 +0100 Subject: [PATCH 67/72] rlc_rx_am: adjust memory order of status_builder and status_report_size --- lib/rlc/rlc_rx_am_entity.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 3dbd1c617c..7f2dc5b5a8 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -630,8 +630,9 @@ void rlc_rx_am_entity::refresh_status_report() void rlc_rx_am_entity::store_status_report() { // Minor inacurracy between status_report_size and status_cached is tolerated here - status_report_size.store(status_builder->get_packed_size(), std::memory_order_relaxed); + uint32_t latest_status_report_size = status_builder->get_packed_size(); status_builder = status_cached.exchange(status_builder, std::memory_order_relaxed); + status_report_size.store(latest_status_report_size, std::memory_order_release); } rlc_am_status_pdu& rlc_rx_am_entity::get_status_pdu() @@ -649,7 +650,7 @@ rlc_am_status_pdu& rlc_rx_am_entity::get_status_pdu() uint32_t rlc_rx_am_entity::get_status_pdu_length() { - return status_report_size.load(std::memory_order_relaxed); + return status_report_size.load(std::memory_order_acquire); } bool rlc_rx_am_entity::status_report_required() From ad7c0482c935b210f24d9bfc398480a248fcae09 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 8 Nov 2024 13:53:48 +0100 Subject: [PATCH 68/72] rlc_rx_am: replace assert with error message in case of non-atomic status PDU exchange --- lib/rlc/rlc_rx_am_entity.cpp | 5 +++-- tests/unittests/rlc/rlc_rx_am_test.cpp | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 7f2dc5b5a8..86776e65a4 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -69,8 +69,9 @@ rlc_rx_am_entity::rlc_rx_am_entity(gnb_du_id_t gnb_du_id, } // initialize cached status report - static_assert(std::atomic::is_always_lock_free, - "RLC RX AM: atomic must always be lock free"); + if (!std::atomic::is_always_lock_free) { + logger.log_error("The status PDU exchange is not lock free. TX real-time performance can be impaired."); + } rlc_am_status_pdu& init_cached_status = *status_cached.load(std::memory_order_relaxed); init_cached_status.ack_sn = st.rx_next_highest; status_report_size.store(init_cached_status.get_packed_size(), std::memory_order_relaxed); diff --git a/tests/unittests/rlc/rlc_rx_am_test.cpp b/tests/unittests/rlc/rlc_rx_am_test.cpp index 08f16703e6..9b2e1ffa76 100644 --- a/tests/unittests/rlc/rlc_rx_am_test.cpp +++ b/tests/unittests/rlc/rlc_rx_am_test.cpp @@ -11,6 +11,7 @@ #include "lib/rlc/rlc_rx_am_entity.h" #include "tests/test_doubles/pdcp/pdcp_pdu_generator.h" #include "srsran/support/executors/manual_task_worker.h" +#include "srsran/support/test_utils.h" #include #include #include @@ -69,6 +70,21 @@ class rlc_rx_am_test_frame : public rlc_rx_upper_layer_data_notifier, void report_metrics(const rlc_metrics& metrics) override {} }; +srsran::log_sink_spy& test_spy = []() -> srsran::log_sink_spy& { + if (!srslog::install_custom_sink( + srsran::log_sink_spy::name(), + std::unique_ptr(new srsran::log_sink_spy(srslog::get_default_log_formatter())))) { + report_fatal_error("Unable to create logger spy"); + } + auto* spy = static_cast(srslog::find_sink(srsran::log_sink_spy::name())); + if (spy == nullptr) { + report_fatal_error("Unable to create logger spy"); + } + + srslog::fetch_basic_logger("RLC", *spy, true); + return *spy; +}(); + /// Fixture class for RLC AM Rx tests. /// It requires TEST_P() and INSTANTIATE_TEST_SUITE_P() to create/spawn tests for each config class rlc_rx_am_test : public ::testing::Test, public ::testing::WithParamInterface @@ -80,6 +96,9 @@ class rlc_rx_am_test : public ::testing::Test, public ::testing::WithParamInterf srslog::init(); logger.set_level(srslog::basic_levels::debug); + // reset log spy + test_spy.reset_counters(); + // init RLC logger srslog::fetch_basic_logger("RLC", false).set_level(srslog::basic_levels::debug); srslog::fetch_basic_logger("RLC", false).set_hex_dump_max_size(100); @@ -432,6 +451,9 @@ class rlc_rx_am_test_with_limit : public rlc_rx_am_test TEST_P(rlc_rx_am_test, create_new_entity) { EXPECT_NE(rlc, nullptr); + // No warnings or error during construction + EXPECT_EQ(test_spy.get_warning_counter(), 0); + EXPECT_EQ(test_spy.get_error_counter(), 0); } /// Verify the status report from a freshly created instance From b98dd7474a373e3d152aa636f6f206ab83f6df24 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 8 Nov 2024 14:33:50 +0100 Subject: [PATCH 69/72] rlc_rx_am: rename symbols involved in status PDU exchange --- lib/rlc/rlc_rx_am_entity.cpp | 28 ++++++++++++++-------------- lib/rlc/rlc_rx_am_entity.h | 12 ++++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/rlc/rlc_rx_am_entity.cpp b/lib/rlc/rlc_rx_am_entity.cpp index 86776e65a4..31554e3fe6 100644 --- a/lib/rlc/rlc_rx_am_entity.cpp +++ b/lib/rlc/rlc_rx_am_entity.cpp @@ -72,9 +72,9 @@ rlc_rx_am_entity::rlc_rx_am_entity(gnb_du_id_t gnb_du_id, if (!std::atomic::is_always_lock_free) { logger.log_error("The status PDU exchange is not lock free. TX real-time performance can be impaired."); } - rlc_am_status_pdu& init_cached_status = *status_cached.load(std::memory_order_relaxed); - init_cached_status.ack_sn = st.rx_next_highest; - status_report_size.store(init_cached_status.get_packed_size(), std::memory_order_relaxed); + rlc_am_status_pdu& init_status_for_exchange = *status_for_exchange.load(std::memory_order_relaxed); + init_status_for_exchange.ack_sn = st.rx_next_highest; + status_report_size.store(init_status_for_exchange.get_packed_size(), std::memory_order_relaxed); logger.log_info("RLC AM configured. {}", cfg); } @@ -538,7 +538,7 @@ expected rlc_rx_am_entity::reassemble_sdu(rlc_rx_am_sdu_info& void rlc_rx_am_entity::refresh_status_report() { - status_builder->reset(); + status_owned_by_writer->reset(); /* * - for the RLC SDUs with SN such that RX_Next <= SN < RX_Highest_Status that has not been completely * received yet, in increasing SN order of RLC SDUs and increasing byte segment order within RLC SDUs, @@ -562,7 +562,7 @@ void rlc_rx_am_entity::refresh_status_report() nack.nack_sn = i; nack.has_so = false; logger.log_debug("Adding nack={}.", nack); - status_builder->push_nack(nack); + status_owned_by_writer->push_nack(nack); } else if (not rx_window[i].fully_received) { srsran_assert(std::holds_alternative(rx_window[i].sdu_data), "Invalid sdu_data variant of incomplete SDU in rx_window. sn={}", @@ -582,7 +582,7 @@ void rlc_rx_am_entity::refresh_status_report() nack.so_start = last_so; nack.so_end = segm->so - 1; // set to last missing byte logger.log_debug("Adding nack={}.", nack); - status_builder->push_nack(nack); + status_owned_by_writer->push_nack(nack); // Sanity check if (nack.so_start > nack.so_end) { @@ -611,7 +611,7 @@ void rlc_rx_am_entity::refresh_status_report() nack.so_start = last_so; nack.so_end = rlc_am_status_nack::so_end_of_sdu; logger.log_debug("Adding nack={}.", nack); - status_builder->push_nack(nack); + status_owned_by_writer->push_nack(nack); // Sanity check srsran_assert(nack.so_start <= nack.so_end, "Invalid segment offsets in nack={}.", nack); } @@ -623,16 +623,16 @@ void rlc_rx_am_entity::refresh_status_report() * - set the ACK_SN to the SN of the next not received RLC SDU which is not * indicated as missing in the resulting STATUS PDU. */ - status_builder->ack_sn = stop_sn; - logger.log_debug("Refreshed status_report. {}", *status_builder); + status_owned_by_writer->ack_sn = stop_sn; + logger.log_debug("Refreshed status_report. {}", *status_owned_by_writer); store_status_report(); } void rlc_rx_am_entity::store_status_report() { - // Minor inacurracy between status_report_size and status_cached is tolerated here - uint32_t latest_status_report_size = status_builder->get_packed_size(); - status_builder = status_cached.exchange(status_builder, std::memory_order_relaxed); + // Minor inacurracy between status_report_size and status_for_exchange is tolerated here + uint32_t latest_status_report_size = status_owned_by_writer->get_packed_size(); + status_owned_by_writer = status_for_exchange.exchange(status_owned_by_writer, std::memory_order_relaxed); status_report_size.store(latest_status_report_size, std::memory_order_release); } @@ -645,8 +645,8 @@ rlc_am_status_pdu& rlc_rx_am_entity::get_status_pdu() } status_prohibit_timer_is_running.store(true, std::memory_order_relaxed); } - status_shared = status_cached.exchange(status_shared, std::memory_order_relaxed); - return *status_shared; + status_owned_by_reader = status_for_exchange.exchange(status_owned_by_reader, std::memory_order_relaxed); + return *status_owned_by_reader; } uint32_t rlc_rx_am_entity::get_status_pdu_length() diff --git a/lib/rlc/rlc_rx_am_entity.h b/lib/rlc/rlc_rx_am_entity.h index 6794cc79fd..6cd9e4b625 100644 --- a/lib/rlc/rlc_rx_am_entity.h +++ b/lib/rlc/rlc_rx_am_entity.h @@ -107,12 +107,12 @@ class rlc_rx_am_entity : public rlc_rx_entity, public rlc_rx_am_status_provider /// Pre-allocated status reports for (re)-building, caching, and sharing with TX entity std::array status_buf; - /// Status report for (re)-building - rlc_am_status_pdu* status_builder = &status_buf[0]; - /// Status report for caching - std::atomic status_cached = &status_buf[1]; - /// Status report for sharing - rlc_am_status_pdu* status_shared = &status_buf[2]; + /// Status report owned by writer for (re)-building + rlc_am_status_pdu* status_owned_by_writer = &status_buf[0]; + /// Status report for exchange that is accessed by writer and reader + std::atomic status_for_exchange = &status_buf[1]; + /// Status report owned by reader for transmission + rlc_am_status_pdu* status_owned_by_reader = &status_buf[2]; /// Size of the cached status report std::atomic status_report_size; From 78dad61d646c9c2670dedca4a5b30da877f12eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 7 Nov 2024 17:21:49 +0100 Subject: [PATCH 70/72] ci: adjust pages size --- .gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7ea0b741cf..61f52f941d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -491,6 +491,14 @@ pages: cd .. - mkdir public/doxygen - rsync -a build/docs/html/ public/doxygen/ + - | + # Remove bigger file if size is bigger than 900MB + while [ $(du -s public | awk '{print $1}') -gt 921600 ]; do + file_to_remove=$(find public -type f ! -name "*.html" ! -name "*.js" -exec ls -l {} + | sort -k5 -n -r | awk 'NR==1' | awk '{print $NF}') + file_size=$(du -h "$file_to_remove" | awk '{print $1}') + echo "Removing file: $file_to_remove (Size: $file_size)" + rm -f "$file_to_remove" + done after_script: - | if [ $CI_JOB_STATUS = "failed" ]; then From 3e5530ce1ef5341b4dbdf4d62d3c21e449e15d8b Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 7 Nov 2024 12:04:46 +0100 Subject: [PATCH 71/72] phy: extend PxSCH BLER test to multiple layers --- .../channel_processors/pxsch_bler_test.cpp | 10 +- .../pxsch_bler_test_channel_emulator.cpp | 97 ++++++++++++------- .../pxsch_bler_test_channel_emulator.h | 12 ++- .../pxsch_bler_test_factories.cpp | 19 ++-- 4 files changed, 89 insertions(+), 49 deletions(-) diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp index 1726b5b3af..e5f96277c6 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test.cpp @@ -36,7 +36,6 @@ using namespace srsran; static constexpr subcarrier_spacing scs = subcarrier_spacing::kHz30; static constexpr uint16_t rnti = 0x1234; static constexpr unsigned bwp_start_rb = 0; -static constexpr unsigned nof_layers = 1; static constexpr unsigned nof_ofdm_symbols = 14; static const symbol_slot_mask dmrs_symbol_mask = {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; static constexpr unsigned nof_ldpc_iterations = 10; @@ -56,6 +55,7 @@ static std::string channel_fading_distribution = "uniform- static float sinr_dB = 60.0F; static unsigned nof_corrupted_re_per_ofdm_symbol = 0; static unsigned nof_rx_ports = 2; +static unsigned nof_layers = 1; static unsigned bwp_size_rb = 273; static pusch_mcs_table mcs_table = pusch_mcs_table::qam64; static sch_mcs_index mcs_index = 20; @@ -330,6 +330,7 @@ class pxsch_bler_test channel_fading_distribution, sinr_dB, nof_corrupted_re_per_ofdm_symbol, + nof_layers, nof_rx_ports, MAX_RB * NRE, nof_ofdm_symbols, @@ -502,6 +503,8 @@ static void usage(std::string_view prog) fmt::print("\t-S SINR. [Default {}]\n", sinr_dB); fmt::print("\t-N Number of corrupted RE per OFDM symbol. [Default {}]\n", nof_corrupted_re_per_ofdm_symbol); fmt::print("\t-P Number of receive ports. [Default {}]\n", nof_rx_ports); + fmt::print("\t-L Number of transmit layers. It must not exceed the number of ports. [Default {}]\n", + nof_layers); fmt::print("\t-B Number of allocated PRBs (same as BWP size). [Default {}]\n", bwp_size_rb); fmt::print("\t-M MCS table. [Default {}]\n", mcs_table); fmt::print("\t-m MCS index. [Default {}]\n", mcs_index); @@ -515,7 +518,7 @@ static void usage(std::string_view prog) static void parse_args(int argc, char** argv) { int opt = 0; - while ((opt = getopt(argc, argv, "C:F:S:N:P:R:B:M:m:DT:vh")) != -1) { + while ((opt = getopt(argc, argv, "C:F:S:N:P:L:R:B:M:m:DT:vh")) != -1) { switch (opt) { case 'C': if (optarg != nullptr) { @@ -539,6 +542,9 @@ static void parse_args(int argc, char** argv) case 'P': nof_rx_ports = std::strtol(optarg, nullptr, 10); break; + case 'L': + nof_layers = std::strtol(optarg, nullptr, 10); + break; case 'B': bwp_size_rb = std::strtol(optarg, nullptr, 10); break; diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.cpp index 936fb7e72d..48f1da8928 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.cpp @@ -79,6 +79,7 @@ channel_emulator::channel_emulator(std::string delay_profile, std::string fading_distribution_, float sinr_dB, unsigned nof_corrupted_re_per_symbol, + unsigned nof_tx_ports, unsigned nof_rx_ports, unsigned nof_subc, unsigned nof_symbols, @@ -86,7 +87,7 @@ channel_emulator::channel_emulator(std::string delay_profile, subcarrier_spacing scs, task_executor& executor_) : nof_ofdm_symbols(nof_symbols), - freq_domain_channel({nof_subc, nof_rx_ports}), + freq_domain_channel({nof_subc, nof_rx_ports, nof_tx_ports}), temp_channel(nof_subc), emulators(max_nof_threads, sinr_dB, nof_corrupted_re_per_symbol, nof_subc), executor(executor_) @@ -144,42 +145,53 @@ channel_emulator::channel_emulator(std::string delay_profile, void channel_emulator::run(resource_grid_writer& rx_grid, const resource_grid_reader& tx_grid) { unsigned nof_rx_ports = freq_domain_channel.get_dimension_size(1); + unsigned nof_tx_ports = freq_domain_channel.get_dimension_size(2); unsigned nof_taps = taps_channel_response.get_dimension_size(1); // Channel emulator. std::atomic count = {0}, completed = {0}; for (unsigned i_rx_port = 0; i_rx_port != nof_rx_ports; ++i_rx_port) { - // Get view of the frequency domain response for this port. - span chan_freq_respone = freq_domain_channel.get_view({i_rx_port}); - - // Generate frequency domain response for the entire slot. - srsvec::zero(chan_freq_respone); - for (unsigned i_tap = 0; i_tap != nof_taps; ++i_tap) { - // Select tap from the fading distribution. - cf_t tap; - switch (fading_distribution) { - case rayleigh: - tap = dist_rayleigh(rgen); - break; - case uniform_phase: - tap = std::polar(1.0F, dist_uniform_phase(rgen)); - break; - case invalid_distribution: - tap = std::numeric_limits::quiet_NaN(); - break; - } + // Generate frequency domain channel response for each transmit port. + for (unsigned i_tx_port = 0; i_tx_port != nof_tx_ports; ++i_tx_port) { + // Get view of the frequency domain response for this port. + span chan_freq_respone = freq_domain_channel.get_view({i_rx_port, i_tx_port}); + + // Generate frequency domain response for the entire slot. + for (unsigned i_tap = 0; i_tap != nof_taps; ++i_tap) { + // Select intermediate tap frequency domain buffer. Use final buffer for the first tap and skip accumulation. + span tap_channel = temp_channel; + if (i_tap == 0) { + tap_channel = chan_freq_respone; + } + + // Select tap from the fading distribution. + cf_t tap; + switch (fading_distribution) { + case rayleigh: + tap = dist_rayleigh(rgen); + break; + case uniform_phase: + tap = std::polar(1.0F, dist_uniform_phase(rgen)); + break; + case invalid_distribution: + tap = std::numeric_limits::quiet_NaN(); + break; + } - // Multiply tap frequency response by a fading distribution tap. - srsvec::sc_prod(taps_channel_response.get_view({i_tap}), tap, temp_channel); + // Multiply tap frequency response by a fading distribution tap. + srsvec::sc_prod(taps_channel_response.get_view({i_tap}), tap, tap_channel); - // Accumulate tap frequency response. - srsvec::add(chan_freq_respone, temp_channel, chan_freq_respone); + // Accumulate tap frequency response. Bypass accumulation for the first tap. + if (i_tap != 0) { + srsvec::add(chan_freq_respone, tap_channel, chan_freq_respone); + } + } } // Run channel for each symbol with the same frequency response. for (unsigned i_symbol = 0; i_symbol != nof_ofdm_symbols; ++i_symbol) { - bool success = executor.execute([this, &rx_grid, &tx_grid, chan_freq_respone, i_rx_port, i_symbol, &completed]() { - emulators.get().run(rx_grid, tx_grid, chan_freq_respone, i_rx_port, i_symbol); + bool success = executor.execute([this, &rx_grid, &tx_grid, i_rx_port, i_symbol, &completed]() { + emulators.get().run(rx_grid, tx_grid, freq_domain_channel, i_rx_port, i_symbol); ++completed; }); report_fatal_error_if_not(success, "Failed to enqueue concurrent channel emulate."); @@ -195,21 +207,36 @@ void channel_emulator::run(resource_grid_writer& rx_grid, const resource_grid_re void channel_emulator::concurrent_channel_emulator::run(resource_grid_writer& rx_grid, const resource_grid_reader& tx_grid, - span freq_response, - unsigned i_port, + const tensor<3, cf_t>& freq_response, + unsigned i_rx_port, unsigned i_symbol) { using namespace std::complex_literals; + unsigned nof_tx_ports = freq_response.get_dimension_size(2); - // Get OFDM symbol. - tx_grid.get(temp_ofdm_symbol, 0, i_symbol, 0); + // For each transmit port. + for (unsigned i_tx_port = 0; i_tx_port != nof_tx_ports; ++i_tx_port) { + // Select temporary buffer. + span single_ofdm_symbol = temp_single_ofdm_symbol; + if (i_tx_port == 0) { + single_ofdm_symbol = temp_ofdm_symbol; + } - // Apply frequency domain fading channel. - srsvec::prod(temp_ofdm_symbol, freq_response, temp_ofdm_symbol); + // Get OFDM symbol. + tx_grid.get(single_ofdm_symbol, i_tx_port, i_symbol, 0); + + // Apply frequency domain fading channel. + srsvec::prod(single_ofdm_symbol, freq_response.get_view({i_rx_port, i_tx_port}), single_ofdm_symbol); + + // Skip accumulating for the first transmit port. + if (i_tx_port != 0) { + srsvec::add(temp_ofdm_symbol, single_ofdm_symbol, temp_ofdm_symbol); + } + } // Apply AWGN. - std::generate(temp_awgn.begin(), temp_awgn.end(), [this]() { return dist_awgn(rgen); }); - srsvec::add(temp_ofdm_symbol, temp_awgn, temp_ofdm_symbol); + std::generate(temp_single_ofdm_symbol.begin(), temp_single_ofdm_symbol.end(), [this]() { return dist_awgn(rgen); }); + srsvec::add(temp_ofdm_symbol, temp_single_ofdm_symbol, temp_ofdm_symbol); // Corrupt REs. std::set corrupted_i_subc; @@ -225,5 +252,5 @@ void channel_emulator::concurrent_channel_emulator::run(resource_grid_writer& } // Write the OFDM symbol back to the grid. - rx_grid.put(i_port, i_symbol, 0, temp_ofdm_symbol); + rx_grid.put(i_rx_port, i_symbol, 0, temp_ofdm_symbol); } diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.h b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.h index bf9d791786..b38d7eb18a 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.h +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_channel_emulator.h @@ -43,6 +43,7 @@ class channel_emulator /// uniform-phase. /// \param[in] sinr_dB Signal-to-Interference-plus-Noise Ratio. /// \param[in] nof_corrupted_re_per_symbol Number of corrupted RE per OFDM symbol. Set to zero for no corrupted RE. + /// \param[in] nof_tx_ports Number of transmit ports. /// \param[in] nof_rx_ports Number of receive ports. /// \param[in] nof_subc Number of resource grid subcarriers. /// \param[in] nof_symbols Number of OFDM symbols per slot. @@ -53,6 +54,7 @@ class channel_emulator std::string fading_distribution, float sinr_dB, unsigned nof_corrupted_re_per_symbol, + unsigned nof_tx_ports, unsigned nof_rx_ports, unsigned nof_subc, unsigned nof_symbols, @@ -77,7 +79,7 @@ class channel_emulator dist_corrupted_re(0, nof_subc - 1), nof_corrupted_re(nof_corrupted_re_), temp_ofdm_symbol(nof_subc), - temp_awgn(nof_subc) + temp_single_ofdm_symbol(nof_subc) { } @@ -89,7 +91,7 @@ class channel_emulator /// \param[in] i_symbol OFDM symbol index within the slot. void run(resource_grid_writer& rx_grid, const resource_grid_reader& tx_grid, - span freq_response, + const tensor<3, cf_t>& freq_response, unsigned i_port, unsigned i_symbol); @@ -106,8 +108,8 @@ class channel_emulator unsigned nof_corrupted_re; /// Temporary OFDM frequency domain symbol. std::vector temp_ofdm_symbol; - /// Temporary generated noise for adding to an OFDM symbol. - std::vector temp_awgn; + /// Temporary single OFDM frequency domain symbol. + std::vector temp_single_ofdm_symbol; }; enum { @@ -124,7 +126,7 @@ class channel_emulator /// Uniform real distribution for phase. std::uniform_real_distribution dist_uniform_phase = std::uniform_real_distribution(-M_PI, M_PI); /// Temporary channel sum. - dynamic_tensor<2, cf_t> freq_domain_channel; + dynamic_tensor<3, cf_t> freq_domain_channel; /// Temporary channel. std::vector temp_channel; /// Frequency response of each of the channel taps. diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp index 925969b5a7..9e5d3fd61f 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp @@ -9,6 +9,7 @@ */ #include "pxsch_bler_test_factories.h" +#include "srsran/phy/upper/channel_processors/pusch/pusch_processor_phy_capabilities.h" #if defined(HWACC_PDSCH_ENABLED) && defined(HWACC_PUSCH_ENABLED) #include "srsran/hal/dpdk/bbdev/bbdev_acc.h" #include "srsran/hal/dpdk/bbdev/bbdev_acc_factory.h" @@ -182,6 +183,8 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto bool dec_enable_early_stop, const std::string& pxsch_type) { + pusch_processor_phy_capabilities pusch_processor_phy_cap = get_pusch_processor_phy_capabilities(); + std::shared_ptr dft_proc_factory = create_dft_processor_factory_fftw_slow(); report_fatal_error_if_not(dft_proc_factory, "Failed to create factory."); @@ -274,13 +277,15 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto report_fatal_error_if_not(uci_dec_factory, "Failed to create factory."); pusch_processor_factory_sw_configuration pusch_proc_factory_config; - pusch_proc_factory_config.estimator_factory = chan_est_factory; - pusch_proc_factory_config.demodulator_factory = pusch_demod_factory; - pusch_proc_factory_config.demux_factory = demux_factory; - pusch_proc_factory_config.decoder_factory = pusch_dec_factory; - pusch_proc_factory_config.uci_dec_factory = uci_dec_factory; - pusch_proc_factory_config.ch_estimate_dimensions = { - MAX_NOF_PRBS, MAX_NSYMB_PER_SLOT, pusch_constants::MAX_NOF_RX_PORTS, 1}; + pusch_proc_factory_config.estimator_factory = chan_est_factory; + pusch_proc_factory_config.demodulator_factory = pusch_demod_factory; + pusch_proc_factory_config.demux_factory = demux_factory; + pusch_proc_factory_config.decoder_factory = pusch_dec_factory; + pusch_proc_factory_config.uci_dec_factory = uci_dec_factory; + pusch_proc_factory_config.ch_estimate_dimensions = {.nof_prb = MAX_NOF_PRBS, + .nof_symbols = MAX_NSYMB_PER_SLOT, + .nof_rx_ports = pusch_constants::MAX_NOF_RX_PORTS, + .nof_tx_layers = pusch_processor_phy_cap.max_nof_layers}; pusch_proc_factory_config.dec_nof_iterations = nof_ldpc_iterations; pusch_proc_factory_config.dec_enable_early_stop = dec_enable_early_stop; pusch_proc_factory_config.max_nof_concurrent_threads = max_nof_threads; From 43f02baa888b4d2134c7cb1c204de3905e8d7355 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Fri, 8 Nov 2024 17:33:06 +0100 Subject: [PATCH 72/72] ci: move viavi tests --- .gitlab/ci/e2e.yml | 3 ++- tests/e2e/tests/viavi/test_declaration.yml | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index fa5f490032..16964687f8 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -471,7 +471,8 @@ viavi: - KEYWORDS: [ "ideal and 1UE", - "ideal and 32UE and not experimental", + "ideal and 32UE and not experimental and not tdd", + "tdd", "fading and 1UE", "fading and 32UE", "birth-death and 1UE", diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 97147a7e73..5131ebb296 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -154,7 +154,7 @@ tests: test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" - id: "32UE ideal UDP attach-detach with traffic DDDSU" + id: "32UE ideal UDP attach-detach with traffic tdd DDDSU" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 enable_qos_viavi: false @@ -169,7 +169,7 @@ tests: test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" - id: "32UE ideal UDP attach-detach with traffic UL Heavy 7u2d" + id: "32UE ideal UDP attach-detach with traffic tdd UL Heavy 7u2d" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 enable_qos_viavi: false @@ -184,7 +184,7 @@ tests: test_name: "32UE ideal UDP attach-detach with traffic High brate" test_timeout: *test_timeout gnb_extra_commands: "log --ngap_level=debug --metrics_level=info metrics --rlc_report_period=1000" - id: "32UE ideal UDP attach-detach with traffic UL Heavy 6u3d" + id: "32UE ideal UDP attach-detach with traffic tdd UL Heavy 6u3d" max_pdschs_per_slot: 1 max_puschs_per_slot: 4 enable_qos_viavi: false