From 99c36774223b37dea7f35aa9b793b574d23b4008 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 22 Nov 2024 18:53:13 +0100 Subject: [PATCH 001/227] asn1,nrppa: remove nrppa asn1 --- include/srsran/asn1/nrppa/nrppa.h | 11861 ---------- lib/asn1/CMakeLists.txt | 6 - lib/asn1/nrppa/nrppa.cpp | 34158 ---------------------------- 3 files changed, 46025 deletions(-) delete mode 100644 include/srsran/asn1/nrppa/nrppa.h delete mode 100644 lib/asn1/nrppa/nrppa.cpp diff --git a/include/srsran/asn1/nrppa/nrppa.h b/include/srsran/asn1/nrppa/nrppa.h deleted file mode 100644 index b4ee0c85ab..0000000000 --- a/include/srsran/asn1/nrppa/nrppa.h +++ /dev/null @@ -1,11861 +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. - * - */ - -/******************************************************************************* - * - * 3GPP TS ASN1 NRPPA v17.8.0 (2024-08) - * - ******************************************************************************/ - -#pragma once - -#include "srsran/asn1/asn1_ap_utils.h" - -namespace asn1 { -namespace nrppa { - -/******************************************************************************* - * Constant Definitions - ******************************************************************************/ - -#define ASN1_NRPPA_ID_ERROR_IND 0 -#define ASN1_NRPPA_ID_PRIVATE_MSG 1 -#define ASN1_NRPPA_ID_E_C_ID_MEAS_INITIATION 2 -#define ASN1_NRPPA_ID_E_C_ID_MEAS_FAIL_IND 3 -#define ASN1_NRPPA_ID_E_C_ID_MEAS_REPORT 4 -#define ASN1_NRPPA_ID_E_C_ID_MEAS_TERMINATION 5 -#define ASN1_NRPPA_ID_O_TDOA_INFO_EXCHANGE 6 -#define ASN1_NRPPA_ID_ASSIST_INFO_CTRL 7 -#define ASN1_NRPPA_ID_ASSIST_INFO_FEEDBACK 8 -#define ASN1_NRPPA_ID_POSITIONING_INFO_EXCHANGE 9 -#define ASN1_NRPPA_ID_POSITIONING_INFO_UPD 10 -#define ASN1_NRPPA_ID_MEAS 11 -#define ASN1_NRPPA_ID_MEAS_REPORT 12 -#define ASN1_NRPPA_ID_MEAS_UPD 13 -#define ASN1_NRPPA_ID_MEAS_ABORT 14 -#define ASN1_NRPPA_ID_MEAS_FAIL_IND 15 -#define ASN1_NRPPA_ID_T_RP_INFO_EXCHANGE 16 -#define ASN1_NRPPA_ID_POSITIONING_ACTIVATION 17 -#define ASN1_NRPPA_ID_POSITIONING_DEACTIVATION 18 -#define ASN1_NRPPA_ID_P_RS_CFG_EXCHANGE 19 -#define ASN1_NRPPA_ID_MEAS_PRECFG 20 -#define ASN1_NRPPA_ID_MEAS_ACTIVATION 21 -#define ASN1_NRPPA_MAX_NR_OF_ERRORS 256 -#define ASN1_NRPPA_MAX_CELLIN_RA_NNODE 3840 -#define ASN1_NRPPA_MAX_IDXES_REPORT 64 -#define ASN1_NRPPA_MAX_NO_MEAS 64 -#define ASN1_NRPPA_MAX_CELL_REPORT 9 -#define ASN1_NRPPA_MAX_CELL_REPORT_NR 9 -#define ASN1_NRPPA_MAXNO_OTDO_ATYPES 63 -#define ASN1_NRPPA_MAX_SERV_CELL 5 -#define ASN1_NRPPA_MAX_EUTRA_MEAS 8 -#define ASN1_NRPPA_MAX_GERAN_MEAS 8 -#define ASN1_NRPPA_MAX_NR_MEAS 8 -#define ASN1_NRPPA_MAX_UTRAN_MEAS 8 -#define ASN1_NRPPA_MAX_WLA_NCHS 16 -#define ASN1_NRPPA_MAXNO_FREQ_HOP_BANDS_MINUS_ONE 7 -#define ASN1_NRPPA_MAX_NO_PATH 2 -#define ASN1_NRPPA_MAX_NR_OF_POS_SI_MSG 32 -#define ASN1_NRPPA_MAXNO_ASSIST_INFO_FAIL_LIST_ITEMS 32 -#define ASN1_NRPPA_MAX_NR_OF_SEGMENTS 64 -#define ASN1_NRPPA_MAX_NR_OF_POS_SIBS 32 -#define ASN1_NRPPA_MAX_NO_OF_MEAS_TR_PS 64 -#define ASN1_NRPPA_MAXNO_TR_PS 65535 -#define ASN1_NRPPA_MAXNO_TRP_INFO_TYPES 64 -#define ASN1_NRPPA_MAXNOOF_ANGLE_INFO 65535 -#define ASN1_NRPPA_MAXNOLCS_GCS_TRANSLATION 3 -#define ASN1_NRPPA_MAXNO_BCAST_CELL 16384 -#define ASN1_NRPPA_MAXNO_SRS_TRIGGER_STATES 3 -#define ASN1_NRPPA_MAXNO_SPATIAL_RELATIONS 64 -#define ASN1_NRPPA_MAXNO_POS_MEAS 16384 -#define ASN1_NRPPA_MAXNO_SRS_CARRIERS 32 -#define ASN1_NRPPA_MAXNO_SC_SS 5 -#define ASN1_NRPPA_MAXNO_SRS_RES_FEATURES 64 -#define ASN1_NRPPA_MAXNO_SRS_POS_RES 64 -#define ASN1_NRPPA_MAXNO_SRS_RES_SETS 16 -#define ASN1_NRPPA_MAXNO_SRS_RES_PER_SET 16 -#define ASN1_NRPPA_MAXNO_SRS_POS_RES_SETS 16 -#define ASN1_NRPPA_MAXNO_SRS_POS_RES_PER_SET 16 -#define ASN1_NRPPA_MAX_PRS_RES_SETS 2 -#define ASN1_NRPPA_MAX_PRS_RES_PER_SET 64 -#define ASN1_NRPPA_MAX_NO_SS_BS 255 -#define ASN1_NRPPA_MAXNOOF_PR_SRES_SET 8 -#define ASN1_NRPPA_MAXNOOF_PR_SRES 64 -#define ASN1_NRPPA_MAXNOOF_UL_AO_AS 8 -#define ASN1_NRPPA_MAX_NO_PATH_EXTENDED 8 -#define ASN1_NRPPA_MAXNO_AR_PS 16 -#define ASN1_NRPPA_MAXNO_UE_TE_GS 256 -#define ASN1_NRPPA_MAXNO_TRPTE_GS 8 -#define ASN1_NRPPA_MAX_FREQ_LAYERS 4 -#define ASN1_NRPPA_MAX_NUM_RES_PER_ANGLE 24 -#define ASN1_NRPPA_MAXNO_AZIMUTH_ANGLES 3600 -#define ASN1_NRPPA_MAXNO_ELEVATION_ANGLES 1801 -#define ASN1_NRPPA_MAXNO_PRSTR_PS 256 -#define ASN1_NRPPA_ID_CAUSE 0 -#define ASN1_NRPPA_ID_CRIT_DIAGNOSTICS 1 -#define ASN1_NRPPA_ID_LMF_UE_MEAS_ID 2 -#define ASN1_NRPPA_ID_REPORT_CHARACTERISTICS 3 -#define ASN1_NRPPA_ID_MEAS_PERIODICITY 4 -#define ASN1_NRPPA_ID_MEAS_QUANTITIES 5 -#define ASN1_NRPPA_ID_RAN_UE_MEAS_ID 6 -#define ASN1_NRPPA_ID_E_C_ID_MEAS_RESULT 7 -#define ASN1_NRPPA_ID_OTDOA_CELLS 8 -#define ASN1_NRPPA_ID_OTDOA_INFO_TYPE_GROUP 9 -#define ASN1_NRPPA_ID_OTDOA_INFO_TYPE_ITEM 10 -#define ASN1_NRPPA_ID_MEAS_QUANTITIES_ITEM 11 -#define ASN1_NRPPA_ID_REQUESTED_SRS_TX_CHARACTERISTICS 12 -#define ASN1_NRPPA_ID_CELL_PORTION_ID 14 -#define ASN1_NRPPA_ID_OTHER_RAT_MEAS_QUANTITIES 15 -#define ASN1_NRPPA_ID_OTHER_RAT_MEAS_QUANTITIES_ITEM 16 -#define ASN1_NRPPA_ID_OTHER_RAT_MEAS_RESULT 17 -#define ASN1_NRPPA_ID_WLAN_MEAS_QUANTITIES 19 -#define ASN1_NRPPA_ID_WLAN_MEAS_QUANTITIES_ITEM 20 -#define ASN1_NRPPA_ID_WLAN_MEAS_RESULT 21 -#define ASN1_NRPPA_ID_TDD_CFG_EUTRA_ITEM 22 -#define ASN1_NRPPA_ID_ASSIST_INFO 23 -#define ASN1_NRPPA_ID_BROADCAST 24 -#define ASN1_NRPPA_ID_ASSIST_INFO_FAIL_LIST 25 -#define ASN1_NRPPA_ID_SRSCFG 26 -#define ASN1_NRPPA_ID_MEAS_RESULT 27 -#define ASN1_NRPPA_ID_TRP_ID 28 -#define ASN1_NRPPA_ID_TRP_INFO_TYPE_LIST_TRP_REQ 29 -#define ASN1_NRPPA_ID_TRP_INFO_LIST_TRP_RESP 30 -#define ASN1_NRPPA_ID_MEAS_BEAM_INFO_REQUEST 31 -#define ASN1_NRPPA_ID_RESULT_SS_RSRP 32 -#define ASN1_NRPPA_ID_RESULT_SS_RSRQ 33 -#define ASN1_NRPPA_ID_RESULT_CSI_RSRP 34 -#define ASN1_NRPPA_ID_RESULT_CSI_RSRQ 35 -#define ASN1_NRPPA_ID_ANGLE_OF_ARRIVAL_NR 36 -#define ASN1_NRPPA_ID_GEOGRAPHICAL_COORDINATES 37 -#define ASN1_NRPPA_ID_POSITIONING_BROADCAST_CELLS 38 -#define ASN1_NRPPA_ID_LMF_MEAS_ID 39 -#define ASN1_NRPPA_ID_RAN_MEAS_ID 40 -#define ASN1_NRPPA_ID_TRP_MEAS_REQUEST_LIST 41 -#define ASN1_NRPPA_ID_TRP_MEAS_RESP_LIST 42 -#define ASN1_NRPPA_ID_TRP_MEAS_REPORT_LIST 43 -#define ASN1_NRPPA_ID_SRS_TYPE 44 -#define ASN1_NRPPA_ID_ACTIVATION_TIME 45 -#define ASN1_NRPPA_ID_SRS_RES_SET_ID 46 -#define ASN1_NRPPA_ID_TRP_LIST 47 -#define ASN1_NRPPA_ID_SRS_SPATIAL_RELATION 48 -#define ASN1_NRPPA_ID_SYS_FRAME_NUM 49 -#define ASN1_NRPPA_ID_SLOT_NUM 50 -#define ASN1_NRPPA_ID_SRS_RES_TRIGGER 51 -#define ASN1_NRPPA_ID_TRP_MEAS_QUANTITIES 52 -#define ASN1_NRPPA_ID_ABORT_TX 53 -#define ASN1_NRPPA_ID_SFN_INITISATION_TIME 54 -#define ASN1_NRPPA_ID_RESULT_NR 55 -#define ASN1_NRPPA_ID_RESULT_EUTRA 56 -#define ASN1_NRPPA_ID_TRP_INFO_TYPE_ITEM 57 -#define ASN1_NRPPA_ID_CGI_NR 58 -#define ASN1_NRPPA_ID_SFN_INITISATION_TIME_NR 59 -#define ASN1_NRPPA_ID_CELL_ID 60 -#define ASN1_NRPPA_ID_SRS_FREQ 61 -#define ASN1_NRPPA_ID_TRP_TYPE 62 -#define ASN1_NRPPA_ID_SRS_SPATIAL_RELATION_PER_SRS_RES 63 -#define ASN1_NRPPA_ID_MEAS_PERIODICITY_EXTENDED 64 -#define ASN1_NRPPA_ID_PRS_RES_ID 65 -#define ASN1_NRPPA_ID_PRSTRP_LIST 66 -#define ASN1_NRPPA_ID_PRS_TX_TRP_LIST 67 -#define ASN1_NRPPA_ID_ON_DEMAND_PRS 68 -#define ASN1_NRPPA_ID_AO_A_SEARCH_WIN 69 -#define ASN1_NRPPA_ID_TRP_MEAS_UPD_LIST 70 -#define ASN1_NRPPA_ID_ZO_A 71 -#define ASN1_NRPPA_ID_RESP_TIME 72 -#define ASN1_NRPPA_ID_UE_REPORT_INFO 73 -#define ASN1_NRPPA_ID_MULTIPLE_UL_AO_A 74 -#define ASN1_NRPPA_ID_UL_SRS_RSRP_P 75 -#define ASN1_NRPPA_ID_SRS_RESTYPE 76 -#define ASN1_NRPPA_ID_EXTENDED_ADD_PATH_LIST 77 -#define ASN1_NRPPA_ID_ARP_LOCATION_INFO 78 -#define ASN1_NRPPA_ID_ARP_ID 79 -#define ASN1_NRPPA_ID_LO_S_N_LO_SI_NFORMATION 80 -#define ASN1_NRPPA_ID_UE_TX_TEG_ASSOC_LIST 81 -#define ASN1_NRPPA_ID_NOF_TRP_RX_TEG 82 -#define ASN1_NRPPA_ID_NOF_TRP_RX_TX_TEG 83 -#define ASN1_NRPPA_ID_TRP_TX_TEG_ASSOC 84 -#define ASN1_NRPPA_ID_TRPTEG_INFO 85 -#define ASN1_NRPPA_ID_TRP_RX_TEG_INFO 86 -#define ASN1_NRPPA_ID_TRP_PRS_INFO_LIST 87 -#define ASN1_NRPPA_ID_PRS_MEASS_INFO_LIST 88 -#define ASN1_NRPPA_ID_PRS_CFG_REQUEST_TYPE 89 -#define ASN1_NRPPA_ID_UE_TEG_INFO_REQUEST 90 -#define ASN1_NRPPA_ID_MEAS_TIME_OCCASION 91 -#define ASN1_NRPPA_ID_MEAS_CHARACTERISTICS_REQUEST_IND 92 -#define ASN1_NRPPA_ID_TRP_BEAM_ANT_INFO 93 -#define ASN1_NRPPA_ID_NR_TADV 94 -#define ASN1_NRPPA_ID_MEAS_AMOUNT 95 -#define ASN1_NRPPA_ID_PATH_PWR 96 -#define ASN1_NRPPA_ID_PRECFG_RESULT 97 -#define ASN1_NRPPA_ID_REQUEST_TYPE 98 -#define ASN1_NRPPA_ID_UE_TEG_REPORT_PERIODICITY 99 -#define ASN1_NRPPA_ID_SRS_PORT_IDX 100 -#define ASN1_NRPPA_ID_PROC_CODE_101_NOT_TO_BE_USED 101 -#define ASN1_NRPPA_ID_PROC_CODE_102_NOT_TO_BE_USED 102 -#define ASN1_NRPPA_ID_PROC_CODE_103_NOT_TO_BE_USED 103 -#define ASN1_NRPPA_ID_UE_TX_TIMING_ERROR_MARGIN 104 -#define ASN1_NRPPA_ID_MEAS_PERIODICITY_NR_AO_A 105 -#define ASN1_NRPPA_ID_SRS_TX_STATUS 106 -#define ASN1_NRPPA_MAX_PRIVATE_IES 65535 -#define ASN1_NRPPA_MAX_PROTOCOL_EXTS 65535 -#define ASN1_NRPPA_MAX_PROTOCOL_IES 65535 - -/******************************************************************************* - * Struct Definitions - ******************************************************************************/ - -// LocationUncertainty-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -using location_uncertainty_ext_ies_o = protocol_ext_empty_o; - -using lcs_to_gcs_translation_ext_ies_container = protocol_ext_container_empty_l; - -// LCS-to-GCS-Translation ::= SEQUENCE -struct lcs_to_gcs_translation_s { - bool ext = false; - bool ie_exts_present = false; - uint16_t alpha = 0; - uint16_t beta = 0; - uint16_t gamma = 0; - lcs_to_gcs_translation_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// MultipleULAoA-Item-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using multiple_ul_ao_a_item_ext_ies_o = protocol_ies_empty_o; - -using ul_ao_a_ext_ies_container = protocol_ext_container_empty_l; - -using zo_a_ext_ies_container = protocol_ext_container_empty_l; - -using trp_beam_pwr_item_ext_ies_container = protocol_ext_container_empty_l; - -// UL-AoA ::= SEQUENCE -struct ul_ao_a_s { - bool ext = false; - bool zenith_ao_a_present = false; - bool lcs_to_gcs_translation_present = false; - bool ie_exts_present = false; - uint16_t azimuth_ao_a = 0; - uint16_t zenith_ao_a = 0; - lcs_to_gcs_translation_s lcs_to_gcs_translation; - ul_ao_a_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ZoA ::= SEQUENCE -struct zo_a_s { - bool ext = false; - bool lcs_to_gcs_translation_present = false; - bool ie_exts_present = false; - uint16_t zenith_ao_a = 0; - lcs_to_gcs_translation_s lcs_to_gcs_translation; - zo_a_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using location_uncertainty_ext_ies_container = protocol_ext_container_empty_l; - -// MultipleULAoA-Item ::= CHOICE -struct multiple_ul_ao_a_item_c { - struct types_opts { - enum options { ul_ao_a, ul_zo_a, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - multiple_ul_ao_a_item_c() = default; - multiple_ul_ao_a_item_c(const multiple_ul_ao_a_item_c& other); - multiple_ul_ao_a_item_c& operator=(const multiple_ul_ao_a_item_c& other); - ~multiple_ul_ao_a_item_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - ul_ao_a_s& ul_ao_a() - { - assert_choice_type(types::ul_ao_a, type_, "MultipleULAoA-Item"); - return c.get(); - } - zo_a_s& ul_zo_a() - { - assert_choice_type(types::ul_zo_a, type_, "MultipleULAoA-Item"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "MultipleULAoA-Item"); - return c.get>(); - } - const ul_ao_a_s& ul_ao_a() const - { - assert_choice_type(types::ul_ao_a, type_, "MultipleULAoA-Item"); - return c.get(); - } - const zo_a_s& ul_zo_a() const - { - assert_choice_type(types::ul_zo_a, type_, "MultipleULAoA-Item"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "MultipleULAoA-Item"); - return c.get>(); - } - ul_ao_a_s& set_ul_ao_a(); - zo_a_s& set_ul_zo_a(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, ul_ao_a_s, zo_a_s> c; - - void destroy_(); -}; - -// RelativePathDelay-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using relative_path_delay_ext_ies_o = protocol_ies_empty_o; - -// TRP-Beam-Power-Item ::= SEQUENCE -struct trp_beam_pwr_item_s { - bool ext = false; - bool prs_res_set_id_present = false; - bool relative_pwr_fine_present = false; - bool ie_exts_present = false; - uint8_t prs_res_set_id = 0; - uint8_t prs_res_id = 0; - uint8_t relative_pwr = 0; - uint8_t relative_pwr_fine = 0; - trp_beam_pwr_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using trp_elevation_angle_list_item_ext_ies_container = protocol_ext_container_empty_l; - -using trp_meas_angle_quality_ext_ies_container = protocol_ext_container_empty_l; - -// TrpMeasurementQuality-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using trp_meas_quality_ext_ies_o = protocol_ies_empty_o; - -using trp_meas_timing_quality_ext_ies_container = protocol_ext_container_empty_l; - -// ARPLocationType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using arp_location_type_ext_ies_o = protocol_ies_empty_o; - -// DL-PRSMutingPattern-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using dl_prs_muting_pattern_ext_ies_o = protocol_ies_empty_o; - -// LocationUncertainty ::= SEQUENCE -struct location_uncertainty_s { - bool ext = false; - bool ie_exts_present = false; - uint16_t horizontal_uncertainty = 0; - uint8_t horizontal_confidence = 0; - uint16_t vertical_uncertainty = 0; - uint8_t vertical_confidence = 0; - location_uncertainty_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using multiple_ul_ao_a_ext_ies_container = protocol_ext_container_empty_l; - -// MultipleULAoA-List ::= SEQUENCE (SIZE (1..8)) OF MultipleULAoA-Item -using multiple_ul_ao_a_list_l = dyn_array; - -// PRSResource-QCLInfo-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using prs_res_qcl_info_ext_ies_o = protocol_ies_empty_o; - -using prs_res_qcl_source_prs_ext_ies_container = protocol_ext_container_empty_l; - -using prs_res_qcl_source_ssb_ext_ies_container = protocol_ext_container_empty_l; - -using relative_cartesian_location_ext_ies_container = protocol_ext_container_empty_l; - -using relative_geodetic_location_ext_ies_container = protocol_ext_container_empty_l; - -// RxTxTimingErrorMargin ::= ENUMERATED -struct rx_tx_timing_error_margin_opts { - enum options { - tc0dot5, - tc1, - tc2, - tc4, - tc8, - tc12, - tc16, - tc20, - tc24, - tc32, - tc40, - tc48, - tc64, - tc80, - tc96, - tc128, - // ... - nulltype - } value; - typedef float number_type; - - const char* to_string() const; - float to_number() const; - const char* to_number_string() const; -}; -using rx_tx_timing_error_margin_e = enumerated; - -// TimingErrorMargin ::= ENUMERATED -struct timing_error_margin_opts { - enum options { - tc0, - tc2, - tc4, - tc6, - tc8, - tc12, - tc16, - tc20, - tc24, - tc32, - tc40, - tc48, - tc56, - tc64, - tc72, - tc80, - /*...*/ nulltype - } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using timing_error_margin_e = enumerated; - -using trp_beam_ant_angles_list_item_ext_ies_container = protocol_ext_container_empty_l; - -// TRP-ElevationAngleList-Item ::= SEQUENCE -struct trp_elevation_angle_list_item_s { - using trp_beam_pwr_list_l_ = dyn_array; - - // member variables - bool ext = false; - bool trp_elevation_angle_fine_present = false; - bool ie_exts_present = false; - uint8_t trp_elevation_angle = 0; - uint8_t trp_elevation_angle_fine = 0; - trp_beam_pwr_list_l_ trp_beam_pwr_list; - trp_elevation_angle_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TrpMeasurementAngleQuality ::= SEQUENCE -struct trp_meas_angle_quality_s { - struct resolution_opts { - enum options { deg0dot1, /*...*/ nulltype } value; - typedef float number_type; - - const char* to_string() const; - float to_number() const; - const char* to_number_string() const; - }; - using resolution_e_ = enumerated; - - // member variables - bool ext = false; - bool zenith_quality_present = false; - bool ie_exts_present = false; - uint16_t azimuth_quality = 0; - uint16_t zenith_quality = 0; - resolution_e_ resolution; - trp_meas_angle_quality_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TrpMeasurementTimingQuality ::= SEQUENCE -struct trp_meas_timing_quality_s { - struct resolution_opts { - enum options { m0dot1, m1, m10, m30, /*...*/ nulltype } value; - typedef float number_type; - - const char* to_string() const; - float to_number() const; - const char* to_number_string() const; - }; - using resolution_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint8_t meas_quality = 0; - resolution_e_ resolution; - trp_meas_timing_quality_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using trp_rx_teg_info_ext_ies_container = protocol_ext_container_empty_l; - -using trp_rx_tx_teg_info_ext_ies_container = protocol_ext_container_empty_l; - -using trp_tx_teg_info_ext_ies_container = protocol_ext_container_empty_l; - -using ul_srs_rsrp_p_ext_ies_container = protocol_ext_container_empty_l; - -// DL-PRSResourceARPLocation-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using dl_prs_res_arp_location_ext_ies_o = protocol_ies_empty_o; - -using extended_add_path_list_item_ext_ies_container = protocol_ext_container_empty_l; - -// MultipleULAoA ::= SEQUENCE -struct multiple_ul_ao_a_s { - bool ext = false; - bool ie_exts_present = false; - multiple_ul_ao_a_list_l multiple_ul_ao_a; - multiple_ul_ao_a_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSResource-QCLSourcePRS ::= SEQUENCE -struct prs_res_qcl_source_prs_s { - bool ext = false; - bool qcl_source_prs_res_id_present = false; - bool ie_exts_present = false; - uint8_t qcl_source_prs_res_set_id = 0; - uint8_t qcl_source_prs_res_id = 0; - prs_res_qcl_source_prs_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSResource-QCLSourceSSB ::= SEQUENCE -struct prs_res_qcl_source_ssb_s { - bool ext = false; - bool ssb_idx_present = false; - bool ie_exts_present = false; - uint16_t pci_nr = 0; - uint8_t ssb_idx = 0; - prs_res_qcl_source_ssb_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// RelativeCartesianLocation ::= SEQUENCE -struct relative_cartesian_location_s { - struct xy_zunit_opts { - enum options { mm, cm, dm, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using xy_zunit_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - xy_zunit_e_ xy_zunit; - int32_t xvalue = -65536; - int32_t yvalue = -65536; - int32_t zvalue = -32768; - location_uncertainty_s location_uncertainty; - relative_cartesian_location_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// RelativeGeodeticLocation ::= SEQUENCE -struct relative_geodetic_location_s { - struct milli_arc_second_units_opts { - enum options { zerodot03, zerodot3, three, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using milli_arc_second_units_e_ = enumerated; - struct height_units_opts { - enum options { mm, cm, m, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using height_units_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - milli_arc_second_units_e_ milli_arc_second_units; - height_units_e_ height_units; - int16_t delta_latitude = -1024; - int16_t delta_longitude = -1024; - int16_t delta_height = -1024; - location_uncertainty_s location_uncertainty; - relative_geodetic_location_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// RelativePathDelay ::= CHOICE -struct relative_path_delay_c { - struct types_opts { - enum options { k0, k1, k2, k3, k4, k5, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - relative_path_delay_c() = default; - relative_path_delay_c(const relative_path_delay_c& other); - relative_path_delay_c& operator=(const relative_path_delay_c& other); - ~relative_path_delay_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint16_t& k0() - { - assert_choice_type(types::k0, type_, "RelativePathDelay"); - return c.get(); - } - uint16_t& k1() - { - assert_choice_type(types::k1, type_, "RelativePathDelay"); - return c.get(); - } - uint16_t& k2() - { - assert_choice_type(types::k2, type_, "RelativePathDelay"); - return c.get(); - } - uint16_t& k3() - { - assert_choice_type(types::k3, type_, "RelativePathDelay"); - return c.get(); - } - uint16_t& k4() - { - assert_choice_type(types::k4, type_, "RelativePathDelay"); - return c.get(); - } - uint16_t& k5() - { - assert_choice_type(types::k5, type_, "RelativePathDelay"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "RelativePathDelay"); - return c.get>(); - } - const uint16_t& k0() const - { - assert_choice_type(types::k0, type_, "RelativePathDelay"); - return c.get(); - } - const uint16_t& k1() const - { - assert_choice_type(types::k1, type_, "RelativePathDelay"); - return c.get(); - } - const uint16_t& k2() const - { - assert_choice_type(types::k2, type_, "RelativePathDelay"); - return c.get(); - } - const uint16_t& k3() const - { - assert_choice_type(types::k3, type_, "RelativePathDelay"); - return c.get(); - } - const uint16_t& k4() const - { - assert_choice_type(types::k4, type_, "RelativePathDelay"); - return c.get(); - } - const uint16_t& k5() const - { - assert_choice_type(types::k5, type_, "RelativePathDelay"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "RelativePathDelay"); - return c.get>(); - } - uint16_t& set_k0(); - uint16_t& set_k1(); - uint16_t& set_k2(); - uint16_t& set_k3(); - uint16_t& set_k4(); - uint16_t& set_k5(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -using rx_teg_ext_ies_container = protocol_ext_container_empty_l; - -using rx_tx_teg_ext_ies_container = protocol_ext_container_empty_l; - -// TRP-BeamAntennaAnglesList-Item ::= SEQUENCE -struct trp_beam_ant_angles_list_item_s { - using trp_elevation_angle_list_l_ = dyn_array; - - // member variables - bool ext = false; - bool trp_azimuth_angle_fine_present = false; - bool ie_exts_present = false; - uint16_t trp_azimuth_angle = 0; - uint8_t trp_azimuth_angle_fine = 0; - trp_elevation_angle_list_l_ trp_elevation_angle_list; - trp_beam_ant_angles_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TrpMeasurementQuality ::= CHOICE -struct trp_meas_quality_c { - struct types_opts { - enum options { timing_meas_quality, angle_meas_quality, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trp_meas_quality_c() = default; - trp_meas_quality_c(const trp_meas_quality_c& other); - trp_meas_quality_c& operator=(const trp_meas_quality_c& other); - ~trp_meas_quality_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_meas_timing_quality_s& timing_meas_quality() - { - assert_choice_type(types::timing_meas_quality, type_, "TrpMeasurementQuality"); - return c.get(); - } - trp_meas_angle_quality_s& angle_meas_quality() - { - assert_choice_type(types::angle_meas_quality, type_, "TrpMeasurementQuality"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TrpMeasurementQuality"); - return c.get>(); - } - const trp_meas_timing_quality_s& timing_meas_quality() const - { - assert_choice_type(types::timing_meas_quality, type_, "TrpMeasurementQuality"); - return c.get(); - } - const trp_meas_angle_quality_s& angle_meas_quality() const - { - assert_choice_type(types::angle_meas_quality, type_, "TrpMeasurementQuality"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TrpMeasurementQuality"); - return c.get>(); - } - trp_meas_timing_quality_s& set_timing_meas_quality(); - trp_meas_angle_quality_s& set_angle_meas_quality(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - trp_meas_angle_quality_s, - trp_meas_timing_quality_s> - c; - - void destroy_(); -}; - -// TRP-Rx-TEGInformation ::= SEQUENCE -struct trp_rx_teg_info_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t trp_rx_teg_id = 0; - timing_error_margin_e trp_rx_timing_error_margin; - trp_rx_teg_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-RxTx-TEGInformation ::= SEQUENCE -struct trp_rx_tx_teg_info_s { - bool ext = false; - bool ie_exts_present = false; - uint16_t trp_rx_tx_teg_id = 0; - rx_tx_timing_error_margin_e trp_rx_tx_timing_error_margin; - trp_rx_tx_teg_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-Tx-TEGInformation ::= SEQUENCE -struct trp_tx_teg_info_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t trp_tx_teg_id = 0; - timing_error_margin_e trp_tx_timing_error_margin; - trp_tx_teg_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPTEGInformation-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using trpteg_info_ext_ies_o = protocol_ies_empty_o; - -// UL-SRS-RSRPP ::= SEQUENCE -struct ul_srs_rsrp_p_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t first_path_rsrp_p = 0; - ul_srs_rsrp_p_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AdditionalPathListItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct add_path_list_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { multiple_ul_ao_a, path_pwr, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - multiple_ul_ao_a_s& multiple_ul_ao_a(); - ul_srs_rsrp_p_s& path_pwr(); - const multiple_ul_ao_a_s& multiple_ul_ao_a() const; - const ul_srs_rsrp_p_s& path_pwr() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -using arp_location_info_ext_ies_container = protocol_ext_container_empty_l; - -// ARPLocationType ::= CHOICE -struct arp_location_type_c { - struct types_opts { - enum options { arp_position_relative_geodetic, arp_position_relative_cartesian, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - arp_location_type_c() = default; - arp_location_type_c(const arp_location_type_c& other); - arp_location_type_c& operator=(const arp_location_type_c& other); - ~arp_location_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - relative_geodetic_location_s& arp_position_relative_geodetic() - { - assert_choice_type(types::arp_position_relative_geodetic, type_, "ARPLocationType"); - return c.get(); - } - relative_cartesian_location_s& arp_position_relative_cartesian() - { - assert_choice_type(types::arp_position_relative_cartesian, type_, "ARPLocationType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ARPLocationType"); - return c.get>(); - } - const relative_geodetic_location_s& arp_position_relative_geodetic() const - { - assert_choice_type(types::arp_position_relative_geodetic, type_, "ARPLocationType"); - return c.get(); - } - const relative_cartesian_location_s& arp_position_relative_cartesian() const - { - assert_choice_type(types::arp_position_relative_cartesian, type_, "ARPLocationType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ARPLocationType"); - return c.get>(); - } - relative_geodetic_location_s& set_arp_position_relative_geodetic(); - relative_cartesian_location_s& set_arp_position_relative_cartesian(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - relative_cartesian_location_s, - relative_geodetic_location_s> - c; - - void destroy_(); -}; - -// Choice-TRP-Beam-Info-Item-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using choice_trp_beam_info_item_ext_ies_o = protocol_ies_empty_o; - -using dl_prs_ext_ies_container = protocol_ext_container_empty_l; - -// DL-PRSMutingPattern ::= CHOICE -struct dl_prs_muting_pattern_c { - struct types_opts { - enum options { two, four, six, eight, sixteen, thirty_two, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - dl_prs_muting_pattern_c() = default; - dl_prs_muting_pattern_c(const dl_prs_muting_pattern_c& other); - dl_prs_muting_pattern_c& operator=(const dl_prs_muting_pattern_c& other); - ~dl_prs_muting_pattern_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - fixed_bitstring<2, false, true>& two() - { - assert_choice_type(types::two, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - fixed_bitstring<4, false, true>& four() - { - assert_choice_type(types::four, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - fixed_bitstring<6, false, true>& six() - { - assert_choice_type(types::six, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - fixed_bitstring<8, false, true>& eight() - { - assert_choice_type(types::eight, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - fixed_bitstring<16, false, true>& sixteen() - { - assert_choice_type(types::sixteen, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - fixed_bitstring<32, false, true>& thirty_two() - { - assert_choice_type(types::thirty_two, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const fixed_bitstring<2, false, true>& two() const - { - assert_choice_type(types::two, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const fixed_bitstring<4, false, true>& four() const - { - assert_choice_type(types::four, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const fixed_bitstring<6, false, true>& six() const - { - assert_choice_type(types::six, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const fixed_bitstring<8, false, true>& eight() const - { - assert_choice_type(types::eight, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const fixed_bitstring<16, false, true>& sixteen() const - { - assert_choice_type(types::sixteen, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const fixed_bitstring<32, false, true>& thirty_two() const - { - assert_choice_type(types::thirty_two, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "DL-PRSMutingPattern"); - return c.get>(); - } - fixed_bitstring<2, false, true>& set_two(); - fixed_bitstring<4, false, true>& set_four(); - fixed_bitstring<6, false, true>& set_six(); - fixed_bitstring<8, false, true>& set_eight(); - fixed_bitstring<16, false, true>& set_sixteen(); - fixed_bitstring<32, false, true>& set_thirty_two(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, protocol_ie_single_container_s> c; - - void destroy_(); -}; - -using dl_prs_res_item_ext_ies_container = protocol_ext_container_empty_l; - -// DL-PRSResourceSetARPLocation-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using dl_prs_res_set_arp_location_ext_ies_o = protocol_ies_empty_o; - -// ExtendedAdditionalPathList-Item ::= SEQUENCE -struct extended_add_path_list_item_s { - bool ext = false; - bool path_quality_present = false; - bool multiple_ul_ao_a_present = false; - bool path_pwr_present = false; - bool ie_exts_present = false; - relative_path_delay_c relative_time_of_path; - trp_meas_quality_c path_quality; - multiple_ul_ao_a_s multiple_ul_ao_a; - ul_srs_rsrp_p_s path_pwr; - extended_add_path_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using ng_ran_access_point_position_ext_ies_container = protocol_ext_container_empty_l; - -using ngran_high_accuracy_access_point_position_ext_ies_container = protocol_ext_container_empty_l; - -// PRSAngleItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct prs_angle_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { prs_res_id, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::prs_res_id; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& prs_res_id() { return c; } - const uint8_t& prs_res_id() const { return c; } - - private: - uint8_t c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -using prs_muting_option1_ext_ies_container = protocol_ext_container_empty_l; - -using prs_muting_option2_ext_ies_container = protocol_ext_container_empty_l; - -using prs_res_item_ext_ies_container = protocol_ext_container_empty_l; - -// PRSResource-QCLInfo ::= CHOICE -struct prs_res_qcl_info_c { - struct types_opts { - enum options { qcl_source_ssb, qcl_source_prs, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - prs_res_qcl_info_c() = default; - prs_res_qcl_info_c(const prs_res_qcl_info_c& other); - prs_res_qcl_info_c& operator=(const prs_res_qcl_info_c& other); - ~prs_res_qcl_info_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - prs_res_qcl_source_ssb_s& qcl_source_ssb() - { - assert_choice_type(types::qcl_source_ssb, type_, "PRSResource-QCLInfo"); - return c.get(); - } - prs_res_qcl_source_prs_s& qcl_source_prs() - { - assert_choice_type(types::qcl_source_prs, type_, "PRSResource-QCLInfo"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "PRSResource-QCLInfo"); - return c.get>(); - } - const prs_res_qcl_source_ssb_s& qcl_source_ssb() const - { - assert_choice_type(types::qcl_source_ssb, type_, "PRSResource-QCLInfo"); - return c.get(); - } - const prs_res_qcl_source_prs_s& qcl_source_prs() const - { - assert_choice_type(types::qcl_source_prs, type_, "PRSResource-QCLInfo"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "PRSResource-QCLInfo"); - return c.get>(); - } - prs_res_qcl_source_ssb_s& set_qcl_source_ssb(); - prs_res_qcl_source_prs_s& set_qcl_source_prs(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - prs_res_qcl_source_prs_s, - prs_res_qcl_source_ssb_s> - c; - - void destroy_(); -}; - -// ReferencePoint-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using ref_point_ext_ies_o = protocol_ies_empty_o; - -// ReferenceSignal-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using ref_sig_ext_ie_o = protocol_ies_empty_o; - -// RxTEG ::= SEQUENCE -struct rx_teg_s { - bool ext = false; - bool ie_exts_present = false; - trp_rx_teg_info_s trp_rx_teg_info; - trp_tx_teg_info_s trp_tx_teg_info; - rx_teg_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// RxTxTEG ::= SEQUENCE -struct rx_tx_teg_s { - bool ext = false; - bool trp_tx_teg_info_present = false; - bool ie_exts_present = false; - trp_rx_tx_teg_info_s trp_rx_tx_teg_info; - trp_tx_teg_info_s trp_tx_teg_info; - rx_tx_teg_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSPortIndex ::= ENUMERATED -struct srs_port_idx_opts { - enum options { id1000, id1001, id1002, id1003, /*...*/ nulltype } value; - typedef uint16_t number_type; - - const char* to_string() const; - uint16_t to_number() const; -}; -using srs_port_idx_e = enumerated; - -// SSBBurstPosition-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using ssb_burst_position_ext_ies_o = protocol_ies_empty_o; - -using ssb_ext_ies_container = protocol_ext_container_empty_l; - -// TRP-BeamAntennaAngles ::= SEQUENCE (SIZE (1..3600)) OF TRP-BeamAntennaAnglesList-Item -using trp_beam_ant_angles_l = dyn_array; - -using trp_beam_ant_explicit_info_ext_ies_container = protocol_ext_container_empty_l; - -// TRPPositionDirectAccuracy-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using trp_position_direct_accuracy_ext_ies_o = protocol_ies_empty_o; - -// TRPReferencePointType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using trp_ref_point_type_ext_ies_o = protocol_ies_empty_o; - -// ARPLocationInformation-Item ::= SEQUENCE -struct arp_location_info_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t arp_id = 1; - arp_location_type_c arp_location_type; - arp_location_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using dl_prs_res_arp_ext_ies_container = protocol_ext_container_empty_l; - -// DL-PRSResourceARPLocation ::= CHOICE -struct dl_prs_res_arp_location_c { - struct types_opts { - enum options { relative_geodetic_location, relative_cartesian_location, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - dl_prs_res_arp_location_c() = default; - dl_prs_res_arp_location_c(const dl_prs_res_arp_location_c& other); - dl_prs_res_arp_location_c& operator=(const dl_prs_res_arp_location_c& other); - ~dl_prs_res_arp_location_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - relative_geodetic_location_s& relative_geodetic_location() - { - assert_choice_type(types::relative_geodetic_location, type_, "DL-PRSResourceARPLocation"); - return c.get(); - } - relative_cartesian_location_s& relative_cartesian_location() - { - assert_choice_type(types::relative_cartesian_location, type_, "DL-PRSResourceARPLocation"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "DL-PRSResourceARPLocation"); - return c.get>(); - } - const relative_geodetic_location_s& relative_geodetic_location() const - { - assert_choice_type(types::relative_geodetic_location, type_, "DL-PRSResourceARPLocation"); - return c.get(); - } - const relative_cartesian_location_s& relative_cartesian_location() const - { - assert_choice_type(types::relative_cartesian_location, type_, "DL-PRSResourceARPLocation"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "DL-PRSResourceARPLocation"); - return c.get>(); - } - relative_geodetic_location_s& set_relative_geodetic_location(); - relative_cartesian_location_s& set_relative_cartesian_location(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - relative_cartesian_location_s, - relative_geodetic_location_s> - c; - - void destroy_(); -}; - -// DLPRSResourceID-Item ::= SEQUENCE -struct dl_prs_res_id_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t dl_prs_res_id = 0; - dl_prs_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// DL-PRS ::= SEQUENCE -struct dl_prs_s { - bool ext = false; - bool dl_prs_res_id_present = false; - bool ie_exts_present = false; - uint16_t prsid = 0; - uint8_t dl_prs_res_set_id = 0; - uint8_t dl_prs_res_id = 0; - dl_prs_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using expected_azimuth_ao_a_ext_ies_container = protocol_ext_container_empty_l; - -using expected_zenith_ao_a_ext_ies_container = protocol_ext_container_empty_l; - -// ExtendedAdditionalPathList ::= SEQUENCE (SIZE (1..8)) OF ExtendedAdditionalPathList-Item -using extended_add_path_list_l = dyn_array; - -// LoS-NLoSInformation-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using lo_s_n_lo_si_nformation_ext_ies_o = protocol_ies_empty_o; - -// NG-RANAccessPointPosition ::= SEQUENCE -struct ng_ran_access_point_position_s { - struct latitude_sign_opts { - enum options { north, south, nulltype } value; - - const char* to_string() const; - }; - using latitude_sign_e_ = enumerated; - struct direction_of_altitude_opts { - enum options { height, depth, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using direction_of_altitude_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - latitude_sign_e_ latitude_sign; - uint32_t latitude = 0; - int32_t longitude = -8388608; - direction_of_altitude_e_ direction_of_altitude; - uint16_t altitude = 0; - uint8_t uncertainty_semi_major = 0; - uint8_t uncertainty_semi_minor = 0; - uint8_t orientation_of_major_axis = 0; - uint8_t uncertainty_altitude = 0; - uint8_t confidence = 0; - ng_ran_access_point_position_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// NGRANHighAccuracyAccessPointPosition ::= SEQUENCE -struct ngran_high_accuracy_access_point_position_s { - bool ext = false; - bool ie_exts_present = false; - int64_t latitude = -2147483648; - int64_t longitude = -2147483648; - int32_t altitude = -64000; - uint16_t uncertainty_semi_major = 0; - uint16_t uncertainty_semi_minor = 0; - uint8_t orientation_of_major_axis = 0; - uint8_t horizontal_confidence = 0; - uint16_t uncertainty_altitude = 0; - uint8_t vertical_confidence = 0; - ngran_high_accuracy_access_point_position_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using pos_res_set_type_aperiodic_ext_ies_container = protocol_ext_container_empty_l; - -// PosResourceSetType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using pos_res_set_type_ext_ies_o = protocol_ies_empty_o; - -using pos_res_set_type_periodic_ext_ies_container = protocol_ext_container_empty_l; - -using pos_res_set_type_semi_persistent_ext_ies_container = protocol_ext_container_empty_l; - -// PosSRSInfo ::= SEQUENCE -struct pos_srs_info_s { - bool ext = false; - uint8_t pos_srs_res_id = 0; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using pr_si_nformation_pos_ext_ies_container = protocol_ext_container_empty_l; - -using prs_muting_ext_ies_container = protocol_ext_container_empty_l; - -// PRSMutingOption1 ::= SEQUENCE -struct prs_muting_option1_s { - struct muting_bit_repeat_factor_opts { - enum options { n1, n2, n4, n8, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using muting_bit_repeat_factor_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - dl_prs_muting_pattern_c muting_pattern; - muting_bit_repeat_factor_e_ muting_bit_repeat_factor; - prs_muting_option1_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSMutingOption2 ::= SEQUENCE -struct prs_muting_option2_s { - bool ext = false; - bool ie_exts_present = false; - dl_prs_muting_pattern_c muting_pattern; - prs_muting_option2_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSResource-Item ::= SEQUENCE -struct prs_res_item_s { - bool ext = false; - bool qcl_info_present = false; - bool ie_exts_present = false; - uint8_t prs_res_id = 0; - uint16_t seq_id = 0; - uint8_t re_offset = 0; - uint16_t res_slot_offset = 0; - uint8_t res_symbol_offset = 0; - prs_res_qcl_info_c qcl_info; - prs_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using res_set_type_aperiodic_ext_ies_container = protocol_ext_container_empty_l; - -// ResourceSetType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using res_set_type_ext_ies_o = protocol_ies_empty_o; - -using res_set_type_periodic_ext_ies_container = protocol_ext_container_empty_l; - -using res_set_type_semi_persistent_ext_ies_container = protocol_ext_container_empty_l; - -using res_type_aperiodic_ext_ies_container = protocol_ext_container_empty_l; - -using res_type_aperiodic_pos_ext_ies_container = protocol_ext_container_empty_l; - -// ResourceType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using res_type_ext_ies_o = protocol_ies_empty_o; - -using res_type_periodic_ext_ies_container = protocol_ext_container_empty_l; - -using res_type_periodic_pos_ext_ies_container = protocol_ext_container_empty_l; - -// ResourceTypePos-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using res_type_pos_ext_ies_o = protocol_ies_empty_o; - -using res_type_semi_persistent_ext_ies_container = protocol_ext_container_empty_l; - -using res_type_semi_persistent_pos_ext_ies_container = protocol_ext_container_empty_l; - -using result_csi_rsrp_per_csi_rs_item_ext_ies_container = protocol_ext_container_empty_l; - -using result_csi_rsrq_per_csi_rs_item_ext_ies_container = protocol_ext_container_empty_l; - -using result_ss_rsrp_per_ssb_item_ext_ies_container = protocol_ext_container_empty_l; - -using result_ss_rsrq_per_ssb_item_ext_ies_container = protocol_ext_container_empty_l; - -// SpatialInformationPos-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using spatial_info_pos_ext_ies_o = protocol_ies_empty_o; - -// SRSInfo ::= SEQUENCE -struct srs_info_s { - bool ext = false; - uint8_t srs_res = 0; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSResourcetype-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct srs_restype_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { srs_port_idx, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::srs_port_idx; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - srs_port_idx_e& srs_port_idx() { return c; } - const srs_port_idx_e& srs_port_idx() const { return c; } - - private: - srs_port_idx_e c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// SSB ::= SEQUENCE -struct ssb_s { - bool ext = false; - bool ssb_idx_present = false; - bool ie_exts_present = false; - uint16_t pci_nr = 0; - uint8_t ssb_idx = 0; - ssb_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-BeamAntennaExplicitInformation ::= SEQUENCE -struct trp_beam_ant_explicit_info_s { - bool ext = false; - bool lcs_to_gcs_translation_present = false; - bool ie_exts_present = false; - trp_beam_ant_angles_l trp_beam_ant_angles; - lcs_to_gcs_translation_s lcs_to_gcs_translation; - trp_beam_ant_explicit_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPTEGInformation ::= CHOICE -struct trpteg_info_c { - struct types_opts { - enum options { rx_tx_teg, rx_teg, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trpteg_info_c() = default; - trpteg_info_c(const trpteg_info_c& other); - trpteg_info_c& operator=(const trpteg_info_c& other); - ~trpteg_info_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - rx_tx_teg_s& rx_tx_teg() - { - assert_choice_type(types::rx_tx_teg, type_, "TRPTEGInformation"); - return c.get(); - } - rx_teg_s& rx_teg() - { - assert_choice_type(types::rx_teg, type_, "TRPTEGInformation"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TRPTEGInformation"); - return c.get>(); - } - const rx_tx_teg_s& rx_tx_teg() const - { - assert_choice_type(types::rx_tx_teg, type_, "TRPTEGInformation"); - return c.get(); - } - const rx_teg_s& rx_teg() const - { - assert_choice_type(types::rx_teg, type_, "TRPTEGInformation"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TRPTEGInformation"); - return c.get>(); - } - rx_tx_teg_s& set_rx_tx_teg(); - rx_teg_s& set_rx_teg(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, rx_teg_s, rx_tx_teg_s> c; - - void destroy_(); -}; - -using trpteg_item_ext_ies_container = protocol_ext_container_empty_l; - -// TransmissionComb-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using tx_comb_ext_ies_o = protocol_ies_empty_o; - -// TransmissionCombPos-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using tx_comb_pos_ext_ies_o = protocol_ies_empty_o; - -struct add_path_list_item_ext_ies_container { - bool multiple_ul_ao_a_present = false; - bool path_pwr_present = false; - multiple_ul_ao_a_s multiple_ul_ao_a; - ul_srs_rsrp_p_s path_pwr; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AngleMeasurementType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using angle_meas_type_ext_ies_o = protocol_ies_empty_o; - -// ARPLocationInformation ::= SEQUENCE (SIZE (1..16)) OF ARPLocationInformation-Item -using arp_location_info_l = dyn_array; - -using cgi_nr_ext_ies_container = protocol_ext_container_empty_l; - -// Choice-TRP-Beam-Antenna-Info-Item ::= CHOICE -struct choice_trp_beam_ant_info_item_c { - struct types_opts { - enum options { ref, explicit_type, no_change, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - choice_trp_beam_ant_info_item_c() = default; - choice_trp_beam_ant_info_item_c(const choice_trp_beam_ant_info_item_c& other); - choice_trp_beam_ant_info_item_c& operator=(const choice_trp_beam_ant_info_item_c& other); - ~choice_trp_beam_ant_info_item_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& ref() - { - assert_choice_type(types::ref, type_, "Choice-TRP-Beam-Antenna-Info-Item"); - return c.get(); - } - trp_beam_ant_explicit_info_s& explicit_type() - { - assert_choice_type(types::explicit_type, type_, "Choice-TRP-Beam-Antenna-Info-Item"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "Choice-TRP-Beam-Antenna-Info-Item"); - return c.get>(); - } - const uint32_t& ref() const - { - assert_choice_type(types::ref, type_, "Choice-TRP-Beam-Antenna-Info-Item"); - return c.get(); - } - const trp_beam_ant_explicit_info_s& explicit_type() const - { - assert_choice_type(types::explicit_type, type_, "Choice-TRP-Beam-Antenna-Info-Item"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "Choice-TRP-Beam-Antenna-Info-Item"); - return c.get>(); - } - uint32_t& set_ref(); - trp_beam_ant_explicit_info_s& set_explicit_type(); - void set_no_change(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, trp_beam_ant_explicit_info_s> c; - - void destroy_(); -}; - -// DLPRSResourceARP ::= SEQUENCE -struct dl_prs_res_arp_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t dl_prs_res_id = 0; - dl_prs_res_arp_location_c dl_prs_res_arp_location; - dl_prs_res_arp_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using dl_prs_res_set_arp_ext_ies_container = protocol_ext_container_empty_l; - -// DL-PRSResourceSetARPLocation ::= CHOICE -struct dl_prs_res_set_arp_location_c { - struct types_opts { - enum options { relative_geodetic_location, relative_cartesian_location, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - dl_prs_res_set_arp_location_c() = default; - dl_prs_res_set_arp_location_c(const dl_prs_res_set_arp_location_c& other); - dl_prs_res_set_arp_location_c& operator=(const dl_prs_res_set_arp_location_c& other); - ~dl_prs_res_set_arp_location_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - relative_geodetic_location_s& relative_geodetic_location() - { - assert_choice_type(types::relative_geodetic_location, type_, "DL-PRSResourceSetARPLocation"); - return c.get(); - } - relative_cartesian_location_s& relative_cartesian_location() - { - assert_choice_type(types::relative_cartesian_location, type_, "DL-PRSResourceSetARPLocation"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "DL-PRSResourceSetARPLocation"); - return c.get>(); - } - const relative_geodetic_location_s& relative_geodetic_location() const - { - assert_choice_type(types::relative_geodetic_location, type_, "DL-PRSResourceSetARPLocation"); - return c.get(); - } - const relative_cartesian_location_s& relative_cartesian_location() const - { - assert_choice_type(types::relative_cartesian_location, type_, "DL-PRSResourceSetARPLocation"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "DL-PRSResourceSetARPLocation"); - return c.get>(); - } - relative_geodetic_location_s& set_relative_geodetic_location(); - relative_cartesian_location_s& set_relative_cartesian_location(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - relative_cartesian_location_s, - relative_geodetic_location_s> - c; - - void destroy_(); -}; - -// Expected-Azimuth-AoA ::= SEQUENCE -struct expected_azimuth_ao_a_s { - bool ext = false; - bool ie_exts_present = false; - uint16_t expected_azimuth_ao_a_value = 0; - uint16_t expected_azimuth_ao_a_uncertainty = 0; - expected_azimuth_ao_a_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using expected_ul_ao_a_ext_ies_container = protocol_ext_container_empty_l; - -// Expected-Zenith-AoA ::= SEQUENCE -struct expected_zenith_ao_a_s { - bool ext = false; - bool ie_exts_present = false; - uint16_t expected_zenith_ao_a_value = 0; - uint16_t expected_zenith_ao_a_uncertainty = 0; - expected_zenith_ao_a_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using expected_zo_a_only_ext_ies_container = protocol_ext_container_empty_l; - -// GNB-RxTxTimeDiff-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct gnb_rx_tx_time_diff_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { extended_add_path_list, trpteg_info, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - extended_add_path_list_l& extended_add_path_list(); - trpteg_info_c& trpteg_info(); - const extended_add_path_list_l& extended_add_path_list() const; - const trpteg_info_c& trpteg_info() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// GNBRxTxTimeDiffMeas-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using gnb_rx_tx_time_diff_meas_ext_ies_o = protocol_ies_empty_o; - -using lcs_to_gcs_translation_item_ext_ies_container = protocol_ext_container_empty_l; - -// LoS-NLoSIndicatorHard ::= ENUMERATED -struct lo_s_n_lo_si_ndicator_hard_opts { - enum options { nlos, los, nulltype } value; - - const char* to_string() const; -}; -using lo_s_n_lo_si_ndicator_hard_e = enumerated; - -using nr_prs_beam_info_item_ext_ies_container = protocol_ext_container_empty_l; - -using on_demand_prs_info_ext_ies_container = protocol_ext_container_empty_l; - -// PosResourceSetTypeAperiodic ::= SEQUENCE -struct pos_res_set_type_aperiodic_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t srs_res_trigger = 1; - pos_res_set_type_aperiodic_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PosResourceSetTypePeriodic ::= SEQUENCE -struct pos_res_set_type_periodic_s { - struct posperiodic_set_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using posperiodic_set_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - posperiodic_set_e_ posperiodic_set; - pos_res_set_type_periodic_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PosResourceSetTypeSemi-persistent ::= SEQUENCE -struct pos_res_set_type_semi_persistent_s { - struct possemi_persistent_set_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using possemi_persistent_set_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - possemi_persistent_set_e_ possemi_persistent_set; - pos_res_set_type_semi_persistent_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSInformationPos ::= SEQUENCE -struct pr_si_nformation_pos_s { - bool ext = false; - bool prs_res_id_pos_present = false; - bool ie_exts_present = false; - uint16_t prs_id_pos = 0; - uint8_t prs_res_set_id_pos = 0; - uint8_t prs_res_id_pos = 0; - pr_si_nformation_pos_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSAngleItem ::= SEQUENCE -struct prs_angle_item_s { - bool ext = false; - bool nr_prs_azimuth_fine_present = false; - bool nr_prs_elevation_present = false; - bool nr_prs_elevation_fine_present = false; - uint16_t nr_prs_azimuth = 0; - uint8_t nr_prs_azimuth_fine = 0; - uint8_t nr_prs_elevation = 0; - uint8_t nr_prs_elevation_fine = 0; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSMuting ::= SEQUENCE -struct prs_muting_s { - bool ext = false; - bool prs_muting_option1_present = false; - bool prs_muting_option2_present = false; - bool ie_exts_present = false; - prs_muting_option1_s prs_muting_option1; - prs_muting_option2_s prs_muting_option2; - prs_muting_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSResource-List ::= SEQUENCE (SIZE (1..64)) OF PRSResource-Item -using prs_res_list_l = dyn_array; - -using prs_res_set_item_ext_ies_container = protocol_ext_container_empty_l; - -// ReferencePoint ::= CHOICE -struct ref_point_c { - struct types_opts { - enum options { relative_coordinate_id, ref_point_coordinate, ref_point_coordinate_ha, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ref_point_c() = default; - ref_point_c(const ref_point_c& other); - ref_point_c& operator=(const ref_point_c& other); - ~ref_point_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint16_t& relative_coordinate_id() - { - assert_choice_type(types::relative_coordinate_id, type_, "ReferencePoint"); - return c.get(); - } - ng_ran_access_point_position_s& ref_point_coordinate() - { - assert_choice_type(types::ref_point_coordinate, type_, "ReferencePoint"); - return c.get(); - } - ngran_high_accuracy_access_point_position_s& ref_point_coordinate_ha() - { - assert_choice_type(types::ref_point_coordinate_ha, type_, "ReferencePoint"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ReferencePoint"); - return c.get>(); - } - const uint16_t& relative_coordinate_id() const - { - assert_choice_type(types::relative_coordinate_id, type_, "ReferencePoint"); - return c.get(); - } - const ng_ran_access_point_position_s& ref_point_coordinate() const - { - assert_choice_type(types::ref_point_coordinate, type_, "ReferencePoint"); - return c.get(); - } - const ngran_high_accuracy_access_point_position_s& ref_point_coordinate_ha() const - { - assert_choice_type(types::ref_point_coordinate_ha, type_, "ReferencePoint"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ReferencePoint"); - return c.get>(); - } - uint16_t& set_relative_coordinate_id(); - ng_ran_access_point_position_s& set_ref_point_coordinate(); - ngran_high_accuracy_access_point_position_s& set_ref_point_coordinate_ha(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> - c; - - void destroy_(); -}; - -// ReferenceSignal ::= CHOICE -struct ref_sig_c { - struct types_opts { - enum options { nzp_csi_rs, ssb, srs, positioning_srs, dl_prs, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ref_sig_c() = default; - ref_sig_c(const ref_sig_c& other); - ref_sig_c& operator=(const ref_sig_c& other); - ~ref_sig_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& nzp_csi_rs() - { - assert_choice_type(types::nzp_csi_rs, type_, "ReferenceSignal"); - return c.get(); - } - ssb_s& ssb() - { - assert_choice_type(types::ssb, type_, "ReferenceSignal"); - return c.get(); - } - uint8_t& srs() - { - assert_choice_type(types::srs, type_, "ReferenceSignal"); - return c.get(); - } - uint8_t& positioning_srs() - { - assert_choice_type(types::positioning_srs, type_, "ReferenceSignal"); - return c.get(); - } - dl_prs_s& dl_prs() - { - assert_choice_type(types::dl_prs, type_, "ReferenceSignal"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ReferenceSignal"); - return c.get>(); - } - const uint8_t& nzp_csi_rs() const - { - assert_choice_type(types::nzp_csi_rs, type_, "ReferenceSignal"); - return c.get(); - } - const ssb_s& ssb() const - { - assert_choice_type(types::ssb, type_, "ReferenceSignal"); - return c.get(); - } - const uint8_t& srs() const - { - assert_choice_type(types::srs, type_, "ReferenceSignal"); - return c.get(); - } - const uint8_t& positioning_srs() const - { - assert_choice_type(types::positioning_srs, type_, "ReferenceSignal"); - return c.get(); - } - const dl_prs_s& dl_prs() const - { - assert_choice_type(types::dl_prs, type_, "ReferenceSignal"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ReferenceSignal"); - return c.get>(); - } - uint8_t& set_nzp_csi_rs(); - ssb_s& set_ssb(); - uint8_t& set_srs(); - uint8_t& set_positioning_srs(); - dl_prs_s& set_dl_prs(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, ssb_s> c; - - void destroy_(); -}; - -// ResourceSetTypeAperiodic ::= SEQUENCE -struct res_set_type_aperiodic_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t srs_res_trigger = 1; - uint8_t slotoffset = 0; - res_set_type_aperiodic_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceSetTypePeriodic ::= SEQUENCE -struct res_set_type_periodic_s { - struct periodic_set_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using periodic_set_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - periodic_set_e_ periodic_set; - res_set_type_periodic_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceSetTypeSemi-persistent ::= SEQUENCE -struct res_set_type_semi_persistent_s { - struct semi_persistent_set_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using semi_persistent_set_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - semi_persistent_set_e_ semi_persistent_set; - res_set_type_semi_persistent_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceTypeAperiodicPos ::= SEQUENCE -struct res_type_aperiodic_pos_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t slot_offset = 0; - res_type_aperiodic_pos_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceTypeAperiodic ::= SEQUENCE -struct res_type_aperiodic_s { - struct aperiodic_res_type_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using aperiodic_res_type_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - aperiodic_res_type_e_ aperiodic_res_type; - res_type_aperiodic_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceTypePeriodicPos ::= SEQUENCE -struct res_type_periodic_pos_s { - struct periodicity_opts { - enum options { - slot1, - slot2, - slot4, - slot5, - slot8, - slot10, - slot16, - slot20, - slot32, - slot40, - slot64, - slot80, - slot160, - slot320, - slot640, - slot1280, - slot2560, - slot5120, - slot10240, - slot40960, - slot81920, - // ... - slot128, - slot256, - slot512, - slot20480, - nulltype - } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; - }; - using periodicity_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - periodicity_e_ periodicity; - uint32_t offset = 0; - res_type_periodic_pos_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceTypePeriodic ::= SEQUENCE -struct res_type_periodic_s { - struct periodicity_opts { - enum options { - slot1, - slot2, - slot4, - slot5, - slot8, - slot10, - slot16, - slot20, - slot32, - slot40, - slot64, - slot80, - slot160, - slot320, - slot640, - slot1280, - slot2560, - // ... - nulltype - } value; - typedef uint16_t number_type; - - const char* to_string() const; - uint16_t to_number() const; - }; - using periodicity_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - periodicity_e_ periodicity; - uint16_t offset = 0; - res_type_periodic_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceTypeSemi-persistentPos ::= SEQUENCE -struct res_type_semi_persistent_pos_s { - struct periodicity_opts { - enum options { - slot1, - slot2, - slot4, - slot5, - slot8, - slot10, - slot16, - slot20, - slot32, - slot40, - slot64, - slot80, - slot160, - slot320, - slot640, - slot1280, - slot2560, - slot5120, - slot10240, - slot40960, - slot81920, - // ... - slot128, - slot256, - slot512, - slot20480, - nulltype - } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; - }; - using periodicity_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - periodicity_e_ periodicity; - uint32_t offset = 0; - res_type_semi_persistent_pos_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResourceTypeSemi-persistent ::= SEQUENCE -struct res_type_semi_persistent_s { - struct periodicity_opts { - enum options { - slot1, - slot2, - slot4, - slot5, - slot8, - slot10, - slot16, - slot20, - slot32, - slot40, - slot64, - slot80, - slot160, - slot320, - slot640, - slot1280, - slot2560, - // ... - nulltype - } value; - typedef uint16_t number_type; - - const char* to_string() const; - uint16_t to_number() const; - }; - using periodicity_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - periodicity_e_ periodicity; - uint16_t offset = 0; - res_type_semi_persistent_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultCSI-RSRP-PerCSI-RS-Item ::= SEQUENCE -struct result_csi_rsrp_per_csi_rs_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t csi_rs_idx = 0; - uint8_t value_csi_rsrp = 0; - result_csi_rsrp_per_csi_rs_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultCSI-RSRQ-PerCSI-RS-Item ::= SEQUENCE -struct result_csi_rsrq_per_csi_rs_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t csi_rs_idx = 0; - uint8_t value_csi_rsrq = 0; - result_csi_rsrq_per_csi_rs_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultSS-RSRP-PerSSB-Item ::= SEQUENCE -struct result_ss_rsrp_per_ssb_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t ssb_idx = 0; - uint8_t value_ss_rsrp = 0; - result_ss_rsrp_per_ssb_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultSS-RSRQ-PerSSB-Item ::= SEQUENCE -struct result_ss_rsrq_per_ssb_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t ssb_idx = 0; - uint8_t value_ss_rsrq = 0; - result_ss_rsrq_per_ssb_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using spatial_relation_per_srs_res_item_ext_ies_container = protocol_ext_container_empty_l; - -using spatial_relationfor_res_id_item_ext_ies_container = protocol_ext_container_empty_l; - -// SRSResourceTypeChoice ::= CHOICE -struct srs_res_type_choice_c { - struct types_opts { - enum options { srs_res_info, pos_srs_res_info, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - srs_res_type_choice_c() = default; - srs_res_type_choice_c(const srs_res_type_choice_c& other); - srs_res_type_choice_c& operator=(const srs_res_type_choice_c& other); - ~srs_res_type_choice_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - srs_info_s& srs_res_info() - { - assert_choice_type(types::srs_res_info, type_, "SRSResourceTypeChoice"); - return c.get(); - } - pos_srs_info_s& pos_srs_res_info() - { - assert_choice_type(types::pos_srs_res_info, type_, "SRSResourceTypeChoice"); - return c.get(); - } - const srs_info_s& srs_res_info() const - { - assert_choice_type(types::srs_res_info, type_, "SRSResourceTypeChoice"); - return c.get(); - } - const pos_srs_info_s& pos_srs_res_info() const - { - assert_choice_type(types::pos_srs_res_info, type_, "SRSResourceTypeChoice"); - return c.get(); - } - srs_info_s& set_srs_res_info(); - pos_srs_info_s& set_pos_srs_res_info(); - -private: - types type_; - choice_buffer_t c; - - void destroy_(); -}; - -// SSBBurstPosition ::= CHOICE -struct ssb_burst_position_c { - struct types_opts { - enum options { short_bitmap, medium_bitmap, long_bitmap, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ssb_burst_position_c() = default; - ssb_burst_position_c(const ssb_burst_position_c& other); - ssb_burst_position_c& operator=(const ssb_burst_position_c& other); - ~ssb_burst_position_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - fixed_bitstring<4, false, true>& short_bitmap() - { - assert_choice_type(types::short_bitmap, type_, "SSBBurstPosition"); - return c.get>(); - } - fixed_bitstring<8, false, true>& medium_bitmap() - { - assert_choice_type(types::medium_bitmap, type_, "SSBBurstPosition"); - return c.get>(); - } - fixed_bitstring<64, false, true>& long_bitmap() - { - assert_choice_type(types::long_bitmap, type_, "SSBBurstPosition"); - return c.get>(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "SSBBurstPosition"); - return c.get>(); - } - const fixed_bitstring<4, false, true>& short_bitmap() const - { - assert_choice_type(types::short_bitmap, type_, "SSBBurstPosition"); - return c.get>(); - } - const fixed_bitstring<8, false, true>& medium_bitmap() const - { - assert_choice_type(types::medium_bitmap, type_, "SSBBurstPosition"); - return c.get>(); - } - const fixed_bitstring<64, false, true>& long_bitmap() const - { - assert_choice_type(types::long_bitmap, type_, "SSBBurstPosition"); - return c.get>(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "SSBBurstPosition"); - return c.get>(); - } - fixed_bitstring<4, false, true>& set_short_bitmap(); - fixed_bitstring<8, false, true>& set_medium_bitmap(); - fixed_bitstring<64, false, true>& set_long_bitmap(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, protocol_ie_single_container_s> c; - - void destroy_(); -}; - -using tf_cfg_ext_ies_container = protocol_ext_container_empty_l; - -using trp_beam_ant_info_ext_ies_container = protocol_ext_container_empty_l; - -// TRPPositionDefinitionType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using trp_position_definition_type_ext_ies_o = protocol_ies_empty_o; - -// TRPPositionDirectAccuracy ::= CHOICE -struct trp_position_direct_accuracy_c { - struct types_opts { - enum options { trp_position, trph_aposition, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trp_position_direct_accuracy_c() = default; - trp_position_direct_accuracy_c(const trp_position_direct_accuracy_c& other); - trp_position_direct_accuracy_c& operator=(const trp_position_direct_accuracy_c& other); - ~trp_position_direct_accuracy_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - ng_ran_access_point_position_s& trp_position() - { - assert_choice_type(types::trp_position, type_, "TRPPositionDirectAccuracy"); - return c.get(); - } - ngran_high_accuracy_access_point_position_s& trph_aposition() - { - assert_choice_type(types::trph_aposition, type_, "TRPPositionDirectAccuracy"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TRPPositionDirectAccuracy"); - return c.get>(); - } - const ng_ran_access_point_position_s& trp_position() const - { - assert_choice_type(types::trp_position, type_, "TRPPositionDirectAccuracy"); - return c.get(); - } - const ngran_high_accuracy_access_point_position_s& trph_aposition() const - { - assert_choice_type(types::trph_aposition, type_, "TRPPositionDirectAccuracy"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TRPPositionDirectAccuracy"); - return c.get>(); - } - ng_ran_access_point_position_s& set_trp_position(); - ngran_high_accuracy_access_point_position_s& set_trph_aposition(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> - c; - - void destroy_(); -}; - -using trp_position_direct_ext_ies_container = protocol_ext_container_empty_l; - -using trp_position_refd_ext_ies_container = protocol_ext_container_empty_l; - -// TRPReferencePointType ::= CHOICE -struct trp_ref_point_type_c { - struct types_opts { - enum options { trp_position_relative_geodetic, trp_position_relative_cartesian, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trp_ref_point_type_c() = default; - trp_ref_point_type_c(const trp_ref_point_type_c& other); - trp_ref_point_type_c& operator=(const trp_ref_point_type_c& other); - ~trp_ref_point_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - relative_geodetic_location_s& trp_position_relative_geodetic() - { - assert_choice_type(types::trp_position_relative_geodetic, type_, "TRPReferencePointType"); - return c.get(); - } - relative_cartesian_location_s& trp_position_relative_cartesian() - { - assert_choice_type(types::trp_position_relative_cartesian, type_, "TRPReferencePointType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TRPReferencePointType"); - return c.get>(); - } - const relative_geodetic_location_s& trp_position_relative_geodetic() const - { - assert_choice_type(types::trp_position_relative_geodetic, type_, "TRPReferencePointType"); - return c.get(); - } - const relative_cartesian_location_s& trp_position_relative_cartesian() const - { - assert_choice_type(types::trp_position_relative_cartesian, type_, "TRPReferencePointType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TRPReferencePointType"); - return c.get>(); - } - relative_geodetic_location_s& set_trp_position_relative_geodetic(); - relative_cartesian_location_s& set_trp_position_relative_cartesian(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - relative_cartesian_location_s, - relative_geodetic_location_s> - c; - - void destroy_(); -}; - -// TRPTEGItem ::= SEQUENCE -struct trpteg_item_s { - using dl_prs_res_id_list_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - trp_tx_teg_info_s trp_tx_teg_info; - uint8_t dl_prs_res_set_id = 0; - dl_prs_res_id_list_l_ dl_prs_res_id_list; - trpteg_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ULRTOAMeas-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using ul_rtoa_meas_ext_ies_o = protocol_ies_empty_o; - -// UL-RTOAMeasurement-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct ul_rtoameas_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { extended_add_path_list, trp_rx_teg_info, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - extended_add_path_list_l& extended_add_path_list(); - trp_rx_teg_info_s& trp_rx_teg_info(); - const extended_add_path_list_l& extended_add_path_list() const; - const trp_rx_teg_info_s& trp_rx_teg_info() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// AdditionalPathListItem ::= SEQUENCE -struct add_path_list_item_s { - bool ext = false; - bool path_quality_present = false; - bool ie_exts_present = false; - relative_path_delay_c relative_time_of_path; - trp_meas_quality_c path_quality; - add_path_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using cgi_eutra_ext_ies_container = protocol_ext_container_empty_l; - -// CGI-NR ::= SEQUENCE -struct cgi_nr_s { - bool ext = false; - bool ie_exts_present = false; - fixed_octstring<3, true> plmn_id; - fixed_bitstring<36, false, true> nr_cell_id; - cgi_nr_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using dl_prs_res_coordinates_ext_ies_container = protocol_ext_container_empty_l; - -// DLPRSResourceSetARP ::= SEQUENCE -struct dl_prs_res_set_arp_s { - using listof_dl_prs_res_arp_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint8_t dl_prs_res_set_id = 0; - dl_prs_res_set_arp_location_c dl_prs_res_set_arp_location; - listof_dl_prs_res_arp_l_ listof_dl_prs_res_arp; - dl_prs_res_set_arp_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// Expected-UL-AoA ::= SEQUENCE -struct expected_ul_ao_a_s { - bool ext = false; - bool expected_zenith_ao_a_present = false; - bool ie_exts_present = false; - expected_azimuth_ao_a_s expected_azimuth_ao_a; - expected_zenith_ao_a_s expected_zenith_ao_a; - expected_ul_ao_a_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// Expected-ZoA-only ::= SEQUENCE -struct expected_zo_a_only_s { - bool ext = false; - bool ie_exts_present = false; - expected_zenith_ao_a_s expected_zo_a_only; - expected_zo_a_only_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// GeographicalCoordinates-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct geographical_coordinates_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { arp_location_info, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::arp_location_info; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - arp_location_info_l& arp_location_info() { return c; } - const arp_location_info_l& arp_location_info() const { return c; } - - private: - arp_location_info_l c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// LCS-to-GCS-TranslationItem ::= SEQUENCE -struct lcs_to_gcs_translation_item_s { - bool ext = false; - bool alpha_fine_present = false; - bool beta_fine_present = false; - bool gamma_fine_present = false; - bool ie_exts_present = false; - uint16_t alpha = 0; - uint8_t alpha_fine = 0; - uint16_t beta = 0; - uint8_t beta_fine = 0; - uint16_t gamma = 0; - uint8_t gamma_fine = 0; - lcs_to_gcs_translation_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// LoS-NLoSInformation ::= CHOICE -struct lo_s_n_lo_si_nformation_c { - struct types_opts { - enum options { lo_s_n_lo_si_ndicator_soft, lo_s_n_lo_si_ndicator_hard, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - lo_s_n_lo_si_nformation_c() = default; - lo_s_n_lo_si_nformation_c(const lo_s_n_lo_si_nformation_c& other); - lo_s_n_lo_si_nformation_c& operator=(const lo_s_n_lo_si_nformation_c& other); - ~lo_s_n_lo_si_nformation_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lo_s_n_lo_si_ndicator_soft() - { - assert_choice_type(types::lo_s_n_lo_si_ndicator_soft, type_, "LoS-NLoSInformation"); - return c.get(); - } - lo_s_n_lo_si_ndicator_hard_e& lo_s_n_lo_si_ndicator_hard() - { - assert_choice_type(types::lo_s_n_lo_si_ndicator_hard, type_, "LoS-NLoSInformation"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "LoS-NLoSInformation"); - return c.get>(); - } - const uint8_t& lo_s_n_lo_si_ndicator_soft() const - { - assert_choice_type(types::lo_s_n_lo_si_ndicator_soft, type_, "LoS-NLoSInformation"); - return c.get(); - } - const lo_s_n_lo_si_ndicator_hard_e& lo_s_n_lo_si_ndicator_hard() const - { - assert_choice_type(types::lo_s_n_lo_si_ndicator_hard, type_, "LoS-NLoSInformation"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "LoS-NLoSInformation"); - return c.get>(); - } - uint8_t& set_lo_s_n_lo_si_ndicator_soft(); - lo_s_n_lo_si_ndicator_hard_e& set_lo_s_n_lo_si_ndicator_hard(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -using nr_prs_beam_info_ies_container = protocol_ext_container_empty_l; - -// NR-PRS-Beam-InformationItem ::= SEQUENCE -struct nr_prs_beam_info_item_s { - using prs_angle_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint8_t pr_sres_set_id = 0; - prs_angle_l_ prs_angle; - nr_prs_beam_info_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// OnDemandPRS-Info ::= SEQUENCE -struct on_demand_prs_info_s { - bool ext = false; - bool allowed_res_set_periodicity_values_present = false; - bool allowed_prs_bw_values_present = false; - bool allowed_res_repeat_factor_values_present = false; - bool allowed_res_nof_symbols_values_present = false; - bool allowed_comb_size_values_present = false; - bool ie_exts_present = false; - fixed_bitstring<16, false, true> on_demand_prs_request_allowed; - fixed_bitstring<24, false, true> allowed_res_set_periodicity_values; - fixed_bitstring<64, false, true> allowed_prs_bw_values; - fixed_bitstring<8, false, true> allowed_res_repeat_factor_values; - fixed_bitstring<8, false, true> allowed_res_nof_symbols_values; - fixed_bitstring<8, false, true> allowed_comb_size_values; - on_demand_prs_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PosResourceSetType ::= CHOICE -struct pos_res_set_type_c { - struct types_opts { - enum options { periodic, semi_persistent, aperiodic, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - pos_res_set_type_c() = default; - pos_res_set_type_c(const pos_res_set_type_c& other); - pos_res_set_type_c& operator=(const pos_res_set_type_c& other); - ~pos_res_set_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - pos_res_set_type_periodic_s& periodic() - { - assert_choice_type(types::periodic, type_, "PosResourceSetType"); - return c.get(); - } - pos_res_set_type_semi_persistent_s& semi_persistent() - { - assert_choice_type(types::semi_persistent, type_, "PosResourceSetType"); - return c.get(); - } - pos_res_set_type_aperiodic_s& aperiodic() - { - assert_choice_type(types::aperiodic, type_, "PosResourceSetType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "PosResourceSetType"); - return c.get>(); - } - const pos_res_set_type_periodic_s& periodic() const - { - assert_choice_type(types::periodic, type_, "PosResourceSetType"); - return c.get(); - } - const pos_res_set_type_semi_persistent_s& semi_persistent() const - { - assert_choice_type(types::semi_persistent, type_, "PosResourceSetType"); - return c.get(); - } - const pos_res_set_type_aperiodic_s& aperiodic() const - { - assert_choice_type(types::aperiodic, type_, "PosResourceSetType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "PosResourceSetType"); - return c.get>(); - } - pos_res_set_type_periodic_s& set_periodic(); - pos_res_set_type_semi_persistent_s& set_semi_persistent(); - pos_res_set_type_aperiodic_s& set_aperiodic(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> - c; - - void destroy_(); -}; - -using pos_sib_segments_ext_ies_container = protocol_ext_container_empty_l; - -// PosSRSResourceIDPerSet-List ::= SEQUENCE (SIZE (1..16)) OF INTEGER (0..63) -using pos_srs_res_id_per_set_list_l = bounded_array; - -using pos_srs_res_item_ext_ies_container = protocol_ext_container_empty_l; - -using pos_srs_res_set_item_ext_ies_container = protocol_ext_container_empty_l; - -// PRSResourceSet-Item ::= SEQUENCE -struct prs_res_set_item_s { - struct subcarrier_spacing_opts { - enum options { khz15, khz30, khz60, khz120, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using subcarrier_spacing_e_ = enumerated; - struct comb_size_opts { - enum options { n2, n4, n6, n12, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using comb_size_e_ = enumerated; - struct cp_type_opts { - enum options { normal, extended, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using cp_type_e_ = enumerated; - struct res_set_periodicity_opts { - enum options { - n4, - n5, - n8, - n10, - n16, - n20, - n32, - n40, - n64, - n80, - n160, - n320, - n640, - n1280, - n2560, - n5120, - n10240, - n20480, - n40960, - n81920, - // ... - nulltype - } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; - }; - using res_set_periodicity_e_ = enumerated; - struct res_repeat_factor_opts { - enum options { rf1, rf2, rf4, rf6, rf8, rf16, rf32, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using res_repeat_factor_e_ = enumerated; - struct res_time_gap_opts { - enum options { tg1, tg2, tg4, tg8, tg16, tg32, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using res_time_gap_e_ = enumerated; - struct res_numof_symbols_opts { - enum options { n2, n4, n6, n12, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using res_numof_symbols_e_ = enumerated; - - // member variables - bool ext = false; - bool prs_muting_present = false; - bool ie_exts_present = false; - uint8_t prs_res_set_id = 0; - subcarrier_spacing_e_ subcarrier_spacing; - uint8_t pr_sbw = 1; - uint16_t start_prb = 0; - uint32_t point_a = 0; - comb_size_e_ comb_size; - cp_type_e_ cp_type; - res_set_periodicity_e_ res_set_periodicity; - uint32_t res_set_slot_offset = 0; - res_repeat_factor_e_ res_repeat_factor; - res_time_gap_e_ res_time_gap; - res_numof_symbols_e_ res_numof_symbols; - prs_muting_s prs_muting; - int8_t prs_res_tx_pwr = -60; - prs_res_list_l prs_res_list; - prs_res_set_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using prs_tx_off_ind_per_res_item_ext_ies_container = protocol_ext_container_empty_l; - -using requested_dl_prs_res_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResourceSetType ::= CHOICE -struct res_set_type_c { - struct types_opts { - enum options { periodic, semi_persistent, aperiodic, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - res_set_type_c() = default; - res_set_type_c(const res_set_type_c& other); - res_set_type_c& operator=(const res_set_type_c& other); - ~res_set_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - res_set_type_periodic_s& periodic() - { - assert_choice_type(types::periodic, type_, "ResourceSetType"); - return c.get(); - } - res_set_type_semi_persistent_s& semi_persistent() - { - assert_choice_type(types::semi_persistent, type_, "ResourceSetType"); - return c.get(); - } - res_set_type_aperiodic_s& aperiodic() - { - assert_choice_type(types::aperiodic, type_, "ResourceSetType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ResourceSetType"); - return c.get>(); - } - const res_set_type_periodic_s& periodic() const - { - assert_choice_type(types::periodic, type_, "ResourceSetType"); - return c.get(); - } - const res_set_type_semi_persistent_s& semi_persistent() const - { - assert_choice_type(types::semi_persistent, type_, "ResourceSetType"); - return c.get(); - } - const res_set_type_aperiodic_s& aperiodic() const - { - assert_choice_type(types::aperiodic, type_, "ResourceSetType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ResourceSetType"); - return c.get>(); - } - res_set_type_periodic_s& set_periodic(); - res_set_type_semi_persistent_s& set_semi_persistent(); - res_set_type_aperiodic_s& set_aperiodic(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - res_set_type_aperiodic_s, - res_set_type_periodic_s, - res_set_type_semi_persistent_s> - c; - - void destroy_(); -}; - -// ResourceType ::= CHOICE -struct res_type_c { - struct types_opts { - enum options { periodic, semi_persistent, aperiodic, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - res_type_c() = default; - res_type_c(const res_type_c& other); - res_type_c& operator=(const res_type_c& other); - ~res_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - res_type_periodic_s& periodic() - { - assert_choice_type(types::periodic, type_, "ResourceType"); - return c.get(); - } - res_type_semi_persistent_s& semi_persistent() - { - assert_choice_type(types::semi_persistent, type_, "ResourceType"); - return c.get(); - } - res_type_aperiodic_s& aperiodic() - { - assert_choice_type(types::aperiodic, type_, "ResourceType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ResourceType"); - return c.get>(); - } - const res_type_periodic_s& periodic() const - { - assert_choice_type(types::periodic, type_, "ResourceType"); - return c.get(); - } - const res_type_semi_persistent_s& semi_persistent() const - { - assert_choice_type(types::semi_persistent, type_, "ResourceType"); - return c.get(); - } - const res_type_aperiodic_s& aperiodic() const - { - assert_choice_type(types::aperiodic, type_, "ResourceType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ResourceType"); - return c.get>(); - } - res_type_periodic_s& set_periodic(); - res_type_semi_persistent_s& set_semi_persistent(); - res_type_aperiodic_s& set_aperiodic(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - res_type_aperiodic_s, - res_type_periodic_s, - res_type_semi_persistent_s> - c; - - void destroy_(); -}; - -// ResourceTypePos ::= CHOICE -struct res_type_pos_c { - struct types_opts { - enum options { periodic, semi_persistent, aperiodic, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - res_type_pos_c() = default; - res_type_pos_c(const res_type_pos_c& other); - res_type_pos_c& operator=(const res_type_pos_c& other); - ~res_type_pos_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - res_type_periodic_pos_s& periodic() - { - assert_choice_type(types::periodic, type_, "ResourceTypePos"); - return c.get(); - } - res_type_semi_persistent_pos_s& semi_persistent() - { - assert_choice_type(types::semi_persistent, type_, "ResourceTypePos"); - return c.get(); - } - res_type_aperiodic_pos_s& aperiodic() - { - assert_choice_type(types::aperiodic, type_, "ResourceTypePos"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ResourceTypePos"); - return c.get>(); - } - const res_type_periodic_pos_s& periodic() const - { - assert_choice_type(types::periodic, type_, "ResourceTypePos"); - return c.get(); - } - const res_type_semi_persistent_pos_s& semi_persistent() const - { - assert_choice_type(types::semi_persistent, type_, "ResourceTypePos"); - return c.get(); - } - const res_type_aperiodic_pos_s& aperiodic() const - { - assert_choice_type(types::aperiodic, type_, "ResourceTypePos"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ResourceTypePos"); - return c.get>(); - } - res_type_periodic_pos_s& set_periodic(); - res_type_semi_persistent_pos_s& set_semi_persistent(); - res_type_aperiodic_pos_s& set_aperiodic(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - res_type_aperiodic_pos_s, - res_type_periodic_pos_s, - res_type_semi_persistent_pos_s> - c; - - void destroy_(); -}; - -using result_csi_rsrp_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultCSI-RSRP-PerCSI-RS ::= SEQUENCE (SIZE (1..64)) OF ResultCSI-RSRP-PerCSI-RS-Item -using result_csi_rsrp_per_csi_rs_l = dyn_array; - -using result_csi_rsrq_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultCSI-RSRQ-PerCSI-RS ::= SEQUENCE (SIZE (1..64)) OF ResultCSI-RSRQ-PerCSI-RS-Item -using result_csi_rsrq_per_csi_rs_l = dyn_array; - -using result_ss_rsrp_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultSS-RSRP-PerSSB ::= SEQUENCE (SIZE (1..64)) OF ResultSS-RSRP-PerSSB-Item -using result_ss_rsrp_per_ssb_l = dyn_array; - -using result_ss_rsrq_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultSS-RSRQ-PerSSB ::= SEQUENCE (SIZE (1..64)) OF ResultSS-RSRQ-PerSSB-Item -using result_ss_rsrq_per_ssb_l = dyn_array; - -// SpatialRelationPerSRSResourceItem ::= SEQUENCE -struct spatial_relation_per_srs_res_item_s { - bool ext = false; - bool ie_exts_present = false; - ref_sig_c ref_sig; - spatial_relation_per_srs_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SpatialRelationPos ::= CHOICE -struct spatial_relation_pos_c { - struct types_opts { - enum options { ssb_pos, pr_si_nformation_pos, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - spatial_relation_pos_c() = default; - spatial_relation_pos_c(const spatial_relation_pos_c& other); - spatial_relation_pos_c& operator=(const spatial_relation_pos_c& other); - ~spatial_relation_pos_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - ssb_s& ssb_pos() - { - assert_choice_type(types::ssb_pos, type_, "SpatialRelationPos"); - return c.get(); - } - pr_si_nformation_pos_s& pr_si_nformation_pos() - { - assert_choice_type(types::pr_si_nformation_pos, type_, "SpatialRelationPos"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "SpatialRelationPos"); - return c.get>(); - } - const ssb_s& ssb_pos() const - { - assert_choice_type(types::ssb_pos, type_, "SpatialRelationPos"); - return c.get(); - } - const pr_si_nformation_pos_s& pr_si_nformation_pos() const - { - assert_choice_type(types::pr_si_nformation_pos, type_, "SpatialRelationPos"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "SpatialRelationPos"); - return c.get>(); - } - ssb_s& set_ssb_pos(); - pr_si_nformation_pos_s& set_pr_si_nformation_pos(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, ssb_s> c; - - void destroy_(); -}; - -// SpatialRelationforResourceIDItem ::= SEQUENCE -struct spatial_relationfor_res_id_item_s { - bool ext = false; - bool ie_exts_present = false; - ref_sig_c ref_sig; - spatial_relationfor_res_id_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using srs_res_ext_ies_container = protocol_ext_container_empty_l; - -// SRSResourceID-List ::= SEQUENCE (SIZE (1..16)) OF INTEGER (0..63) -using srs_res_id_list_l = bounded_array; - -using srs_res_set_ext_ies_container = protocol_ext_container_empty_l; - -// SRSResourcetype ::= SEQUENCE -struct srs_restype_s { - bool ext = false; - srs_res_type_choice_c srs_res_type_choice; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using ssb_info_item_ext_ies_container = protocol_ext_container_empty_l; - -using tdd_cfg_eutra_item_item_ext_ies_container = protocol_ext_container_empty_l; - -// TF-Configuration ::= SEQUENCE -struct tf_cfg_s { - struct ssb_subcarrier_spacing_opts { - enum options { khz15, khz30, khz120, khz240, /*...*/ khz60, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using ssb_subcarrier_spacing_e_ = enumerated; - struct ssb_periodicity_opts { - enum options { ms5, ms10, ms20, ms40, ms80, ms160, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using ssb_periodicity_e_ = enumerated; - - // member variables - bool ext = false; - bool ssb_burst_position_present = false; - bool sfn_initisation_time_present = false; - bool ie_exts_present = false; - uint32_t ssb_freq = 0; - ssb_subcarrier_spacing_e_ ssb_subcarrier_spacing; - int8_t ssb_tx_pwr = -60; - ssb_periodicity_e_ ssb_periodicity; - uint8_t ssb_half_frame_offset = 0; - uint8_t ssb_sfn_offset = 0; - ssb_burst_position_c ssb_burst_position; - fixed_bitstring<64, false, true> sfn_initisation_time; - tf_cfg_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TimeStampSlotIndex-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using time_stamp_slot_idx_ext_ies_o = protocol_ies_empty_o; - -// TRPBeamAntennaInformation ::= SEQUENCE -struct trp_beam_ant_info_s { - bool ext = false; - bool ie_exts_present = false; - choice_trp_beam_ant_info_item_c choice_trp_beam_ant_info_item; - trp_beam_ant_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPPositionDirect ::= SEQUENCE -struct trp_position_direct_s { - bool ext = false; - bool ie_exts_present = false; - trp_position_direct_accuracy_c accuracy; - trp_position_direct_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPPositionReferenced ::= SEQUENCE -struct trp_position_refd_s { - bool ext = false; - bool ie_exts_present = false; - ref_point_c ref_point; - trp_ref_point_type_c ref_point_type; - trp_position_refd_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPTxTEGAssociation ::= SEQUENCE (SIZE (1..8)) OF TRPTEGItem -using trp_tx_teg_assoc_l = dyn_array; - -// TRPType ::= ENUMERATED -struct trp_type_opts { - enum options { prs_only_tp, srs_only_rp, tp, rp, trp, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using trp_type_e = enumerated; - -// TransmissionComb ::= CHOICE -struct tx_comb_c { - struct n2_s_ { - uint8_t comb_offset_n2 = 0; - uint8_t cyclic_shift_n2 = 0; - }; - struct n4_s_ { - uint8_t comb_offset_n4 = 0; - uint8_t cyclic_shift_n4 = 0; - }; - struct types_opts { - enum options { n2, n4, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - tx_comb_c() = default; - tx_comb_c(const tx_comb_c& other); - tx_comb_c& operator=(const tx_comb_c& other); - ~tx_comb_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - n2_s_& n2() - { - assert_choice_type(types::n2, type_, "TransmissionComb"); - return c.get(); - } - n4_s_& n4() - { - assert_choice_type(types::n4, type_, "TransmissionComb"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TransmissionComb"); - return c.get>(); - } - const n2_s_& n2() const - { - assert_choice_type(types::n2, type_, "TransmissionComb"); - return c.get(); - } - const n4_s_& n4() const - { - assert_choice_type(types::n4, type_, "TransmissionComb"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TransmissionComb"); - return c.get>(); - } - n2_s_& set_n2(); - n4_s_& set_n4(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// TransmissionCombPos ::= CHOICE -struct tx_comb_pos_c { - struct n2_s_ { - uint8_t comb_offset_n2 = 0; - uint8_t cyclic_shift_n2 = 0; - }; - struct n4_s_ { - uint8_t comb_offset_n4 = 0; - uint8_t cyclic_shift_n4 = 0; - }; - struct n8_s_ { - uint8_t comb_offset_n8 = 0; - uint8_t cyclic_shift_n8 = 0; - }; - struct types_opts { - enum options { n2, n4, n8, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - tx_comb_pos_c() = default; - tx_comb_pos_c(const tx_comb_pos_c& other); - tx_comb_pos_c& operator=(const tx_comb_pos_c& other); - ~tx_comb_pos_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - n2_s_& n2() - { - assert_choice_type(types::n2, type_, "TransmissionCombPos"); - return c.get(); - } - n4_s_& n4() - { - assert_choice_type(types::n4, type_, "TransmissionCombPos"); - return c.get(); - } - n8_s_& n8() - { - assert_choice_type(types::n8, type_, "TransmissionCombPos"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TransmissionCombPos"); - return c.get>(); - } - const n2_s_& n2() const - { - assert_choice_type(types::n2, type_, "TransmissionCombPos"); - return c.get(); - } - const n4_s_& n4() const - { - assert_choice_type(types::n4, type_, "TransmissionCombPos"); - return c.get(); - } - const n8_s_& n8() const - { - assert_choice_type(types::n8, type_, "TransmissionCombPos"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TransmissionCombPos"); - return c.get>(); - } - n2_s_& set_n2(); - n4_s_& set_n4(); - n8_s_& set_n8(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// AdditionalPathList ::= SEQUENCE (SIZE (1..2)) OF AdditionalPathListItem -using add_path_list_l = dyn_array; - -// AngleMeasurementType ::= CHOICE -struct angle_meas_type_c { - struct types_opts { - enum options { expected_ul_ao_a, expected_zo_a, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - angle_meas_type_c() = default; - angle_meas_type_c(const angle_meas_type_c& other); - angle_meas_type_c& operator=(const angle_meas_type_c& other); - ~angle_meas_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - expected_ul_ao_a_s& expected_ul_ao_a() - { - assert_choice_type(types::expected_ul_ao_a, type_, "AngleMeasurementType"); - return c.get(); - } - expected_zo_a_only_s& expected_zo_a() - { - assert_choice_type(types::expected_zo_a, type_, "AngleMeasurementType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "AngleMeasurementType"); - return c.get>(); - } - const expected_ul_ao_a_s& expected_ul_ao_a() const - { - assert_choice_type(types::expected_ul_ao_a, type_, "AngleMeasurementType"); - return c.get(); - } - const expected_zo_a_only_s& expected_zo_a() const - { - assert_choice_type(types::expected_zo_a, type_, "AngleMeasurementType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "AngleMeasurementType"); - return c.get>(); - } - expected_ul_ao_a_s& set_expected_ul_ao_a(); - expected_zo_a_only_s& set_expected_zo_a(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> - c; - - void destroy_(); -}; - -using ao_a_assist_info_ext_ies_container = protocol_ext_container_empty_l; - -using assist_info_meta_data_ext_ies_container = protocol_ext_container_empty_l; - -// CGI-EUTRA ::= SEQUENCE -struct cgi_eutra_s { - bool ext = false; - bool ie_exts_present = false; - fixed_octstring<3, true> plmn_id; - fixed_bitstring<28, false, true> eutr_acell_id; - cgi_eutra_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// DLPRSResourceCoordinates ::= SEQUENCE -struct dl_prs_res_coordinates_s { - using listof_dl_prs_res_set_arp_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - listof_dl_prs_res_set_arp_l_ listof_dl_prs_res_set_arp; - dl_prs_res_coordinates_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct gnb_rx_tx_time_diff_ext_ies_container { - bool extended_add_path_list_present = false; - bool trpteg_info_present = false; - extended_add_path_list_l extended_add_path_list; - trpteg_info_c trpteg_info; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// GNBRxTxTimeDiffMeas ::= CHOICE -struct gnb_rx_tx_time_diff_meas_c { - struct types_opts { - enum options { k0, k1, k2, k3, k4, k5, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - gnb_rx_tx_time_diff_meas_c() = default; - gnb_rx_tx_time_diff_meas_c(const gnb_rx_tx_time_diff_meas_c& other); - gnb_rx_tx_time_diff_meas_c& operator=(const gnb_rx_tx_time_diff_meas_c& other); - ~gnb_rx_tx_time_diff_meas_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& k0() - { - assert_choice_type(types::k0, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - uint32_t& k1() - { - assert_choice_type(types::k1, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - uint32_t& k2() - { - assert_choice_type(types::k2, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - uint32_t& k3() - { - assert_choice_type(types::k3, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - uint32_t& k4() - { - assert_choice_type(types::k4, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - uint16_t& k5() - { - assert_choice_type(types::k5, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "GNBRxTxTimeDiffMeas"); - return c.get>(); - } - const uint32_t& k0() const - { - assert_choice_type(types::k0, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - const uint32_t& k1() const - { - assert_choice_type(types::k1, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - const uint32_t& k2() const - { - assert_choice_type(types::k2, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - const uint32_t& k3() const - { - assert_choice_type(types::k3, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - const uint32_t& k4() const - { - assert_choice_type(types::k4, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - const uint16_t& k5() const - { - assert_choice_type(types::k5, type_, "GNBRxTxTimeDiffMeas"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "GNBRxTxTimeDiffMeas"); - return c.get>(); - } - uint32_t& set_k0(); - uint32_t& set_k1(); - uint32_t& set_k2(); - uint32_t& set_k3(); - uint32_t& set_k4(); - uint16_t& set_k5(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// NR-PRS-Beam-Information ::= SEQUENCE -struct nr_prs_beam_info_s { - using nr_prs_beam_info_list_l_ = dyn_array; - using lcs_to_gcs_translation_list_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - nr_prs_beam_info_list_l_ nr_prs_beam_info_list; - lcs_to_gcs_translation_list_l_ lcs_to_gcs_translation_list; - nr_prs_beam_info_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct pos_sib_segments_item_s_ { - bool ext = false; - bool ie_exts_present = false; - unbounded_octstring assist_data_sib_elem; - pos_sib_segments_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PosSRSResource-Item ::= SEQUENCE -struct pos_srs_res_item_s { - struct nrof_symbols_opts { - enum options { n1, n2, n4, n8, n12, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using nrof_symbols_e_ = enumerated; - struct group_or_seq_hop_opts { - enum options { neither, group_hop, seq_hop, nulltype } value; - - const char* to_string() const; - }; - using group_or_seq_hop_e_ = enumerated; - - // member variables - bool ext = false; - bool spatial_relation_pos_present = false; - bool ie_exts_present = false; - uint8_t srs_pos_res_id = 0; - tx_comb_pos_c tx_comb_pos; - uint8_t start_position = 0; - nrof_symbols_e_ nrof_symbols; - uint16_t freq_domain_shift = 0; - uint8_t c_srs = 0; - group_or_seq_hop_e_ group_or_seq_hop; - res_type_pos_c res_type_pos; - uint32_t seq_id = 0; - spatial_relation_pos_c spatial_relation_pos; - pos_srs_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PosSRSResourceSet-Item ::= SEQUENCE -struct pos_srs_res_set_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t possrs_res_set_id = 0; - pos_srs_res_id_per_set_list_l poss_rs_res_id_per_set_list; - pos_res_set_type_c posres_set_type; - pos_srs_res_set_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using prs_cfg_ext_ies_container = protocol_ext_container_empty_l; - -// PRSMutingConfiguration-EUTRA-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using prs_muting_cfg_eutra_ext_ie_o = protocol_ies_empty_o; - -// PRSResourceSet-List ::= SEQUENCE (SIZE (1..8)) OF PRSResourceSet-Item -using prs_res_set_list_l = dyn_array; - -// PRSTransmissionOffIndicationPerResource-Item ::= SEQUENCE -struct prs_tx_off_ind_per_res_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t prs_res_id = 0; - prs_tx_off_ind_per_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using prs_tx_off_per_res_item_ext_ies_container = protocol_ext_container_empty_l; - -using prs_tx_off_per_res_set_item_ext_ies_container = protocol_ext_container_empty_l; - -// RequestedDLPRSResource-Item ::= SEQUENCE -struct requested_dl_prs_res_item_s { - bool ext = false; - bool qcl_info_present = false; - bool ie_exts_present = false; - prs_res_qcl_info_c qcl_info; - requested_dl_prs_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultCSI-RSRP-Item ::= SEQUENCE -struct result_csi_rsrp_item_s { - bool ext = false; - bool cgi_nr_present = false; - bool value_csi_rsrp_cell_present = false; - bool ie_exts_present = false; - uint16_t nr_pci = 0; - uint32_t nr_arfcn = 0; - cgi_nr_s cgi_nr; - uint8_t value_csi_rsrp_cell = 0; - result_csi_rsrp_per_csi_rs_l csi_rsrp_per_csi_rs; - result_csi_rsrp_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultCSI-RSRQ-Item ::= SEQUENCE -struct result_csi_rsrq_item_s { - bool ext = false; - bool cgi_nr_present = false; - bool value_csi_rsrq_cell_present = false; - bool ie_exts_present = false; - uint16_t nr_pci = 0; - uint32_t nr_arfcn = 0; - cgi_nr_s cgi_nr; - uint8_t value_csi_rsrq_cell = 0; - result_csi_rsrq_per_csi_rs_l csi_rsrq_per_csi_rs; - result_csi_rsrq_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using result_eutra_item_ext_ies_container = protocol_ext_container_empty_l; - -using result_nr_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultSS-RSRP-Item ::= SEQUENCE -struct result_ss_rsrp_item_s { - bool ext = false; - bool cgi_nr_present = false; - bool value_ss_rsrp_cell_present = false; - bool ie_exts_present = false; - uint16_t nr_pci = 0; - uint32_t nr_arfcn = 0; - cgi_nr_s cgi_nr; - uint8_t value_ss_rsrp_cell = 0; - result_ss_rsrp_per_ssb_l ss_rsrp_per_ssb; - result_ss_rsrp_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultSS-RSRQ-Item ::= SEQUENCE -struct result_ss_rsrq_item_s { - bool ext = false; - bool cgi_nr_present = false; - bool value_ss_rsrq_cell_present = false; - bool ie_exts_present = false; - uint16_t nr_pci = 0; - uint32_t nr_arfcn = 0; - cgi_nr_s cgi_nr; - uint8_t value_ss_rsrq_cell = 0; - result_ss_rsrq_per_ssb_l ss_rsrq_per_ssb; - result_ss_rsrq_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using spatial_direction_info_ext_ies_container = protocol_ext_container_empty_l; - -using spatial_relation_info_ext_ies_container = protocol_ext_container_empty_l; - -using spatial_relation_per_srs_res_ext_ies_container = protocol_ext_container_empty_l; - -// SpatialRelationPerSRSResource-List ::= SEQUENCE (SIZE (1..16)) OF SpatialRelationPerSRSResourceItem -using spatial_relation_per_srs_res_list_l = dyn_array; - -// SpatialRelationforResourceID ::= SEQUENCE (SIZE (1..64)) OF SpatialRelationforResourceIDItem -using spatial_relationfor_res_id_l = dyn_array; - -// SRSResource ::= SEQUENCE -struct srs_res_s { - struct nrof_srs_ports_opts { - enum options { port1, ports2, ports4, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using nrof_srs_ports_e_ = enumerated; - struct nrof_symbols_opts { - enum options { n1, n2, n4, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using nrof_symbols_e_ = enumerated; - struct repeat_factor_opts { - enum options { n1, n2, n4, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using repeat_factor_e_ = enumerated; - struct group_or_seq_hop_opts { - enum options { neither, group_hop, seq_hop, nulltype } value; - - const char* to_string() const; - }; - using group_or_seq_hop_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint8_t srs_res_id = 0; - nrof_srs_ports_e_ nrof_srs_ports; - tx_comb_c tx_comb; - uint8_t start_position = 0; - nrof_symbols_e_ nrof_symbols; - repeat_factor_e_ repeat_factor; - uint8_t freq_domain_position = 0; - uint16_t freq_domain_shift = 0; - uint8_t c_srs = 0; - uint8_t b_srs = 0; - uint8_t b_hop = 0; - group_or_seq_hop_e_ group_or_seq_hop; - res_type_c res_type; - uint16_t seq_id = 0; - srs_res_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSResourceSet ::= SEQUENCE -struct srs_res_set_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t srs_res_set_id = 0; - srs_res_id_list_l srs_res_id_list; - res_set_type_c res_set_type; - srs_res_set_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using ssb_info_ext_ies_container = protocol_ext_container_empty_l; - -// SSBInfoItem ::= SEQUENCE -struct ssb_info_item_s { - bool ext = false; - bool ie_exts_present = false; - tf_cfg_s ssb_cfg; - uint16_t pci_nr = 0; - ssb_info_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using start_time_and_dur_ext_ies_container = protocol_ext_container_empty_l; - -// TDD-Config-EUTRA-Item ::= SEQUENCE -struct tdd_cfg_eutra_item_s { - struct sf_assign_opts { - enum options { sa0, sa1, sa2, sa3, sa4, sa5, sa6, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using sf_assign_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - sf_assign_e_ sf_assign; - tdd_cfg_eutra_item_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPInformationTypeResponseItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct trp_info_type_resp_item_ext_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { trp_type, on_demand_prs, trp_tx_teg_assoc, trp_beam_ant_info, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_type_e& trp_type(); - on_demand_prs_info_s& on_demand_prs(); - trp_tx_teg_assoc_l& trp_tx_teg_assoc(); - trp_beam_ant_info_s& trp_beam_ant_info(); - const trp_type_e& trp_type() const; - const on_demand_prs_info_s& on_demand_prs() const; - const trp_tx_teg_assoc_l& trp_tx_teg_assoc() const; - const trp_beam_ant_info_s& trp_beam_ant_info() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TrpMeasurementResultItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct trp_meas_result_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { srs_restype, arp_id, lo_s_n_lo_si_nformation, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - srs_restype_s& srs_restype(); - uint8_t& arp_id(); - lo_s_n_lo_si_nformation_c& lo_s_n_lo_si_nformation(); - const srs_restype_s& srs_restype() const; - const uint8_t& arp_id() const; - const lo_s_n_lo_si_nformation_c& lo_s_n_lo_si_nformation() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TrpMeasuredResultsValue-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct trp_measured_results_value_ext_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { zo_a, multiple_ul_ao_a, ul_srs_rsrp_p, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - zo_a_s& zo_a(); - multiple_ul_ao_a_s& multiple_ul_ao_a(); - ul_srs_rsrp_p_s& ul_srs_rsrp_p(); - const zo_a_s& zo_a() const; - const multiple_ul_ao_a_s& multiple_ul_ao_a() const; - const ul_srs_rsrp_p_s& ul_srs_rsrp_p() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TRPPositionDefinitionType ::= CHOICE -struct trp_position_definition_type_c { - struct types_opts { - enum options { direct, refd, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trp_position_definition_type_c() = default; - trp_position_definition_type_c(const trp_position_definition_type_c& other); - trp_position_definition_type_c& operator=(const trp_position_definition_type_c& other); - ~trp_position_definition_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_position_direct_s& direct() - { - assert_choice_type(types::direct, type_, "TRPPositionDefinitionType"); - return c.get(); - } - trp_position_refd_s& refd() - { - assert_choice_type(types::refd, type_, "TRPPositionDefinitionType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TRPPositionDefinitionType"); - return c.get>(); - } - const trp_position_direct_s& direct() const - { - assert_choice_type(types::direct, type_, "TRPPositionDefinitionType"); - return c.get(); - } - const trp_position_refd_s& refd() const - { - assert_choice_type(types::refd, type_, "TRPPositionDefinitionType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TRPPositionDefinitionType"); - return c.get>(); - } - trp_position_direct_s& set_direct(); - trp_position_refd_s& set_refd(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - trp_position_direct_s, - trp_position_refd_s> - c; - - void destroy_(); -}; - -// ULRTOAMeas ::= CHOICE -struct ul_rtoa_meas_c { - struct types_opts { - enum options { k0, k1, k2, k3, k4, k5, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - ul_rtoa_meas_c() = default; - ul_rtoa_meas_c(const ul_rtoa_meas_c& other); - ul_rtoa_meas_c& operator=(const ul_rtoa_meas_c& other); - ~ul_rtoa_meas_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& k0() - { - assert_choice_type(types::k0, type_, "ULRTOAMeas"); - return c.get(); - } - uint32_t& k1() - { - assert_choice_type(types::k1, type_, "ULRTOAMeas"); - return c.get(); - } - uint32_t& k2() - { - assert_choice_type(types::k2, type_, "ULRTOAMeas"); - return c.get(); - } - uint32_t& k3() - { - assert_choice_type(types::k3, type_, "ULRTOAMeas"); - return c.get(); - } - uint32_t& k4() - { - assert_choice_type(types::k4, type_, "ULRTOAMeas"); - return c.get(); - } - uint16_t& k5() - { - assert_choice_type(types::k5, type_, "ULRTOAMeas"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "ULRTOAMeas"); - return c.get>(); - } - const uint32_t& k0() const - { - assert_choice_type(types::k0, type_, "ULRTOAMeas"); - return c.get(); - } - const uint32_t& k1() const - { - assert_choice_type(types::k1, type_, "ULRTOAMeas"); - return c.get(); - } - const uint32_t& k2() const - { - assert_choice_type(types::k2, type_, "ULRTOAMeas"); - return c.get(); - } - const uint32_t& k3() const - { - assert_choice_type(types::k3, type_, "ULRTOAMeas"); - return c.get(); - } - const uint32_t& k4() const - { - assert_choice_type(types::k4, type_, "ULRTOAMeas"); - return c.get(); - } - const uint16_t& k5() const - { - assert_choice_type(types::k5, type_, "ULRTOAMeas"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "ULRTOAMeas"); - return c.get>(); - } - uint32_t& set_k0(); - uint32_t& set_k1(); - uint32_t& set_k2(); - uint32_t& set_k3(); - uint32_t& set_k4(); - uint16_t& set_k5(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -struct ul_rtoameas_ext_ies_container { - bool extended_add_path_list_present = false; - bool trp_rx_teg_info_present = false; - extended_add_path_list_l extended_add_path_list; - trp_rx_teg_info_s trp_rx_teg_info; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AoA-AssistanceInfo ::= SEQUENCE -struct ao_a_assist_info_s { - bool ext = false; - bool lcs_to_gcs_translation_present = false; - bool ie_exts_present = false; - angle_meas_type_c angle_meas; - lcs_to_gcs_translation_s lcs_to_gcs_translation; - ao_a_assist_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AssistanceInformationMetaData ::= SEQUENCE -struct assist_info_meta_data_s { - struct encrypted_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using encrypted_e_ = enumerated; - struct gns_si_d_opts { - enum options { gps, sbas, qzss, galileo, glonass, bds, navic, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using gns_si_d_e_ = enumerated; - struct sba_si_d_opts { - enum options { waas, egnos, msas, gagan, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using sba_si_d_e_ = enumerated; - - // member variables - bool ext = false; - bool encrypted_present = false; - bool gns_si_d_present = false; - bool sba_si_d_present = false; - bool ie_exts_present = false; - encrypted_e_ encrypted; - gns_si_d_e_ gns_si_d; - sba_si_d_e_ sba_si_d; - assist_info_meta_data_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// GeographicalCoordinates ::= SEQUENCE -struct geographical_coordinates_s { - bool ext = false; - bool dl_prs_res_coordinates_present = false; - trp_position_definition_type_c trp_position_definition_type; - dl_prs_res_coordinates_s dl_prs_res_coordinates; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// GNB-RxTxTimeDiff ::= SEQUENCE -struct gnb_rx_tx_time_diff_s { - bool ext = false; - bool ie_exts_present = false; - gnb_rx_tx_time_diff_meas_c rx_tx_time_diff; - add_path_list_l add_path_list; - gnb_rx_tx_time_diff_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using meas_beam_info_ext_ies_container = protocol_ext_container_empty_l; - -// NumberOfFrequencyHoppingBands ::= ENUMERATED -struct nof_freq_hop_bands_opts { - enum options { twobands, fourbands, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using nof_freq_hop_bands_e = enumerated; - -// NumberOfTRPRxTEG ::= ENUMERATED -struct nof_trp_rx_teg_opts { - enum options { two, three, four, six, eight, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using nof_trp_rx_teg_e = enumerated; - -// NumberOfTRPRxTxTEG ::= ENUMERATED -struct nof_trp_rx_tx_teg_opts { - enum options { two, three, four, six, eight, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using nof_trp_rx_tx_teg_e = enumerated; - -// OTDOACell-Information-Item-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct otdoa_cell_info_item_ext_ie_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { tdd_cfg_eutra_item, cgi_nr, sfn_initisation_time_nr, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - tdd_cfg_eutra_item_s& tdd_cfg_eutra_item(); - cgi_nr_s& cgi_nr(); - fixed_bitstring<64, false, true>& sfn_initisation_time_nr(); - const tdd_cfg_eutra_item_s& tdd_cfg_eutra_item() const; - const cgi_nr_s& cgi_nr() const; - const fixed_bitstring<64, false, true>& sfn_initisation_time_nr() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PathlossReferenceSignal-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using pathloss_ref_sig_ext_ie_o = protocol_ies_empty_o; - -// PosSIB-Segments ::= SEQUENCE (SIZE (1..64)) OF PosSIB-Segments-item -using pos_sib_segments_l = dyn_array; - -// PosSIB-Type ::= ENUMERATED -struct pos_sib_type_opts { - enum options { - pos_sib_type1_neg1, - pos_sib_type1_neg2, - pos_sib_type1_neg3, - pos_sib_type1_neg4, - pos_sib_type1_neg5, - pos_sib_type1_neg6, - pos_sib_type1_neg7, - pos_sib_type1_neg8, - pos_sib_type2_neg1, - pos_sib_type2_neg2, - pos_sib_type2_neg3, - pos_sib_type2_neg4, - pos_sib_type2_neg5, - pos_sib_type2_neg6, - pos_sib_type2_neg7, - pos_sib_type2_neg8, - pos_sib_type2_neg9, - pos_sib_type2_neg10, - pos_sib_type2_neg11, - pos_sib_type2_neg12, - pos_sib_type2_neg13, - pos_sib_type2_neg14, - pos_sib_type2_neg15, - pos_sib_type2_neg16, - pos_sib_type2_neg17, - pos_sib_type2_neg18, - pos_sib_type2_neg19, - pos_sib_type2_neg20, - pos_sib_type2_neg21, - pos_sib_type2_neg22, - pos_sib_type2_neg23, - pos_sib_type2_neg24, - pos_sib_type2_neg25, - pos_sib_type3_neg1, - pos_sib_type4_neg1, - pos_sib_type5_neg1, - pos_sib_type6_neg1, - pos_sib_type6_neg2, - pos_sib_type6_neg3, - // ... - pos_sib_type1_neg9, - pos_sib_type1_neg10, - pos_sib_type6_neg4, - pos_sib_type6_neg5, - pos_sib_type6_neg6, - nulltype - } value; - - const char* to_string() const; -}; -using pos_sib_type_e = enumerated; - -using pos_sibs_ext_ies_container = protocol_ext_container_empty_l; - -// PosSRSResource-List ::= SEQUENCE (SIZE (1..64)) OF PosSRSResource-Item -using pos_srs_res_list_l = dyn_array; - -// PosSRSResourceSet-List ::= SEQUENCE (SIZE (1..16)) OF PosSRSResourceSet-Item -using pos_srs_res_set_list_l = dyn_array; - -// PRSConfiguration ::= SEQUENCE -struct prs_cfg_s { - bool ext = false; - bool ie_exts_present = false; - prs_res_set_list_l prs_res_set_list; - prs_cfg_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using prs_freq_hop_cfg_eutra_item_ies_container = protocol_ext_container_empty_l; - -// PRSTransmissionOffIndication-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using prs_tx_off_ind_ext_ies_o = protocol_ies_empty_o; - -// PRSTransmissionOffPerResource-Item ::= SEQUENCE -struct prs_tx_off_per_res_item_s { - using prs_tx_off_ind_per_res_list_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint8_t prs_res_set_id = 0; - prs_tx_off_ind_per_res_list_l_ prs_tx_off_ind_per_res_list; - prs_tx_off_per_res_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSTransmissionOffPerResourceSet-Item ::= SEQUENCE -struct prs_tx_off_per_res_set_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t prs_res_set_id = 0; - prs_tx_off_per_res_set_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// RequestedDLPRSResource-List ::= SEQUENCE (SIZE (1..64)) OF RequestedDLPRSResource-Item -using requested_dl_prs_res_list_l = dyn_array; - -using requested_dl_prs_res_set_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultCSI-RSRP ::= SEQUENCE (SIZE (1..9)) OF ResultCSI-RSRP-Item -using result_csi_rsrp_l = dyn_array; - -// ResultCSI-RSRQ ::= SEQUENCE (SIZE (1..9)) OF ResultCSI-RSRQ-Item -using result_csi_rsrq_l = dyn_array; - -// ResultEUTRA-Item ::= SEQUENCE -struct result_eutra_item_s { - bool ext = false; - bool value_rsrp_eutra_present = false; - bool value_rsrq_eutra_present = false; - bool cgi_eutra_present = false; - bool ie_exts_present = false; - uint16_t pci_eutra = 0; - uint32_t earfcn = 0; - uint8_t value_rsrp_eutra = 0; - uint8_t value_rsrq_eutra = 0; - cgi_eutra_s cgi_eutra; - result_eutra_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultNR-Item ::= SEQUENCE -struct result_nr_item_s { - bool ext = false; - bool value_ss_rsrp_cell_present = false; - bool value_ss_rsrq_cell_present = false; - bool cgi_nr_present = false; - bool ie_exts_present = false; - uint16_t nr_pci = 0; - uint32_t nr_arfcn = 0; - uint8_t value_ss_rsrp_cell = 0; - uint8_t value_ss_rsrq_cell = 0; - result_ss_rsrp_per_ssb_l ss_rsrp_per_ssb; - result_ss_rsrq_per_ssb_l ss_rsrq_per_ssb; - cgi_nr_s cgi_nr; - result_nr_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using result_rsrp_eutra_item_ext_ies_container = protocol_ext_container_empty_l; - -using result_rsrq_eutra_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultSS-RSRP ::= SEQUENCE (SIZE (1..9)) OF ResultSS-RSRP-Item -using result_ss_rsrp_l = dyn_array; - -// ResultSS-RSRQ ::= SEQUENCE (SIZE (1..9)) OF ResultSS-RSRQ-Item -using result_ss_rsrq_l = dyn_array; - -using scs_specific_carrier_ext_ies_container = protocol_ext_container_empty_l; - -// SpatialDirectionInformation ::= SEQUENCE -struct spatial_direction_info_s { - bool ext = false; - bool ie_exts_present = false; - nr_prs_beam_info_s nr_prs_beam_info; - spatial_direction_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SpatialRelationInfo ::= SEQUENCE -struct spatial_relation_info_s { - bool ext = false; - bool ie_exts_present = false; - spatial_relationfor_res_id_l spatial_relationfor_res_id; - spatial_relation_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SpatialRelationPerSRSResource ::= SEQUENCE -struct spatial_relation_per_srs_res_s { - bool ext = false; - bool ie_exts_present = false; - spatial_relation_per_srs_res_list_l spatial_relation_per_srs_res_list; - spatial_relation_per_srs_res_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using srs_cfg_ext_ies_container = protocol_ext_container_empty_l; - -// SRSResource-List ::= SEQUENCE (SIZE (1..64)) OF SRSResource -using srs_res_list_l = dyn_array; - -// SRSResourceSet-List ::= SEQUENCE (SIZE (1..16)) OF SRSResourceSet -using srs_res_set_list_l = dyn_array; - -// SSBInfo ::= SEQUENCE -struct ssb_info_s { - using list_of_ssb_info_l_ = dyn_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - list_of_ssb_info_l_ list_of_ssb_info; - ssb_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// StartTimeAndDuration ::= SEQUENCE -struct start_time_and_dur_s { - bool ext = false; - bool start_time_present = false; - bool dur_present = false; - bool ie_exts_present = false; - fixed_bitstring<64, false, true> start_time; - uint32_t dur = 0; - start_time_and_dur_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using time_stamp_ext_ies_container = protocol_ext_container_empty_l; - -// TimeStampSlotIndex ::= CHOICE -struct time_stamp_slot_idx_c { - struct types_opts { - enum options { scs_15, scs_30, scs_60, scs_120, choice_ext, nulltype } value; - typedef int8_t number_type; - - const char* to_string() const; - int8_t to_number() const; - }; - using types = enumerated; - - // choice methods - time_stamp_slot_idx_c() = default; - time_stamp_slot_idx_c(const time_stamp_slot_idx_c& other); - time_stamp_slot_idx_c& operator=(const time_stamp_slot_idx_c& other); - ~time_stamp_slot_idx_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& scs_15() - { - assert_choice_type(types::scs_15, type_, "TimeStampSlotIndex"); - return c.get(); - } - uint8_t& scs_30() - { - assert_choice_type(types::scs_30, type_, "TimeStampSlotIndex"); - return c.get(); - } - uint8_t& scs_60() - { - assert_choice_type(types::scs_60, type_, "TimeStampSlotIndex"); - return c.get(); - } - uint8_t& scs_120() - { - assert_choice_type(types::scs_120, type_, "TimeStampSlotIndex"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TimeStampSlotIndex"); - return c.get>(); - } - const uint8_t& scs_15() const - { - assert_choice_type(types::scs_15, type_, "TimeStampSlotIndex"); - return c.get(); - } - const uint8_t& scs_30() const - { - assert_choice_type(types::scs_30, type_, "TimeStampSlotIndex"); - return c.get(); - } - const uint8_t& scs_60() const - { - assert_choice_type(types::scs_60, type_, "TimeStampSlotIndex"); - return c.get(); - } - const uint8_t& scs_120() const - { - assert_choice_type(types::scs_120, type_, "TimeStampSlotIndex"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TimeStampSlotIndex"); - return c.get>(); - } - uint8_t& set_scs_15(); - uint8_t& set_scs_30(); - uint8_t& set_scs_60(); - uint8_t& set_scs_120(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// UL-RTOAMeasurement ::= SEQUENCE -struct ul_rtoameas_s { - bool ext = false; - bool ie_exts_present = false; - ul_rtoa_meas_c ul_rto_ameas; - add_path_list_l add_path_list; - ul_rtoameas_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using active_ul_bwp_ext_ies_container = protocol_ext_container_empty_l; - -// CPLength-EUTRA ::= ENUMERATED -struct cp_len_eutra_opts { - enum options { normal, extended, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using cp_len_eutra_e = enumerated; - -// DL-Bandwidth-EUTRA ::= ENUMERATED -struct dl_bw_eutra_opts { - enum options { bw6, bw15, bw25, bw50, bw75, bw100, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using dl_bw_eutra_e = enumerated; - -// MeasurementBeamInfo ::= SEQUENCE -struct meas_beam_info_s { - bool ext = false; - bool prs_res_id_present = false; - bool prs_res_set_id_present = false; - bool ssb_idx_present = false; - bool ie_exts_present = false; - uint8_t prs_res_id = 0; - uint8_t prs_res_set_id = 0; - uint8_t ssb_idx = 0; - meas_beam_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// MeasurementQuantitiesValue ::= ENUMERATED -struct meas_quantities_value_opts { - enum options { - cell_id, - angle_of_arrival, - timing_advance_type1, - timing_advance_type2, - rsrp, - rsrq, - // ... - ss_rsrp, - ss_rsrq, - csi_rsrp, - csi_rsrq, - angle_of_arrival_nr, - timing_advance_nr, - nulltype - } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using meas_quantities_value_e = enumerated; - -using meas_quantities_value_ext_ies_container = protocol_ext_container_empty_l; - -// MeasuredResultsValue-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct measured_results_value_ext_ie_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { - result_ss_rsrp, - result_ss_rsrq, - result_csi_rsrp, - result_csi_rsrq, - angle_of_arrival_nr, - nr_tadv, - nulltype - } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - result_ss_rsrp_l& result_ss_rsrp(); - result_ss_rsrq_l& result_ss_rsrq(); - result_csi_rsrp_l& result_csi_rsrp(); - result_csi_rsrq_l& result_csi_rsrq(); - ul_ao_a_s& angle_of_arrival_nr(); - uint16_t& nr_tadv(); - const result_ss_rsrp_l& result_ss_rsrp() const; - const result_ss_rsrq_l& result_ss_rsrq() const; - const result_csi_rsrp_l& result_csi_rsrp() const; - const result_csi_rsrq_l& result_csi_rsrq() const; - const ul_ao_a_s& angle_of_arrival_nr() const; - const uint16_t& nr_tadv() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// NG-RANCell-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using ng_ran_cell_ext_ie_o = protocol_ies_empty_o; - -// NumberOfAntennaPorts-EUTRA ::= ENUMERATED -struct nof_ant_ports_eutra_opts { - enum options { n1_or_n2, n4, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using nof_ant_ports_eutra_e = enumerated; - -// NumberOfDlFrames-EUTRA ::= ENUMERATED -struct nof_dl_frames_eutra_opts { - enum options { sf1, sf2, sf4, sf6, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using nof_dl_frames_eutra_e = enumerated; - -// OtherRATMeasurementQuantitiesValue ::= ENUMERATED -struct other_rat_meas_quantities_value_opts { - enum options { geran, utran, /*...*/ nr, eutra, nulltype } value; - - const char* to_string() const; -}; -using other_rat_meas_quantities_value_e = enumerated; - -using other_rat_meas_quantities_value_ext_ies_container = protocol_ext_container_empty_l; - -struct pos_sibs_item_s_ { - bool ext = false; - bool assist_info_meta_data_present = false; - bool broadcast_prio_present = false; - bool ie_exts_present = false; - pos_sib_type_e pos_sib_type; - pos_sib_segments_l pos_sib_segments; - assist_info_meta_data_s assist_info_meta_data; - uint8_t broadcast_prio = 1; - pos_sibs_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRS-Bandwidth-EUTRA ::= ENUMERATED -struct prs_bw_eutra_opts { - enum options { bw6, bw15, bw25, bw50, bw75, bw100, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using prs_bw_eutra_e = enumerated; - -// PRSFrequencyHoppingConfiguration-EUTRA ::= SEQUENCE -struct prs_freq_hop_cfg_eutra_s { - using band_positions_l_ = bounded_array; - - // member variables - bool ext = false; - bool ie_exts_present = false; - nof_freq_hop_bands_e no_of_freq_hop_bands; - band_positions_l_ band_positions; - prs_freq_hop_cfg_eutra_item_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSMutingConfiguration-EUTRA ::= CHOICE -struct prs_muting_cfg_eutra_c { - struct types_opts { - enum options { - two, - four, - eight, - sixteen, - thirty_two, - sixty_four, - one_hundred_and_twenty_eight, - two_hundred_and_fifty_six, - five_hundred_and_twelve, - one_thousand_and_twenty_four, - choice_ext, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - prs_muting_cfg_eutra_c() = default; - prs_muting_cfg_eutra_c(const prs_muting_cfg_eutra_c& other); - prs_muting_cfg_eutra_c& operator=(const prs_muting_cfg_eutra_c& other); - ~prs_muting_cfg_eutra_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - fixed_bitstring<2, false, true>& two() - { - assert_choice_type(types::two, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<4, false, true>& four() - { - assert_choice_type(types::four, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<8, false, true>& eight() - { - assert_choice_type(types::eight, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<16, false, true>& sixteen() - { - assert_choice_type(types::sixteen, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<32, false, true>& thirty_two() - { - assert_choice_type(types::thirty_two, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<64, false, true>& sixty_four() - { - assert_choice_type(types::sixty_four, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<128, false, true>& one_hundred_and_twenty_eight() - { - assert_choice_type(types::one_hundred_and_twenty_eight, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<256, false, true>& two_hundred_and_fifty_six() - { - assert_choice_type(types::two_hundred_and_fifty_six, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<512, false, true>& five_hundred_and_twelve() - { - assert_choice_type(types::five_hundred_and_twelve, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<1024, false, true>& one_thousand_and_twenty_four() - { - assert_choice_type(types::one_thousand_and_twenty_four, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<2, false, true>& two() const - { - assert_choice_type(types::two, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<4, false, true>& four() const - { - assert_choice_type(types::four, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<8, false, true>& eight() const - { - assert_choice_type(types::eight, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<16, false, true>& sixteen() const - { - assert_choice_type(types::sixteen, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<32, false, true>& thirty_two() const - { - assert_choice_type(types::thirty_two, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<64, false, true>& sixty_four() const - { - assert_choice_type(types::sixty_four, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<128, false, true>& one_hundred_and_twenty_eight() const - { - assert_choice_type(types::one_hundred_and_twenty_eight, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<256, false, true>& two_hundred_and_fifty_six() const - { - assert_choice_type(types::two_hundred_and_fifty_six, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<512, false, true>& five_hundred_and_twelve() const - { - assert_choice_type(types::five_hundred_and_twelve, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const fixed_bitstring<1024, false, true>& one_thousand_and_twenty_four() const - { - assert_choice_type(types::one_thousand_and_twenty_four, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "PRSMutingConfiguration-EUTRA"); - return c.get>(); - } - fixed_bitstring<2, false, true>& set_two(); - fixed_bitstring<4, false, true>& set_four(); - fixed_bitstring<8, false, true>& set_eight(); - fixed_bitstring<16, false, true>& set_sixteen(); - fixed_bitstring<32, false, true>& set_thirty_two(); - fixed_bitstring<64, false, true>& set_sixty_four(); - fixed_bitstring<128, false, true>& set_one_hundred_and_twenty_eight(); - fixed_bitstring<256, false, true>& set_two_hundred_and_fifty_six(); - fixed_bitstring<512, false, true>& set_five_hundred_and_twelve(); - fixed_bitstring<1024, false, true>& set_one_thousand_and_twenty_four(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, protocol_ie_single_container_s> c; - - void destroy_(); -}; - -// PRSOccasionGroup-EUTRA ::= ENUMERATED -struct prs_occasion_group_eutra_opts { - enum options { og2, og4, og8, og16, og32, og64, og128, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using prs_occasion_group_eutra_e = enumerated; - -// PRSTransmissionOffPerResource ::= SEQUENCE (SIZE (1..8)) OF PRSTransmissionOffPerResource-Item -using prs_tx_off_per_res_l = dyn_array; - -// PRSTransmissionOffPerResourceSet ::= SEQUENCE (SIZE (1..8)) OF PRSTransmissionOffPerResourceSet-Item -using prs_tx_off_per_res_set_l = dyn_array; - -// RequestedDLPRSResourceSet-Item ::= SEQUENCE -struct requested_dl_prs_res_set_item_s { - struct comb_size_opts { - enum options { n2, n4, n6, n12, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using comb_size_e_ = enumerated; - struct res_set_periodicity_opts { - enum options { - n4, - n5, - n8, - n10, - n16, - n20, - n32, - n40, - n64, - n80, - n160, - n320, - n640, - n1280, - n2560, - n5120, - n10240, - n20480, - n40960, - n81920, - // ... - nulltype - } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; - }; - using res_set_periodicity_e_ = enumerated; - struct res_repeat_factor_opts { - enum options { rf1, rf2, rf4, rf6, rf8, rf16, rf32, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using res_repeat_factor_e_ = enumerated; - struct res_numof_symbols_opts { - enum options { n2, n4, n6, n12, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using res_numof_symbols_e_ = enumerated; - - // member variables - bool ext = false; - bool pr_sbw_present = false; - bool comb_size_present = false; - bool res_set_periodicity_present = false; - bool res_repeat_factor_present = false; - bool res_numof_symbols_present = false; - bool res_set_start_time_and_dur_present = false; - bool ie_exts_present = false; - uint8_t pr_sbw = 1; - comb_size_e_ comb_size; - res_set_periodicity_e_ res_set_periodicity; - res_repeat_factor_e_ res_repeat_factor; - res_numof_symbols_e_ res_numof_symbols; - requested_dl_prs_res_list_l requested_dl_prs_res_list; - start_time_and_dur_s res_set_start_time_and_dur; - requested_dl_prs_res_set_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultEUTRA ::= SEQUENCE (SIZE (1..8)) OF ResultEUTRA-Item -using result_eutra_l = dyn_array; - -using result_geran_item_ext_ies_container = protocol_ext_container_empty_l; - -// ResultNR ::= SEQUENCE (SIZE (1..8)) OF ResultNR-Item -using result_nr_l = dyn_array; - -// ResultRSRP-EUTRA-Item ::= SEQUENCE -struct result_rsrp_eutra_item_s { - bool ext = false; - bool cgi_eutra_present = false; - bool ie_exts_present = false; - uint16_t pci_eutra = 0; - uint32_t earfcn = 0; - cgi_eutra_s cgi_eutra; - uint8_t value_rsrp_eutra = 0; - result_rsrp_eutra_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultRSRQ-EUTRA-Item ::= SEQUENCE -struct result_rsrq_eutra_item_s { - bool ext = false; - bool cgi_utra_present = false; - bool ie_exts_present = false; - uint16_t pci_eutra = 0; - uint32_t earfcn = 0; - cgi_eutra_s cgi_utra; - uint8_t value_rsrq_eutra = 0; - result_rsrq_eutra_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using result_utran_item_ext_ies_container = protocol_ext_container_empty_l; - -// SCS-SpecificCarrier ::= SEQUENCE -struct scs_specific_carrier_s { - struct subcarrier_spacing_opts { - enum options { khz15, khz30, khz60, khz120, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using subcarrier_spacing_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint16_t offset_to_carrier = 0; - subcarrier_spacing_e_ subcarrier_spacing; - uint16_t carrier_bw = 1; - scs_specific_carrier_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SemipersistentSRS-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct semipersistent_srs_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { srs_spatial_relation, srs_spatial_relation_per_srs_res, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - spatial_relation_info_s& srs_spatial_relation(); - spatial_relation_per_srs_res_s& srs_spatial_relation_per_srs_res(); - const spatial_relation_info_s& srs_spatial_relation() const; - const spatial_relation_per_srs_res_s& srs_spatial_relation_per_srs_res() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// SRSConfig ::= SEQUENCE -struct srs_cfg_s { - bool ext = false; - bool ie_exts_present = false; - srs_res_list_l srs_res_list; - pos_srs_res_list_l pos_srs_res_list; - srs_res_set_list_l srs_res_set_list; - pos_srs_res_set_list_l pos_srs_res_set_list; - srs_cfg_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TimeStamp ::= SEQUENCE -struct time_stamp_s { - bool ext = false; - bool meas_time_present = false; - bool ie_ext_present = false; - uint16_t sys_frame_num = 0; - time_stamp_slot_idx_c slot_idx; - fixed_bitstring<64, false, true> meas_time; - time_stamp_ext_ies_container ie_ext; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TP-Type-EUTRA ::= ENUMERATED -struct tp_type_eutra_opts { - enum options { prs_only_tp, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using tp_type_eutra_e = enumerated; - -// TRPInformationTypeResponseItem ::= CHOICE -struct trp_info_type_resp_item_c { - struct types_opts { - enum options { - pci_nr, - cgi_nr, - arfcn, - prs_cfg, - ss_binfo, - sfn_initisation_time, - spatial_direction_info, - geographical_coordinates, - choice_ext, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trp_info_type_resp_item_c() = default; - trp_info_type_resp_item_c(const trp_info_type_resp_item_c& other); - trp_info_type_resp_item_c& operator=(const trp_info_type_resp_item_c& other); - ~trp_info_type_resp_item_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint16_t& pci_nr() - { - assert_choice_type(types::pci_nr, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - cgi_nr_s& cgi_nr() - { - assert_choice_type(types::cgi_nr, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - uint32_t& arfcn() - { - assert_choice_type(types::arfcn, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - prs_cfg_s& prs_cfg() - { - assert_choice_type(types::prs_cfg, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - ssb_info_s& ss_binfo() - { - assert_choice_type(types::ss_binfo, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - fixed_bitstring<64, false, true>& sfn_initisation_time() - { - assert_choice_type(types::sfn_initisation_time, type_, "TRPInformationTypeResponseItem"); - return c.get>(); - } - spatial_direction_info_s& spatial_direction_info() - { - assert_choice_type(types::spatial_direction_info, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - geographical_coordinates_s& geographical_coordinates() - { - assert_choice_type(types::geographical_coordinates, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TRPInformationTypeResponseItem"); - return c.get>(); - } - const uint16_t& pci_nr() const - { - assert_choice_type(types::pci_nr, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const cgi_nr_s& cgi_nr() const - { - assert_choice_type(types::cgi_nr, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const uint32_t& arfcn() const - { - assert_choice_type(types::arfcn, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const prs_cfg_s& prs_cfg() const - { - assert_choice_type(types::prs_cfg, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const ssb_info_s& ss_binfo() const - { - assert_choice_type(types::ss_binfo, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const fixed_bitstring<64, false, true>& sfn_initisation_time() const - { - assert_choice_type(types::sfn_initisation_time, type_, "TRPInformationTypeResponseItem"); - return c.get>(); - } - const spatial_direction_info_s& spatial_direction_info() const - { - assert_choice_type(types::spatial_direction_info, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const geographical_coordinates_s& geographical_coordinates() const - { - assert_choice_type(types::geographical_coordinates, type_, "TRPInformationTypeResponseItem"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TRPInformationTypeResponseItem"); - return c.get>(); - } - uint16_t& set_pci_nr(); - cgi_nr_s& set_cgi_nr(); - uint32_t& set_arfcn(); - prs_cfg_s& set_prs_cfg(); - ssb_info_s& set_ss_binfo(); - fixed_bitstring<64, false, true>& set_sfn_initisation_time(); - spatial_direction_info_s& set_spatial_direction_info(); - geographical_coordinates_s& set_geographical_coordinates(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - geographical_coordinates_s, - protocol_ie_single_container_s, - prs_cfg_s, - spatial_direction_info_s, - ssb_info_s> - c; - - void destroy_(); -}; - -// TRP-MeasurementRequestItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct trp_meas_request_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { cell_id, ao_a_search_win, nof_trp_rx_teg, nof_trp_rx_tx_teg, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cgi_nr_s& cell_id(); - ao_a_assist_info_s& ao_a_search_win(); - nof_trp_rx_teg_e& nof_trp_rx_teg(); - nof_trp_rx_tx_teg_e& nof_trp_rx_tx_teg(); - const cgi_nr_s& cell_id() const; - const ao_a_assist_info_s& ao_a_search_win() const; - const nof_trp_rx_teg_e& nof_trp_rx_teg() const; - const nof_trp_rx_tx_teg_e& nof_trp_rx_tx_teg() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -struct trp_meas_result_item_ext_ies_container { - bool srs_restype_present = false; - bool arp_id_present = false; - bool lo_s_n_lo_si_nformation_present = false; - srs_restype_s srs_restype; - uint8_t arp_id; - lo_s_n_lo_si_nformation_c lo_s_n_lo_si_nformation; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-MeasurementUpdateItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct trp_meas_upd_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { nof_trp_rx_teg, nof_trp_rx_tx_teg, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ext_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - nof_trp_rx_teg_e& nof_trp_rx_teg(); - nof_trp_rx_tx_teg_e& nof_trp_rx_tx_teg(); - const nof_trp_rx_teg_e& nof_trp_rx_teg() const; - const nof_trp_rx_tx_teg_e& nof_trp_rx_tx_teg() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TrpMeasuredResultsValue ::= CHOICE -struct trp_measured_results_value_c { - struct types_opts { - enum options { ul_angle_of_arrival, ul_srs_rsrp, ul_rtoa, gnb_rx_tx_time_diff, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - trp_measured_results_value_c() = default; - trp_measured_results_value_c(const trp_measured_results_value_c& other); - trp_measured_results_value_c& operator=(const trp_measured_results_value_c& other); - ~trp_measured_results_value_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - ul_ao_a_s& ul_angle_of_arrival() - { - assert_choice_type(types::ul_angle_of_arrival, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - uint8_t& ul_srs_rsrp() - { - assert_choice_type(types::ul_srs_rsrp, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - ul_rtoameas_s& ul_rtoa() - { - assert_choice_type(types::ul_rtoa, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - gnb_rx_tx_time_diff_s& gnb_rx_tx_time_diff() - { - assert_choice_type(types::gnb_rx_tx_time_diff, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "TrpMeasuredResultsValue"); - return c.get>(); - } - const ul_ao_a_s& ul_angle_of_arrival() const - { - assert_choice_type(types::ul_angle_of_arrival, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - const uint8_t& ul_srs_rsrp() const - { - assert_choice_type(types::ul_srs_rsrp, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - const ul_rtoameas_s& ul_rtoa() const - { - assert_choice_type(types::ul_rtoa, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - const gnb_rx_tx_time_diff_s& gnb_rx_tx_time_diff() const - { - assert_choice_type(types::gnb_rx_tx_time_diff, type_, "TrpMeasuredResultsValue"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "TrpMeasuredResultsValue"); - return c.get>(); - } - ul_ao_a_s& set_ul_angle_of_arrival(); - uint8_t& set_ul_srs_rsrp(); - ul_rtoameas_s& set_ul_rtoa(); - gnb_rx_tx_time_diff_s& set_gnb_rx_tx_time_diff(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - ul_ao_a_s, - ul_rtoameas_s> - c; - - void destroy_(); -}; - -// WLANMeasurementQuantitiesValue ::= ENUMERATED -struct wlan_meas_quantities_value_opts { - enum options { wlan, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using wlan_meas_quantities_value_e = enumerated; - -using wlan_meas_quantities_value_ext_ies_container = protocol_ext_container_empty_l; - -// ActiveULBWP ::= SEQUENCE -struct active_ul_bwp_s { - struct subcarrier_spacing_opts { - enum options { khz15, khz30, khz60, khz120, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using subcarrier_spacing_e_ = enumerated; - struct cp_opts { - enum options { normal, extended, nulltype } value; - - const char* to_string() const; - }; - using cp_e_ = enumerated; - struct shift7dot5k_hz_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using shift7dot5k_hz_e_ = enumerated; - - // member variables - bool ext = false; - bool shift7dot5k_hz_present = false; - bool ie_exts_present = false; - uint16_t location_and_bw = 0; - subcarrier_spacing_e_ subcarrier_spacing; - cp_e_ cp; - uint16_t tx_direct_current_location = 0; - shift7dot5k_hz_e_ shift7dot5k_hz; - srs_cfg_s srs_cfg; - active_ul_bwp_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AperiodicSRSResourceTriggerList ::= SEQUENCE (SIZE (1..3)) OF INTEGER (1..3) -using aperiodic_srs_res_trigger_list_l = bounded_array; - -// BroadcastPeriodicity ::= ENUMERATED -struct broadcast_periodicity_opts { - enum options { ms80, ms160, ms320, ms640, ms1280, ms2560, ms5120, /*...*/ nulltype } value; - typedef uint16_t number_type; - - const char* to_string() const; - uint16_t to_number() const; -}; -using broadcast_periodicity_e = enumerated; - -// BandwidthSRS-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using bw_srs_ext_ies_o = protocol_ies_empty_o; - -using carrier_freq_ext_ies_container = protocol_ext_container_empty_l; - -using crit_diagnostics_ie_list_ext_ies_container = protocol_ext_container_empty_l; - -// MeasurementQuantities-Item ::= SEQUENCE -struct meas_quantities_item_s { - bool ext = false; - bool ie_exts_present = false; - meas_quantities_value_e meas_quantities_value; - meas_quantities_value_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// OTDOACell-Information-Item ::= CHOICE -struct otdoa_cell_info_item_c { - struct types_opts { - enum options { - pci_eutra, - cgi_eutra, - tac, - earfcn, - prs_bw_eutra, - prs_cfg_idx_eutra, - cp_len_eutra, - nof_dl_frames_eutra, - nof_ant_ports_eutra, - sfn_initisation_time_eutra, - ng_ran_access_point_position, - prs_muting_cfg_eutra, - prsid_eutra, - tpid_eutra, - tp_type_eutra, - nof_dl_frames_extended_eutra, - crs_cp_len_eutra, - dl_bw_eutra, - prs_occasion_group_eutra, - prs_freq_hop_cfg_eutra, - choice_ext, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - otdoa_cell_info_item_c() = default; - otdoa_cell_info_item_c(const otdoa_cell_info_item_c& other); - otdoa_cell_info_item_c& operator=(const otdoa_cell_info_item_c& other); - ~otdoa_cell_info_item_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint16_t& pci_eutra() - { - assert_choice_type(types::pci_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - cgi_eutra_s& cgi_eutra() - { - assert_choice_type(types::cgi_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - fixed_octstring<3, true>& tac() - { - assert_choice_type(types::tac, type_, "OTDOACell-Information-Item"); - return c.get>(); - } - uint32_t& earfcn() - { - assert_choice_type(types::earfcn, type_, "OTDOACell-Information-Item"); - return c.get(); - } - prs_bw_eutra_e& prs_bw_eutra() - { - assert_choice_type(types::prs_bw_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - uint16_t& prs_cfg_idx_eutra() - { - assert_choice_type(types::prs_cfg_idx_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - cp_len_eutra_e& cp_len_eutra() - { - assert_choice_type(types::cp_len_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - nof_dl_frames_eutra_e& nof_dl_frames_eutra() - { - assert_choice_type(types::nof_dl_frames_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - nof_ant_ports_eutra_e& nof_ant_ports_eutra() - { - assert_choice_type(types::nof_ant_ports_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - fixed_bitstring<64, false, true>& sfn_initisation_time_eutra() - { - assert_choice_type(types::sfn_initisation_time_eutra, type_, "OTDOACell-Information-Item"); - return c.get>(); - } - ng_ran_access_point_position_s& ng_ran_access_point_position() - { - assert_choice_type(types::ng_ran_access_point_position, type_, "OTDOACell-Information-Item"); - return c.get(); - } - prs_muting_cfg_eutra_c& prs_muting_cfg_eutra() - { - assert_choice_type(types::prs_muting_cfg_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - uint16_t& prsid_eutra() - { - assert_choice_type(types::prsid_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - uint16_t& tpid_eutra() - { - assert_choice_type(types::tpid_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - tp_type_eutra_e& tp_type_eutra() - { - assert_choice_type(types::tp_type_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - uint8_t& nof_dl_frames_extended_eutra() - { - assert_choice_type(types::nof_dl_frames_extended_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - cp_len_eutra_e& crs_cp_len_eutra() - { - assert_choice_type(types::crs_cp_len_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - dl_bw_eutra_e& dl_bw_eutra() - { - assert_choice_type(types::dl_bw_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - prs_occasion_group_eutra_e& prs_occasion_group_eutra() - { - assert_choice_type(types::prs_occasion_group_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - prs_freq_hop_cfg_eutra_s& prs_freq_hop_cfg_eutra() - { - assert_choice_type(types::prs_freq_hop_cfg_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "OTDOACell-Information-Item"); - return c.get>(); - } - const uint16_t& pci_eutra() const - { - assert_choice_type(types::pci_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const cgi_eutra_s& cgi_eutra() const - { - assert_choice_type(types::cgi_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const fixed_octstring<3, true>& tac() const - { - assert_choice_type(types::tac, type_, "OTDOACell-Information-Item"); - return c.get>(); - } - const uint32_t& earfcn() const - { - assert_choice_type(types::earfcn, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const prs_bw_eutra_e& prs_bw_eutra() const - { - assert_choice_type(types::prs_bw_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const uint16_t& prs_cfg_idx_eutra() const - { - assert_choice_type(types::prs_cfg_idx_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const cp_len_eutra_e& cp_len_eutra() const - { - assert_choice_type(types::cp_len_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const nof_dl_frames_eutra_e& nof_dl_frames_eutra() const - { - assert_choice_type(types::nof_dl_frames_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const nof_ant_ports_eutra_e& nof_ant_ports_eutra() const - { - assert_choice_type(types::nof_ant_ports_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const fixed_bitstring<64, false, true>& sfn_initisation_time_eutra() const - { - assert_choice_type(types::sfn_initisation_time_eutra, type_, "OTDOACell-Information-Item"); - return c.get>(); - } - const ng_ran_access_point_position_s& ng_ran_access_point_position() const - { - assert_choice_type(types::ng_ran_access_point_position, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const prs_muting_cfg_eutra_c& prs_muting_cfg_eutra() const - { - assert_choice_type(types::prs_muting_cfg_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const uint16_t& prsid_eutra() const - { - assert_choice_type(types::prsid_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const uint16_t& tpid_eutra() const - { - assert_choice_type(types::tpid_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const tp_type_eutra_e& tp_type_eutra() const - { - assert_choice_type(types::tp_type_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const uint8_t& nof_dl_frames_extended_eutra() const - { - assert_choice_type(types::nof_dl_frames_extended_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const cp_len_eutra_e& crs_cp_len_eutra() const - { - assert_choice_type(types::crs_cp_len_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const dl_bw_eutra_e& dl_bw_eutra() const - { - assert_choice_type(types::dl_bw_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const prs_occasion_group_eutra_e& prs_occasion_group_eutra() const - { - assert_choice_type(types::prs_occasion_group_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const prs_freq_hop_cfg_eutra_s& prs_freq_hop_cfg_eutra() const - { - assert_choice_type(types::prs_freq_hop_cfg_eutra, type_, "OTDOACell-Information-Item"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "OTDOACell-Information-Item"); - return c.get>(); - } - uint16_t& set_pci_eutra(); - cgi_eutra_s& set_cgi_eutra(); - fixed_octstring<3, true>& set_tac(); - uint32_t& set_earfcn(); - prs_bw_eutra_e& set_prs_bw_eutra(); - uint16_t& set_prs_cfg_idx_eutra(); - cp_len_eutra_e& set_cp_len_eutra(); - nof_dl_frames_eutra_e& set_nof_dl_frames_eutra(); - nof_ant_ports_eutra_e& set_nof_ant_ports_eutra(); - fixed_bitstring<64, false, true>& set_sfn_initisation_time_eutra(); - ng_ran_access_point_position_s& set_ng_ran_access_point_position(); - prs_muting_cfg_eutra_c& set_prs_muting_cfg_eutra(); - uint16_t& set_prsid_eutra(); - uint16_t& set_tpid_eutra(); - tp_type_eutra_e& set_tp_type_eutra(); - uint8_t& set_nof_dl_frames_extended_eutra(); - cp_len_eutra_e& set_crs_cp_len_eutra(); - dl_bw_eutra_e& set_dl_bw_eutra(); - prs_occasion_group_eutra_e& set_prs_occasion_group_eutra(); - prs_freq_hop_cfg_eutra_s& set_prs_freq_hop_cfg_eutra(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - fixed_octstring<3, true>, - ng_ran_access_point_position_s, - protocol_ie_single_container_s, - prs_freq_hop_cfg_eutra_s, - prs_muting_cfg_eutra_c> - c; - - void destroy_(); -}; - -// OTDOA-Information-Item ::= ENUMERATED -struct otdoa_info_item_opts { - enum options { - pci, - cgi, - tac, - earfcn, - prs_bw, - prs_cfg_idx, - cp_len, - no_dl_frames, - no_ant_ports, - sfn_init_time, - ng_ran_access_point_position, - prsmutingcfg, - prsid, - tpid, - tp_type, - crs_cp_len, - dl_bw, - multipleprs_cfgsper_cell, - prs_occasion_group, - prs_freq_hop_cfg, - // ... - tdd_cfg, - nulltype - } value; - - const char* to_string() const; -}; -using otdoa_info_item_e = enumerated; - -using otdoa_info_type_item_ext_ies_container = protocol_ext_container_empty_l; - -// OtherRATMeasurementQuantities-Item ::= SEQUENCE -struct other_rat_meas_quantities_item_s { - bool ext = false; - bool ie_exts_present = false; - other_rat_meas_quantities_value_e other_rat_meas_quantities_value; - other_rat_meas_quantities_value_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// OtherRATMeasuredResultsValue-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct other_rat_measured_results_value_ext_ie_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { result_nr, result_eutra, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - result_nr_l& result_nr(); - result_eutra_l& result_eutra(); - const result_nr_l& result_nr() const; - const result_eutra_l& result_eutra() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -using pathloss_ref_info_ext_ies_container = protocol_ext_container_empty_l; - -// PathlossReferenceSignal ::= CHOICE -struct pathloss_ref_sig_c { - struct types_opts { - enum options { ssb_ref, dl_prs_ref, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - pathloss_ref_sig_c() = default; - pathloss_ref_sig_c(const pathloss_ref_sig_c& other); - pathloss_ref_sig_c& operator=(const pathloss_ref_sig_c& other); - ~pathloss_ref_sig_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - ssb_s& ssb_ref() - { - assert_choice_type(types::ssb_ref, type_, "PathlossReferenceSignal"); - return c.get(); - } - dl_prs_s& dl_prs_ref() - { - assert_choice_type(types::dl_prs_ref, type_, "PathlossReferenceSignal"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "PathlossReferenceSignal"); - return c.get>(); - } - const ssb_s& ssb_ref() const - { - assert_choice_type(types::ssb_ref, type_, "PathlossReferenceSignal"); - return c.get(); - } - const dl_prs_s& dl_prs_ref() const - { - assert_choice_type(types::dl_prs_ref, type_, "PathlossReferenceSignal"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "PathlossReferenceSignal"); - return c.get>(); - } - ssb_s& set_ssb_ref(); - dl_prs_s& set_dl_prs_ref(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, ssb_s> c; - - void destroy_(); -}; - -// PeriodicityItem ::= ENUMERATED -struct periodicity_item_opts { - enum options { - ms0dot125, - ms0dot25, - ms0dot5, - ms0dot625, - ms1, - ms1dot25, - ms2, - ms2dot5, - ms4dot, - ms5, - ms8, - ms10, - ms16, - ms20, - ms32, - ms40, - ms64, - ms80m, - ms160, - ms320, - ms640m, - ms1280, - ms2560, - ms5120, - ms10240, - // ... - nulltype - } value; - typedef float number_type; - - const char* to_string() const; - float to_number() const; - const char* to_number_string() const; -}; -using periodicity_item_e = enumerated; - -// PosSIBs ::= SEQUENCE (SIZE (1..32)) OF PosSIBs-item -using pos_sibs_l = dyn_array; - -// PRSTransmissionOffIndication ::= CHOICE -struct prs_tx_off_ind_c { - struct types_opts { - enum options { prs_tx_off_per_trp, prs_tx_off_per_res_set, prs_tx_off_per_res, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - prs_tx_off_ind_c() = default; - prs_tx_off_ind_c(const prs_tx_off_ind_c& other); - prs_tx_off_ind_c& operator=(const prs_tx_off_ind_c& other); - ~prs_tx_off_ind_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - prs_tx_off_per_res_set_l& prs_tx_off_per_res_set() - { - assert_choice_type(types::prs_tx_off_per_res_set, type_, "PRSTransmissionOffIndication"); - return c.get(); - } - prs_tx_off_per_res_l& prs_tx_off_per_res() - { - assert_choice_type(types::prs_tx_off_per_res, type_, "PRSTransmissionOffIndication"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "PRSTransmissionOffIndication"); - return c.get>(); - } - const prs_tx_off_per_res_set_l& prs_tx_off_per_res_set() const - { - assert_choice_type(types::prs_tx_off_per_res_set, type_, "PRSTransmissionOffIndication"); - return c.get(); - } - const prs_tx_off_per_res_l& prs_tx_off_per_res() const - { - assert_choice_type(types::prs_tx_off_per_res, type_, "PRSTransmissionOffIndication"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "PRSTransmissionOffIndication"); - return c.get>(); - } - void set_prs_tx_off_per_trp(); - prs_tx_off_per_res_set_l& set_prs_tx_off_per_res_set(); - prs_tx_off_per_res_l& set_prs_tx_off_per_res(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - prs_tx_off_per_res_l, - prs_tx_off_per_res_set_l> - c; - - void destroy_(); -}; - -using prs_tx_off_info_ext_ies_container = protocol_ext_container_empty_l; - -// RequestedDLPRSResourceSet-List ::= SEQUENCE (SIZE (1..8)) OF RequestedDLPRSResourceSet-Item -using requested_dl_prs_res_set_list_l = dyn_array; - -using requested_dl_prs_tx_characteristics_ext_ies_container = protocol_ext_container_empty_l; - -// ResultGERAN-Item ::= SEQUENCE -struct result_geran_item_s { - bool ext = false; - bool ie_exts_present = false; - uint16_t bcch = 0; - uint8_t pci_geran = 0; - uint8_t rssi = 0; - result_geran_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResultRSRP-EUTRA ::= SEQUENCE (SIZE (1..9)) OF ResultRSRP-EUTRA-Item -using result_rsrp_eutra_l = dyn_array; - -// ResultRSRQ-EUTRA ::= SEQUENCE (SIZE (1..9)) OF ResultRSRQ-EUTRA-Item -using result_rsrq_eutra_l = dyn_array; - -// ResultUTRAN-Item ::= SEQUENCE -struct result_utran_item_s { - struct pci_utran_c_ { - struct types_opts { - enum options { phys_cell_i_du_tra_fdd, phys_cell_i_du_tra_tdd, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - pci_utran_c_() = default; - pci_utran_c_(const pci_utran_c_& other); - pci_utran_c_& operator=(const pci_utran_c_& other); - ~pci_utran_c_() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint16_t& phys_cell_i_du_tra_fdd() - { - assert_choice_type(types::phys_cell_i_du_tra_fdd, type_, "physCellIDUTRAN"); - return c.get(); - } - uint8_t& phys_cell_i_du_tra_tdd() - { - assert_choice_type(types::phys_cell_i_du_tra_tdd, type_, "physCellIDUTRAN"); - return c.get(); - } - const uint16_t& phys_cell_i_du_tra_fdd() const - { - assert_choice_type(types::phys_cell_i_du_tra_fdd, type_, "physCellIDUTRAN"); - return c.get(); - } - const uint8_t& phys_cell_i_du_tra_tdd() const - { - assert_choice_type(types::phys_cell_i_du_tra_tdd, type_, "physCellIDUTRAN"); - return c.get(); - } - uint16_t& set_phys_cell_i_du_tra_fdd(); - uint8_t& set_phys_cell_i_du_tra_tdd(); - - private: - types type_; - pod_choice_buffer_t c; - - void destroy_(); - }; - - // member variables - bool ext = false; - bool utra_rs_cp_present = false; - bool utra_ec_n0_present = false; - bool ie_exts_present = false; - uint16_t uarfcn = 0; - pci_utran_c_ pci_utran; - int8_t utra_rs_cp = -5; - uint8_t utra_ec_n0 = 0; - result_utran_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using search_win_info_ext_ies_container = protocol_ext_container_empty_l; - -using srs_carrier_list_item_ext_ies_container = protocol_ext_container_empty_l; - -// SRSResourceSet-Item-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct srs_res_set_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { srs_spatial_relation_per_srs_res, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::srs_spatial_relation_per_srs_res; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - spatial_relation_per_srs_res_s& srs_spatial_relation_per_srs_res() { return c; } - const spatial_relation_per_srs_res_s& srs_spatial_relation_per_srs_res() const { return c; } - - private: - spatial_relation_per_srs_res_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -using srs_res_trigger_ext_ies_container = protocol_ext_container_empty_l; - -using sys_info_ext_ies_container = protocol_ext_container_empty_l; - -using trp_info_ext_ies_container = protocol_ext_container_empty_l; - -// TRPInformationTypeItem ::= ENUMERATED -struct trp_info_type_item_opts { - enum options { - nr_pci, - ng_ran_cgi, - arfcn, - prs_cfg, - ssb_info, - sfn_init_time, - spatial_direct_info, - geo_coord, - // ... - trp_type, - ondemand_pr_si_nfo, - trp_tx_teg, - beam_ant_info, - nulltype - } value; - - const char* to_string() const; -}; -using trp_info_type_item_e = enumerated; - -// TRPInformationTypeResponseList ::= SEQUENCE (SIZE (1..64)) OF TRPInformationTypeResponseItem -using trp_info_type_resp_list_l = dyn_array; - -// TRP-MeasurementResponseItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct trp_meas_resp_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { cell_id, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::cell_id; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cgi_nr_s& cell_id() { return c; } - const cgi_nr_s& cell_id() const { return c; } - - private: - cgi_nr_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TrpMeasurementResultItem ::= SEQUENCE -struct trp_meas_result_item_s { - bool ext = false; - bool meas_quality_present = false; - bool meas_beam_info_present = false; - bool ie_exts_present = false; - trp_measured_results_value_c measured_results_value; - time_stamp_s time_stamp; - trp_meas_quality_c meas_quality; - meas_beam_info_s meas_beam_info; - trp_meas_result_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TypeOfError ::= ENUMERATED -struct type_of_error_opts { - enum options { not_understood, missing, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using type_of_error_e = enumerated; - -// UETxTEGAssociationItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct ue_tx_teg_assoc_item_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { ue_tx_timing_error_margin, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::ue_tx_timing_error_margin; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - timing_error_margin_e& ue_tx_timing_error_margin() { return c; } - const timing_error_margin_e& ue_tx_timing_error_margin() const { return c; } - - private: - timing_error_margin_e c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// UplinkChannelBW-PerSCS-List ::= SEQUENCE (SIZE (1..5)) OF SCS-SpecificCarrier -using ul_ch_bw_per_scs_list_l = dyn_array; - -// WLANMeasurementQuantities-Item ::= SEQUENCE -struct wlan_meas_quantities_item_s { - bool ext = false; - bool ie_exts_present = false; - wlan_meas_quantities_value_e wlan_meas_quantities_value; - wlan_meas_quantities_value_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using aperiodic_srs_ext_ies_container = protocol_ext_container_empty_l; - -using assist_info_fail_list_ext_ies_container = protocol_ext_container_empty_l; - -// CarrierFreq ::= SEQUENCE -struct carrier_freq_s { - bool ext = false; - bool ie_exts_present = false; - uint32_t point_a = 0; - uint16_t offset_to_carrier = 0; - carrier_freq_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// Cause-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using cause_ext_ie_o = protocol_ies_empty_o; - -struct crit_diagnostics_ie_list_item_s_ { - bool ext = false; - bool ie_exts_present = false; - crit_e ie_crit; - uint32_t ie_id = 0; - type_of_error_e type_of_error; - crit_diagnostics_ie_list_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// E-CID-MeasurementResult-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct e_c_id_meas_result_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { geographical_coordinates, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::geographical_coordinates; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - geographical_coordinates_s& geographical_coordinates() { return c; } - const geographical_coordinates_s& geographical_coordinates() const { return c; } - - private: - geographical_coordinates_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementQuantities-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_quantities_item_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { meas_quantities_item, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::meas_quantities_item; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - meas_quantities_item_s& meas_quantities_item() { return c; } - const meas_quantities_item_s& meas_quantities_item() const { return c; } - - private: - meas_quantities_item_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasuredResultsValue ::= CHOICE -struct measured_results_value_c { - struct types_opts { - enum options { - value_angle_of_arrival_eutra, - value_timing_advance_type1_eutra, - value_timing_advance_type2_eutra, - result_rsrp_eutra, - result_rsrq_eutra, - choice_ext, - nulltype - } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - measured_results_value_c() = default; - measured_results_value_c(const measured_results_value_c& other); - measured_results_value_c& operator=(const measured_results_value_c& other); - ~measured_results_value_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint16_t& value_angle_of_arrival_eutra() - { - assert_choice_type(types::value_angle_of_arrival_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - uint16_t& value_timing_advance_type1_eutra() - { - assert_choice_type(types::value_timing_advance_type1_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - uint16_t& value_timing_advance_type2_eutra() - { - assert_choice_type(types::value_timing_advance_type2_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - result_rsrp_eutra_l& result_rsrp_eutra() - { - assert_choice_type(types::result_rsrp_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - result_rsrq_eutra_l& result_rsrq_eutra() - { - assert_choice_type(types::result_rsrq_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "MeasuredResultsValue"); - return c.get>(); - } - const uint16_t& value_angle_of_arrival_eutra() const - { - assert_choice_type(types::value_angle_of_arrival_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - const uint16_t& value_timing_advance_type1_eutra() const - { - assert_choice_type(types::value_timing_advance_type1_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - const uint16_t& value_timing_advance_type2_eutra() const - { - assert_choice_type(types::value_timing_advance_type2_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - const result_rsrp_eutra_l& result_rsrp_eutra() const - { - assert_choice_type(types::result_rsrp_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - const result_rsrq_eutra_l& result_rsrq_eutra() const - { - assert_choice_type(types::result_rsrq_eutra, type_, "MeasuredResultsValue"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "MeasuredResultsValue"); - return c.get>(); - } - uint16_t& set_value_angle_of_arrival_eutra(); - uint16_t& set_value_timing_advance_type1_eutra(); - uint16_t& set_value_timing_advance_type2_eutra(); - result_rsrp_eutra_l& set_result_rsrp_eutra(); - result_rsrq_eutra_l& set_result_rsrq_eutra(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - result_rsrp_eutra_l, - result_rsrq_eutra_l> - c; - - void destroy_(); -}; - -// NG-RANCell ::= CHOICE -struct ng_ran_cell_c { - struct types_opts { - enum options { eutra_cell_id, nr_cell_id, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - ng_ran_cell_c() = default; - ng_ran_cell_c(const ng_ran_cell_c& other); - ng_ran_cell_c& operator=(const ng_ran_cell_c& other); - ~ng_ran_cell_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - fixed_bitstring<28, false, true>& eutra_cell_id() - { - assert_choice_type(types::eutra_cell_id, type_, "NG-RANCell"); - return c.get>(); - } - fixed_bitstring<36, false, true>& nr_cell_id() - { - assert_choice_type(types::nr_cell_id, type_, "NG-RANCell"); - return c.get>(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "NG-RANCell"); - return c.get>(); - } - const fixed_bitstring<28, false, true>& eutra_cell_id() const - { - assert_choice_type(types::eutra_cell_id, type_, "NG-RANCell"); - return c.get>(); - } - const fixed_bitstring<36, false, true>& nr_cell_id() const - { - assert_choice_type(types::nr_cell_id, type_, "NG-RANCell"); - return c.get>(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "NG-RANCell"); - return c.get>(); - } - fixed_bitstring<28, false, true>& set_eutra_cell_id(); - fixed_bitstring<36, false, true>& set_nr_cell_id(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, protocol_ie_single_container_s> c; - - void destroy_(); -}; - -using ng_ran_cgi_ext_ies_container = protocol_ext_container_empty_l; - -// OTDOACell-Information ::= SEQUENCE (SIZE (1..63)) OF OTDOACell-Information-Item -using otdoa_cell_info_l = dyn_array; - -using otdoa_cells_ext_ies_container = protocol_ext_container_empty_l; - -// OTDOA-Information-Type-Item ::= SEQUENCE -struct otdoa_info_type_item_s { - bool ext = false; - bool ie_exts_present = false; - otdoa_info_item_e otdoa_info_item; - otdoa_info_type_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// OtherRATMeasurementQuantities-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct other_rat_meas_quantities_item_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { other_rat_meas_quantities_item, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::other_rat_meas_quantities_item; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - other_rat_meas_quantities_item_s& other_rat_meas_quantities_item() { return c; } - const other_rat_meas_quantities_item_s& other_rat_meas_quantities_item() const { return c; } - - private: - other_rat_meas_quantities_item_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// Outcome ::= ENUMERATED -struct outcome_opts { - enum options { failed, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using outcome_e = enumerated; - -// PathlossReferenceInformation ::= SEQUENCE -struct pathloss_ref_info_s { - bool ext = false; - bool ie_exts_present = false; - pathloss_ref_sig_c pathloss_ref_sig; - pathloss_ref_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PeriodicityList ::= SEQUENCE (SIZE (1..16)) OF PeriodicityItem -using periodicity_list_l = bounded_array; - -// PosSRSResourceID-List ::= SEQUENCE (SIZE (1..64)) OF INTEGER (0..63) -using pos_srs_res_id_list_l = dyn_array; - -using prs_meass_info_list_item_ext_ies_container = protocol_ext_container_empty_l; - -// PRSTransmissionOffInformation ::= SEQUENCE -struct prs_tx_off_info_s { - bool ext = false; - bool ie_exts_present = false; - prs_tx_off_ind_c prs_tx_off_ind; - prs_tx_off_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using prs_tx_trp_item_ext_ies_container = protocol_ext_container_empty_l; - -using prstrp_item_ext_ies_container = protocol_ext_container_empty_l; - -// RequestedDLPRSTransmissionCharacteristics ::= SEQUENCE -struct requested_dl_prs_tx_characteristics_s { - bool ext = false; - bool numof_freq_layers_present = false; - bool start_time_and_dur_present = false; - bool ie_exts_present = false; - requested_dl_prs_res_set_list_l requested_dl_prs_res_set_list; - uint8_t numof_freq_layers = 1; - start_time_and_dur_s start_time_and_dur; - requested_dl_prs_tx_characteristics_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// RequestedSRSTransmissionCharacteristics-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -struct requested_srs_tx_characteristics_ext_ies_o { - // Extension ::= OPEN TYPE - struct ext_c { - struct types_opts { - enum options { srs_freq, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::srs_freq; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& srs_freq() { return c; } - const uint32_t& srs_freq() const { return c; } - - private: - uint32_t c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static ext_c get_ext(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// ResultGERAN ::= SEQUENCE (SIZE (1..8)) OF ResultGERAN-Item -using result_geran_l = dyn_array; - -// ResultUTRAN ::= SEQUENCE (SIZE (1..8)) OF ResultUTRAN-Item -using result_utran_l = dyn_array; - -// Search-window-information ::= SEQUENCE -struct search_win_info_s { - bool ext = false; - bool ie_exts_present = false; - int16_t expected_propagation_delay = -3841; - uint8_t delay_uncertainty = 1; - search_win_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct semipersistent_srs_ext_ies_container { - bool srs_spatial_relation_present = false; - bool srs_spatial_relation_per_srs_res_present = false; - spatial_relation_info_s srs_spatial_relation; - spatial_relation_per_srs_res_s srs_spatial_relation_per_srs_res; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSCarrier-List-Item ::= SEQUENCE -struct srs_carrier_list_item_s { - bool ext = false; - bool pci_nr_present = false; - bool ie_exts_present = false; - uint32_t point_a = 0; - ul_ch_bw_per_scs_list_l ul_ch_bw_per_scs_list; - active_ul_bwp_s active_ul_bwp; - uint16_t pci_nr = 0; - srs_carrier_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSResourceTrigger ::= SEQUENCE -struct srs_res_trigger_s { - bool ext = false; - bool ie_exts_present = false; - aperiodic_srs_res_trigger_list_l aperiodic_srs_res_trigger_list; - srs_res_trigger_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSType-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using srs_type_ext_ies_o = protocol_ies_empty_o; - -struct sys_info_item_s_ { - bool ext = false; - bool ie_exts_present = false; - broadcast_periodicity_e broadcast_periodicity; - pos_sibs_l pos_sibs; - sys_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPInformation ::= SEQUENCE -struct trp_info_s { - bool ext = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - trp_info_type_resp_list_l trp_info_type_resp_list; - trp_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using trp_info_trp_resp_ext_ies_container = protocol_ext_container_empty_l; - -// TRPInformationTypeItemTRPReq ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct trp_info_type_item_trp_req_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { trp_info_type_item, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::trp_info_type_item; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_info_type_item_e& trp_info_type_item() { return c; } - const trp_info_type_item_e& trp_info_type_item() const { return c; } - - private: - trp_info_type_item_e c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -using trp_item_ext_ies_container = protocol_ext_container_empty_l; - -// TRPMeasurementQuantities-Item ::= ENUMERATED -struct trp_meas_quantities_item_opts { - enum options { - gnb_rx_tx_time_diff, - ul_srs_rsrp, - ul_ao_a, - ul_rtoa, - /*...*/ multiple_ul_ao_a, - ul_srs_rsrp_p, - nulltype - } value; - - const char* to_string() const; -}; -using trp_meas_quantities_item_e = enumerated; - -using trp_meas_quantities_list_item_ext_ies_container = protocol_ext_container_empty_l; - -struct trp_meas_request_item_ext_ies_container { - bool cell_id_present = false; - bool ao_a_search_win_present = false; - bool nof_trp_rx_teg_present = false; - bool nof_trp_rx_tx_teg_present = false; - cgi_nr_s cell_id; - ao_a_assist_info_s ao_a_search_win; - nof_trp_rx_teg_e nof_trp_rx_teg; - nof_trp_rx_tx_teg_e nof_trp_rx_tx_teg; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TrpMeasurementResult ::= SEQUENCE (SIZE (1..16384)) OF TrpMeasurementResultItem -using trp_meas_result_l = dyn_array; - -struct trp_meas_upd_item_ext_ies_container { - bool nof_trp_rx_teg_present = false; - bool nof_trp_rx_tx_teg_present = false; - nof_trp_rx_teg_e nof_trp_rx_teg; - nof_trp_rx_tx_teg_e nof_trp_rx_tx_teg; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// WLANBand ::= ENUMERATED -struct wlan_band_opts { - enum options { band2dot4, band5, /*...*/ nulltype } value; - typedef float number_type; - - const char* to_string() const; - float to_number() const; - const char* to_number_string() const; -}; -using wlan_band_e = enumerated; - -// WLANChannelList ::= SEQUENCE (SIZE (1..16)) OF INTEGER (0..255) -using wlan_ch_list_l = bounded_array; - -// WLANCountryCode ::= ENUMERATED -struct wlan_country_code_opts { - enum options { united_states, europe, japan, global, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using wlan_country_code_e = enumerated; - -// WLANMeasurementQuantities-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct wlan_meas_quantities_item_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { wlan_meas_quantities_item, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::wlan_meas_quantities_item; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - wlan_meas_quantities_item_s& wlan_meas_quantities_item() { return c; } - const wlan_meas_quantities_item_s& wlan_meas_quantities_item() const { return c; } - - private: - wlan_meas_quantities_item_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -using wlan_meas_result_item_ext_ies_container = protocol_ext_container_empty_l; - -// AbortTransmission-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -using abort_tx_ext_ies_o = protocol_ies_empty_o; - -// AperiodicSRS ::= SEQUENCE -struct aperiodic_srs_s { - struct aperiodic_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using aperiodic_e_ = enumerated; - - // member variables - bool ext = false; - bool srs_res_trigger_present = false; - bool ie_exts_present = false; - aperiodic_e_ aperiodic; - srs_res_trigger_s srs_res_trigger; - aperiodic_srs_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using assist_info_ext_ies_container = protocol_ext_container_empty_l; - -struct assist_info_fail_list_item_s_ { - bool ext = false; - bool ie_exts_present = false; - pos_sib_type_e pos_sib_type; - outcome_e outcome; - assist_info_fail_list_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// BandwidthSRS ::= CHOICE -struct bw_srs_c { - struct fr1_opts { - enum options { mhz5, mhz10, mhz20, mhz40, mhz50, mhz80, mhz100, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using fr1_e_ = enumerated; - struct fr2_opts { - enum options { mhz50, mhz100, mhz200, mhz400, /*...*/ nulltype } value; - typedef uint16_t number_type; - - const char* to_string() const; - uint16_t to_number() const; - }; - using fr2_e_ = enumerated; - struct types_opts { - enum options { fr1, fr2, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - bw_srs_c() = default; - bw_srs_c(const bw_srs_c& other); - bw_srs_c& operator=(const bw_srs_c& other); - ~bw_srs_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - fr1_e_& fr1() - { - assert_choice_type(types::fr1, type_, "BandwidthSRS"); - return c.get(); - } - fr2_e_& fr2() - { - assert_choice_type(types::fr2, type_, "BandwidthSRS"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "BandwidthSRS"); - return c.get>(); - } - const fr1_e_& fr1() const - { - assert_choice_type(types::fr1, type_, "BandwidthSRS"); - return c.get(); - } - const fr2_e_& fr2() const - { - assert_choice_type(types::fr2, type_, "BandwidthSRS"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "BandwidthSRS"); - return c.get>(); - } - fr1_e_& set_fr1(); - fr2_e_& set_fr2(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// CauseMisc ::= ENUMERATED -struct cause_misc_opts { - enum options { unspecified, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using cause_misc_e = enumerated; - -// CauseProtocol ::= ENUMERATED -struct cause_protocol_opts { - enum options { - transfer_syntax_error, - abstract_syntax_error_reject, - abstract_syntax_error_ignore_and_notify, - msg_not_compatible_with_receiver_state, - semantic_error, - unspecified, - abstract_syntax_error_falsely_constructed_msg, - // ... - nulltype - } value; - - const char* to_string() const; -}; -using cause_protocol_e = enumerated; - -// CauseRadioNetwork ::= ENUMERATED -struct cause_radio_network_opts { - enum options { - unspecified, - requested_item_not_supported, - requested_item_temporarily_not_available, - // ... - serving_ng_ran_node_changed, - requested_item_not_supported_on_time, - nulltype - } value; - - const char* to_string() const; -}; -using cause_radio_network_e = enumerated; - -using crit_diagnostics_ext_ies_container = protocol_ext_container_empty_l; - -// CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..256)) OF CriticalityDiagnostics-IE-List-item -using crit_diagnostics_ie_list_l = dyn_array; - -// MeasuredResults ::= SEQUENCE (SIZE (1..64)) OF MeasuredResultsValue -using measured_results_l = dyn_array; - -// NG-RAN-CGI ::= SEQUENCE -struct ng_ran_cgi_s { - bool ext = false; - bool ie_exts_present = false; - fixed_octstring<3, true> plmn_id; - ng_ran_cell_c ng_ra_ncell; - ng_ran_cgi_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct nr_ppa_private_ies_empty_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::nulltype; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - }; -}; - -struct otdoa_cells_item_s_ { - bool ext = false; - bool ie_exts_present = false; - otdoa_cell_info_l otdoa_cell_info; - otdoa_cells_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// OTDOA-Information-Type-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct otdoa_info_type_item_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { otdoa_info_type_item, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::otdoa_info_type_item; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - otdoa_info_type_item_s& otdoa_info_type_item() { return c; } - const otdoa_info_type_item_s& otdoa_info_type_item() const { return c; } - - private: - otdoa_info_type_item_s c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// OtherRATMeasuredResultsValue ::= CHOICE -struct other_rat_measured_results_value_c { - struct types_opts { - enum options { result_geran, result_utran, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - other_rat_measured_results_value_c() = default; - other_rat_measured_results_value_c(const other_rat_measured_results_value_c& other); - other_rat_measured_results_value_c& operator=(const other_rat_measured_results_value_c& other); - ~other_rat_measured_results_value_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - result_geran_l& result_geran() - { - assert_choice_type(types::result_geran, type_, "OtherRATMeasuredResultsValue"); - return c.get(); - } - result_utran_l& result_utran() - { - assert_choice_type(types::result_utran, type_, "OtherRATMeasuredResultsValue"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "OtherRATMeasuredResultsValue"); - return c.get>(); - } - const result_geran_l& result_geran() const - { - assert_choice_type(types::result_geran, type_, "OtherRATMeasuredResultsValue"); - return c.get(); - } - const result_utran_l& result_utran() const - { - assert_choice_type(types::result_utran, type_, "OtherRATMeasuredResultsValue"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "OtherRATMeasuredResultsValue"); - return c.get>(); - } - result_geran_l& set_result_geran(); - result_utran_l& set_result_utran(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, - result_geran_l, - result_utran_l> - c; - - void destroy_(); -}; - -// PrivateIE-ID ::= CHOICE -struct private_ie_id_c { - struct types_opts { - enum options { local, global, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - private_ie_id_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& local() - { - assert_choice_type(types::local, type_, "PrivateIE-ID"); - return c; - } - const uint32_t& local() const - { - assert_choice_type(types::local, type_, "PrivateIE-ID"); - return c; - } - uint32_t& set_local(); - void set_global(); - -private: - types type_; - uint32_t c; -}; - -// PRS-Measurements-Info-List-Item ::= SEQUENCE -struct prs_meass_info_list_item_s { - struct meas_prs_periodicity_opts { - enum options { ms20, ms40, ms80, ms160, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using meas_prs_periodicity_e_ = enumerated; - struct meas_prs_len_opts { - enum options { ms1dot5, ms3, ms3dot5, ms4, ms5dot5, ms6, ms10, ms20, nulltype } value; - typedef float number_type; - - const char* to_string() const; - float to_number() const; - const char* to_number_string() const; - }; - using meas_prs_len_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint32_t point_a = 0; - meas_prs_periodicity_e_ meas_prs_periodicity; - uint8_t meas_prs_offset = 0; - meas_prs_len_e_ meas_prs_len; - prs_meass_info_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSTransmissionTRPItem ::= SEQUENCE -struct prs_tx_trp_item_s { - bool ext = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - prs_cfg_s prs_cfg; - prs_tx_trp_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSTRPItem ::= SEQUENCE -struct prstrp_item_s { - bool ext = false; - bool requested_dl_prs_tx_characteristics_present = false; - bool prs_tx_off_info_present = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - requested_dl_prs_tx_characteristics_s requested_dl_prs_tx_characteristics; - prs_tx_off_info_s prs_tx_off_info; - prstrp_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using resp_time_ext_ies_container = protocol_ext_container_empty_l; - -// SemipersistentSRS ::= SEQUENCE -struct semipersistent_srs_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t srs_res_set_id = 0; - semipersistent_srs_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSCarrier-List ::= SEQUENCE (SIZE (1..32)) OF SRSCarrier-List-Item -using srs_carrier_list_l = dyn_array; - -// SRSResourceSet-Item ::= SEQUENCE -struct srs_res_set_item_s { - bool ext = false; - bool nof_srs_res_per_set_present = false; - bool spatial_relation_info_present = false; - bool pathloss_ref_info_present = false; - uint8_t nof_srs_res_per_set = 1; - periodicity_list_l periodicity_list; - spatial_relation_info_s spatial_relation_info; - pathloss_ref_info_s pathloss_ref_info; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using srscfg_ext_ies_container = protocol_ext_container_empty_l; - -// SystemInformation ::= SEQUENCE (SIZE (1..32)) OF SystemInformation-item -using sys_info_l = dyn_array; - -// TriggeringMessage ::= ENUMERATED -struct trigger_msg_opts { - enum options { init_msg, successful_outcome, unsuccessful_outcome, nulltype } value; - - const char* to_string() const; -}; -using trigger_msg_e = enumerated; - -struct trp_info_list_trp_resp_item_s_ { - bool ext = false; - bool ie_exts_present = false; - trp_info_s trp_info; - trp_info_trp_resp_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPItem ::= SEQUENCE -struct trp_item_s { - bool ext = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - trp_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPMeasurementQuantitiesList-Item ::= SEQUENCE -struct trp_meas_quantities_list_item_s { - bool ext = false; - bool timing_report_granularity_factor_present = false; - bool ie_exts_present = false; - trp_meas_quantities_item_e trp_meas_quantities_item; - uint8_t timing_report_granularity_factor = 0; - trp_meas_quantities_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-MeasurementRequestItem ::= SEQUENCE -struct trp_meas_request_item_s { - bool ext = false; - bool search_win_info_present = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - search_win_info_s search_win_info; - trp_meas_request_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-MeasurementResponseItem ::= SEQUENCE -struct trp_meas_resp_item_s { - bool ext = false; - uint32_t trp_id = 1; - trp_meas_result_l meas_result; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRP-MeasurementUpdateItem ::= SEQUENCE -struct trp_meas_upd_item_s { - bool ext = false; - bool ao_a_win_info_present = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - ao_a_assist_info_s ao_a_win_info; - trp_meas_upd_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using trp_prs_info_list_item_ext_ies_container = protocol_ext_container_empty_l; - -using ue_report_info_ext_ies_container = protocol_ext_container_empty_l; - -// UETxTEGAssociationItem ::= SEQUENCE -struct ue_tx_teg_assoc_item_s { - bool ext = false; - bool carrier_freq_present = false; - uint8_t ue_tx_teg_id = 0; - pos_srs_res_id_list_l pos_srs_res_id_list; - time_stamp_s time_stamp; - carrier_freq_s carrier_freq; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// WLANMeasurementResult-Item ::= SEQUENCE -struct wlan_meas_result_item_s { - bool ext = false; - bool bs_si_d_present = false; - bool hes_si_d_present = false; - bool operating_class_present = false; - bool country_code_present = false; - bool wlan_band_present = false; - bool ie_exts_present = false; - uint8_t wlan_rssi = 0; - bounded_octstring<1, 32, true> ssi_d; - fixed_octstring<6, true> bs_si_d; - fixed_octstring<6, true> hes_si_d; - uint16_t operating_class = 0; - wlan_country_code_e country_code; - wlan_ch_list_l wlan_ch_list; - wlan_band_e wlan_band; - wlan_meas_result_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AssistanceInformationFailureList ::= SEQUENCE (SIZE (1..32)) OF AssistanceInformationFailureList-item -using assist_info_fail_list_l = dyn_array; - -// Assistance-Information ::= SEQUENCE -struct assist_info_s { - bool ext = false; - bool ie_exts_present = false; - sys_info_l sys_info; - assist_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// Broadcast ::= ENUMERATED -struct broadcast_opts { - enum options { start, stop, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using broadcast_e = enumerated; - -// Cause ::= CHOICE -struct cause_c { - struct types_opts { - enum options { radio_network, protocol, misc, choice_ext, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - cause_c() = default; - cause_c(const cause_c& other); - cause_c& operator=(const cause_c& other); - ~cause_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_radio_network_e& radio_network() - { - assert_choice_type(types::radio_network, type_, "Cause"); - return c.get(); - } - cause_protocol_e& protocol() - { - assert_choice_type(types::protocol, type_, "Cause"); - return c.get(); - } - cause_misc_e& misc() - { - assert_choice_type(types::misc, type_, "Cause"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "Cause"); - return c.get>(); - } - const cause_radio_network_e& radio_network() const - { - assert_choice_type(types::radio_network, type_, "Cause"); - return c.get(); - } - const cause_protocol_e& protocol() const - { - assert_choice_type(types::protocol, type_, "Cause"); - return c.get(); - } - const cause_misc_e& misc() const - { - assert_choice_type(types::misc, type_, "Cause"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "Cause"); - return c.get>(); - } - cause_radio_network_e& set_radio_network(); - cause_protocol_e& set_protocol(); - cause_misc_e& set_misc(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// CriticalityDiagnostics ::= SEQUENCE -struct crit_diagnostics_s { - bool ext = false; - bool proc_code_present = false; - bool trigger_msg_present = false; - bool proc_crit_present = false; - bool nrppatransaction_id_present = false; - bool ie_exts_present = false; - uint16_t proc_code = 0; - trigger_msg_e trigger_msg; - crit_e proc_crit; - uint16_t nrppatransaction_id = 0; - crit_diagnostics_ie_list_l ies_crit_diagnostics; - crit_diagnostics_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// E-CID-MeasurementResult ::= SEQUENCE -struct e_c_id_meas_result_s { - bool ext = false; - bool ng_ran_access_point_position_present = false; - ng_ran_cgi_s serving_cell_id; - fixed_octstring<3, true> serving_cell_tac; - ng_ran_access_point_position_s ng_ran_access_point_position; - measured_results_l measured_results; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// MeasurementAmount ::= ENUMERATED -struct meas_amount_opts { - enum options { ma0, ma1, ma2, ma4, ma8, ma16, ma32, ma64, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using meas_amount_e = enumerated; - -// MeasurementBeamInfoRequest ::= ENUMERATED -struct meas_beam_info_request_opts { - enum options { true_value, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using meas_beam_info_request_e = enumerated; - -// MeasurementPeriodicity ::= ENUMERATED -struct meas_periodicity_opts { - enum options { - ms120, - ms240, - ms480, - ms640, - ms1024, - ms2048, - ms5120, - ms10240, - min1, - min6, - min12, - min30, - min60, - // ... - ms20480, - ms40960, - extended, - nulltype - } value; - typedef uint16_t number_type; - - const char* to_string() const; - uint16_t to_number() const; -}; -using meas_periodicity_e = enumerated; - -// MeasurementPeriodicityExtended ::= ENUMERATED -struct meas_periodicity_extended_opts { - enum options { - ms160, - ms320, - ms1280, - ms2560, - ms61440, - ms81920, - ms368640, - ms737280, - ms1843200, - /*...*/ nulltype - } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; -}; -using meas_periodicity_extended_e = enumerated; - -// MeasurementPeriodicityNR-AoA ::= ENUMERATED -struct meas_periodicity_nr_ao_a_opts { - enum options { - ms160, - ms320, - ms640, - ms1280, - ms2560, - ms5120, - ms10240, - ms20480, - ms40960, - ms61440, - ms81920, - ms368640, - ms737280, - ms1843200, - // ... - nulltype - } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; -}; -using meas_periodicity_nr_ao_a_e = enumerated; - -// MeasurementQuantities ::= SEQUENCE (SIZE (1..64)) OF ProtocolIE-Single-Container{NRPPA-PROTOCOL-IES : IEsSetParam} -using meas_quantities_l = dyn_array>; - -// MeasurementTimeOccasion ::= ENUMERATED -struct meas_time_occasion_opts { - enum options { o1, o4, /*...*/ nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; -}; -using meas_time_occasion_e = enumerated; - -// OTDOACells ::= SEQUENCE (SIZE (1..3840)) OF OTDOACells-item -using otdoa_cells_l = dyn_array; - -// OtherRATMeasurementQuantities ::= SEQUENCE (SIZE (0..64)) OF ProtocolIE-Single-Container{NRPPA-PROTOCOL-IES : -// IEsSetParam} -using other_rat_meas_quantities_l = dyn_array>; - -// OtherRATMeasurementResult ::= SEQUENCE (SIZE (1..64)) OF OtherRATMeasuredResultsValue -using other_rat_meas_result_l = dyn_array; - -// PositioningBroadcastCells ::= SEQUENCE (SIZE (1..16384)) OF NG-RAN-CGI -using positioning_broadcast_cells_l = dyn_array; - -// PrivateIE-Field{NRPPA-PRIVATE-IES : IEsSetParam} ::= SEQUENCE{{NRPPA-PRIVATE-IES}} -template -struct private_ie_field_s { - private_ie_id_c id; - crit_e crit; - typename ies_set_paramT_::value_c value; - - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PrivateMessage-IEs ::= OBJECT SET OF NRPPA-PRIVATE-IES -using private_msg_ies_o = nr_ppa_private_ies_empty_o; - -// PRSConfigRequestType ::= ENUMERATED -struct prs_cfg_request_type_opts { - enum options { cfgure, off, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using prs_cfg_request_type_e = enumerated; - -// PRS-Measurements-Info-List ::= SEQUENCE (SIZE (1..4)) OF PRS-Measurements-Info-List-Item -using prs_meass_info_list_l = dyn_array; - -// PRSTransmissionTRPList ::= SEQUENCE (SIZE (1..65535)) OF PRSTransmissionTRPItem -using prs_tx_trp_list_l = dyn_array; - -// PRSTRPList ::= SEQUENCE (SIZE (1..65535)) OF PRSTRPItem -using prstrp_list_l = dyn_array; - -// ReportCharacteristics ::= ENUMERATED -struct report_characteristics_opts { - enum options { on_demand, periodic, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using report_characteristics_e = enumerated; - -// RequestType ::= ENUMERATED -struct request_type_opts { - enum options { activ, deactiv, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using request_type_e = enumerated; - -// RequestedSRSTransmissionCharacteristics ::= SEQUENCE -struct requested_srs_tx_characteristics_s { - struct res_type_opts { - enum options { periodic, semi_persistent, aperiodic, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using res_type_e_ = enumerated; - using list_of_srs_res_set_l_ = dyn_array; - - // member variables - bool ext = false; - bool nof_txs_present = false; - bool ssb_info_present = false; - uint16_t nof_txs = 0; - res_type_e_ res_type; - bw_srs_c bw; - list_of_srs_res_set_l_ list_of_srs_res_set; - ssb_info_s ssb_info; - protocol_ext_container_l ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// ResponseTime ::= SEQUENCE -struct resp_time_s { - struct time_unit_opts { - enum options { second, ten_seconds, ten_milliseconds, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using time_unit_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - uint8_t time = 1; - time_unit_e_ time_unit; - resp_time_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// SRSTransmissionStatus ::= ENUMERATED -struct srs_tx_status_opts { - enum options { stopped, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using srs_tx_status_e = enumerated; - -// SRSType ::= CHOICE -struct srs_type_c { - struct types_opts { - enum options { semipersistent_srs, aperiodic_srs, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - srs_type_c() = default; - srs_type_c(const srs_type_c& other); - srs_type_c& operator=(const srs_type_c& other); - ~srs_type_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - semipersistent_srs_s& semipersistent_srs() - { - assert_choice_type(types::semipersistent_srs, type_, "SRSType"); - return c.get(); - } - aperiodic_srs_s& aperiodic_srs() - { - assert_choice_type(types::aperiodic_srs, type_, "SRSType"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "SRSType"); - return c.get>(); - } - const semipersistent_srs_s& semipersistent_srs() const - { - assert_choice_type(types::semipersistent_srs, type_, "SRSType"); - return c.get(); - } - const aperiodic_srs_s& aperiodic_srs() const - { - assert_choice_type(types::aperiodic_srs, type_, "SRSType"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "SRSType"); - return c.get>(); - } - semipersistent_srs_s& set_semipersistent_srs(); - aperiodic_srs_s& set_aperiodic_srs(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t, semipersistent_srs_s> c; - - void destroy_(); -}; - -// SRSConfiguration ::= SEQUENCE -struct srscfg_s { - bool ext = false; - bool ie_exts_present = false; - srs_carrier_list_l srs_carrier_list; - srscfg_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// TRPInformationListTRPResp ::= SEQUENCE (SIZE (1..65535)) OF TRPInformationListTRPResp-item -using trp_info_list_trp_resp_l = dyn_array; - -// TRPInformationTypeListTRPReq ::= SEQUENCE (SIZE (1..64)) OF ProtocolIE-Single-Container{NRPPA-PROTOCOL-IES : -// IEsSetParam} -using trp_info_type_list_trp_req_l = dyn_array>; - -// TRPList ::= SEQUENCE (SIZE (1..65535)) OF TRPItem -using trp_list_l = dyn_array; - -// TRPMeasurementQuantities ::= SEQUENCE (SIZE (1..16384)) OF TRPMeasurementQuantitiesList-Item -using trp_meas_quantities_l = dyn_array; - -// TRP-MeasurementRequestList ::= SEQUENCE (SIZE (1..64)) OF TRP-MeasurementRequestItem -using trp_meas_request_list_l = dyn_array; - -// TRP-MeasurementResponseList ::= SEQUENCE (SIZE (1..64)) OF TRP-MeasurementResponseItem -using trp_meas_resp_list_l = dyn_array; - -// TRP-MeasurementUpdateList ::= SEQUENCE (SIZE (1..64)) OF TRP-MeasurementUpdateItem -using trp_meas_upd_list_l = dyn_array; - -// TRP-PRS-Information-List-Item ::= SEQUENCE -struct trp_prs_info_list_item_s { - bool ext = false; - bool cgi_nr_present = false; - bool ie_exts_present = false; - uint32_t trp_id = 1; - uint16_t nr_pci = 0; - cgi_nr_s cgi_nr; - prs_cfg_s prs_cfg; - trp_prs_info_list_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// UEReportingInformation ::= SEQUENCE -struct ue_report_info_s { - struct report_amount_opts { - enum options { ma0, ma1, ma2, ma4, ma8, ma16, ma32, ma64, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using report_amount_e_ = enumerated; - struct report_interv_opts { - enum options { none, one, two, four, eight, ten, sixteen, twenty, thirty_two, sixty_four, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using report_interv_e_ = enumerated; - - // member variables - bool ext = false; - bool ie_exts_present = false; - report_amount_e_ report_amount; - report_interv_e_ report_interv; - ue_report_info_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// UE-TEG-Info-Request ::= ENUMERATED -struct ue_teg_info_request_opts { - enum options { on_demand, periodic, stop, /*...*/ nulltype } value; - - const char* to_string() const; -}; -using ue_teg_info_request_e = enumerated; - -// UE-TEG-ReportingPeriodicity ::= ENUMERATED -struct ue_teg_report_periodicity_opts { - enum options { ms160, ms320, ms1280, ms2560, ms61440, ms81920, ms368640, ms737280, /*...*/ nulltype } value; - typedef uint32_t number_type; - - const char* to_string() const; - uint32_t to_number() const; -}; -using ue_teg_report_periodicity_e = enumerated; - -// UETxTEGAssociationList ::= SEQUENCE (SIZE (1..256)) OF UETxTEGAssociationItem -using ue_tx_teg_assoc_list_l = dyn_array; - -// WLANMeasurementQuantities ::= SEQUENCE (SIZE (0..64)) OF ProtocolIE-Single-Container{NRPPA-PROTOCOL-IES : -// IEsSetParam} -using wlan_meas_quantities_l = dyn_array>; - -// WLANMeasurementResult ::= SEQUENCE (SIZE (1..64)) OF WLANMeasurementResult-Item -using wlan_meas_result_l = dyn_array; - -// AbortTransmission ::= CHOICE -struct abort_tx_c { - struct types_opts { - enum options { deactiv_srs_res_set_id, release_all, choice_ext, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - abort_tx_c() = default; - abort_tx_c(const abort_tx_c& other); - abort_tx_c& operator=(const abort_tx_c& other); - ~abort_tx_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& deactiv_srs_res_set_id() - { - assert_choice_type(types::deactiv_srs_res_set_id, type_, "AbortTransmission"); - return c.get(); - } - protocol_ie_single_container_s& choice_ext() - { - assert_choice_type(types::choice_ext, type_, "AbortTransmission"); - return c.get>(); - } - const uint8_t& deactiv_srs_res_set_id() const - { - assert_choice_type(types::deactiv_srs_res_set_id, type_, "AbortTransmission"); - return c.get(); - } - const protocol_ie_single_container_s& choice_ext() const - { - assert_choice_type(types::choice_ext, type_, "AbortTransmission"); - return c.get>(); - } - uint8_t& set_deactiv_srs_res_set_id(); - void set_release_all(); - protocol_ie_single_container_s& set_choice_ext(); - -private: - types type_; - choice_buffer_t> c; - - void destroy_(); -}; - -// AssistanceInformationControl-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct assist_info_ctrl_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { assist_info, broadcast, positioning_broadcast_cells, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - assist_info_s& assist_info(); - broadcast_e& broadcast(); - positioning_broadcast_cells_l& positioning_broadcast_cells(); - const assist_info_s& assist_info() const; - const broadcast_e& broadcast() const; - const positioning_broadcast_cells_l& positioning_broadcast_cells() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// AssistanceInformationFeedback-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct assist_info_feedback_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { assist_info_fail_list, positioning_broadcast_cells, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - assist_info_fail_list_l& assist_info_fail_list(); - positioning_broadcast_cells_l& positioning_broadcast_cells(); - crit_diagnostics_s& crit_diagnostics(); - const assist_info_fail_list_l& assist_info_fail_list() const; - const positioning_broadcast_cells_l& positioning_broadcast_cells() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// E-CIDMeasurementFailureIndication-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct e_c_id_meas_fail_ind_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_ue_meas_id, ran_ue_meas_id, cause, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lmf_ue_meas_id(); - uint8_t& ran_ue_meas_id(); - cause_c& cause(); - const uint8_t& lmf_ue_meas_id() const; - const uint8_t& ran_ue_meas_id() const; - const cause_c& cause() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// E-CIDMeasurementInitiationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct e_c_id_meas_initiation_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_ue_meas_id, cause, crit_diagnostics, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lmf_ue_meas_id(); - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const uint8_t& lmf_ue_meas_id() const; - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// E-CIDMeasurementInitiationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct e_c_id_meas_initiation_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { - lmf_ue_meas_id, - report_characteristics, - meas_periodicity, - meas_quantities, - other_rat_meas_quantities, - wlan_meas_quantities, - meas_periodicity_nr_ao_a, - nulltype - } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lmf_ue_meas_id(); - report_characteristics_e& report_characteristics(); - meas_periodicity_e& meas_periodicity(); - meas_quantities_l& meas_quantities(); - other_rat_meas_quantities_l& other_rat_meas_quantities(); - wlan_meas_quantities_l& wlan_meas_quantities(); - meas_periodicity_nr_ao_a_e& meas_periodicity_nr_ao_a(); - const uint8_t& lmf_ue_meas_id() const; - const report_characteristics_e& report_characteristics() const; - const meas_periodicity_e& meas_periodicity() const; - const meas_quantities_l& meas_quantities() const; - const other_rat_meas_quantities_l& other_rat_meas_quantities() const; - const wlan_meas_quantities_l& wlan_meas_quantities() const; - const meas_periodicity_nr_ao_a_e& meas_periodicity_nr_ao_a() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// E-CIDMeasurementInitiationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct e_c_id_meas_initiation_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { - lmf_ue_meas_id, - ran_ue_meas_id, - e_c_id_meas_result, - crit_diagnostics, - cell_portion_id, - other_rat_meas_result, - wlan_meas_result, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lmf_ue_meas_id(); - uint8_t& ran_ue_meas_id(); - e_c_id_meas_result_s& e_c_id_meas_result(); - crit_diagnostics_s& crit_diagnostics(); - uint16_t& cell_portion_id(); - other_rat_meas_result_l& other_rat_meas_result(); - wlan_meas_result_l& wlan_meas_result(); - const uint8_t& lmf_ue_meas_id() const; - const uint8_t& ran_ue_meas_id() const; - const e_c_id_meas_result_s& e_c_id_meas_result() const; - const crit_diagnostics_s& crit_diagnostics() const; - const uint16_t& cell_portion_id() const; - const other_rat_meas_result_l& other_rat_meas_result() const; - const wlan_meas_result_l& wlan_meas_result() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// E-CIDMeasurementReport-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct e_c_id_meas_report_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_ue_meas_id, ran_ue_meas_id, e_c_id_meas_result, cell_portion_id, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lmf_ue_meas_id(); - uint8_t& ran_ue_meas_id(); - e_c_id_meas_result_s& e_c_id_meas_result(); - uint16_t& cell_portion_id(); - const uint8_t& lmf_ue_meas_id() const; - const uint8_t& ran_ue_meas_id() const; - const e_c_id_meas_result_s& e_c_id_meas_result() const; - const uint16_t& cell_portion_id() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// E-CIDMeasurementTerminationCommand-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct e_c_id_meas_termination_cmd_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_ue_meas_id, ran_ue_meas_id, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint8_t& lmf_ue_meas_id(); - uint8_t& ran_ue_meas_id(); - const uint8_t& lmf_ue_meas_id() const; - const uint8_t& ran_ue_meas_id() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// ErrorIndication-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct error_ind_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementAbort-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_abort_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_meas_id, ran_meas_id, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - uint32_t& ran_meas_id(); - const uint32_t& lmf_meas_id() const; - const uint32_t& ran_meas_id() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementActivation-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_activation_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { request_type, prs_meass_info_list, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - request_type_e& request_type(); - prs_meass_info_list_l& prs_meass_info_list(); - const request_type_e& request_type() const; - const prs_meass_info_list_l& prs_meass_info_list() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_meas_id, cause, crit_diagnostics, nulltype } value; - typedef uint8_t number_type; - - const char* to_string() const; - uint8_t to_number() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const uint32_t& lmf_meas_id() const; - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementFailureIndication-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_fail_ind_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_meas_id, ran_meas_id, cause, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - uint32_t& ran_meas_id(); - cause_c& cause(); - const uint32_t& lmf_meas_id() const; - const uint32_t& ran_meas_id() const; - const cause_c& cause() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementPreconfigurationConfirm-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_precfg_confirm_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { precfg_result, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - fixed_bitstring<8, false, true>& precfg_result(); - crit_diagnostics_s& crit_diagnostics(); - const fixed_bitstring<8, false, true>& precfg_result() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementPreconfigurationRefuse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_precfg_refuse_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementReport-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_report_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_meas_id, ran_meas_id, trp_meas_report_list, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - uint32_t& ran_meas_id(); - trp_meas_resp_list_l& trp_meas_report_list(); - const uint32_t& lmf_meas_id() const; - const uint32_t& ran_meas_id() const; - const trp_meas_resp_list_l& trp_meas_report_list() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { - lmf_meas_id, - trp_meas_request_list, - report_characteristics, - meas_periodicity, - trp_meas_quantities, - sfn_initisation_time, - srscfg, - meas_beam_info_request, - sys_frame_num, - slot_num, - meas_periodicity_extended, - resp_time, - meas_characteristics_request_ind, - meas_time_occasion, - meas_amount, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - trp_meas_request_list_l& trp_meas_request_list(); - report_characteristics_e& report_characteristics(); - meas_periodicity_e& meas_periodicity(); - trp_meas_quantities_l& trp_meas_quantities(); - fixed_bitstring<64, false, true>& sfn_initisation_time(); - srscfg_s& srscfg(); - meas_beam_info_request_e& meas_beam_info_request(); - uint16_t& sys_frame_num(); - uint8_t& slot_num(); - meas_periodicity_extended_e& meas_periodicity_extended(); - resp_time_s& resp_time(); - fixed_bitstring<16, false, true>& meas_characteristics_request_ind(); - meas_time_occasion_e& meas_time_occasion(); - meas_amount_e& meas_amount(); - const uint32_t& lmf_meas_id() const; - const trp_meas_request_list_l& trp_meas_request_list() const; - const report_characteristics_e& report_characteristics() const; - const meas_periodicity_e& meas_periodicity() const; - const trp_meas_quantities_l& trp_meas_quantities() const; - const fixed_bitstring<64, false, true>& sfn_initisation_time() const; - const srscfg_s& srscfg() const; - const meas_beam_info_request_e& meas_beam_info_request() const; - const uint16_t& sys_frame_num() const; - const uint8_t& slot_num() const; - const meas_periodicity_extended_e& meas_periodicity_extended() const; - const resp_time_s& resp_time() const; - const fixed_bitstring<16, false, true>& meas_characteristics_request_ind() const; - const meas_time_occasion_e& meas_time_occasion() const; - const meas_amount_e& meas_amount() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { lmf_meas_id, ran_meas_id, trp_meas_resp_list, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - uint32_t& ran_meas_id(); - trp_meas_resp_list_l& trp_meas_resp_list(); - crit_diagnostics_s& crit_diagnostics(); - const uint32_t& lmf_meas_id() const; - const uint32_t& ran_meas_id() const; - const trp_meas_resp_list_l& trp_meas_resp_list() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// MeasurementUpdate-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_upd_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { - lmf_meas_id, - ran_meas_id, - srscfg, - trp_meas_upd_list, - meas_characteristics_request_ind, - meas_time_occasion, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - uint32_t& lmf_meas_id(); - uint32_t& ran_meas_id(); - srscfg_s& srscfg(); - trp_meas_upd_list_l& trp_meas_upd_list(); - fixed_bitstring<16, false, true>& meas_characteristics_request_ind(); - meas_time_occasion_e& meas_time_occasion(); - const uint32_t& lmf_meas_id() const; - const uint32_t& ran_meas_id() const; - const srscfg_s& srscfg() const; - const trp_meas_upd_list_l& trp_meas_upd_list() const; - const fixed_bitstring<16, false, true>& meas_characteristics_request_ind() const; - const meas_time_occasion_e& meas_time_occasion() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// OTDOAInformationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct otdoa_info_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// OTDOAInformationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct otdoa_info_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { otdoa_cells, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - otdoa_cells_l& otdoa_cells(); - crit_diagnostics_s& crit_diagnostics(); - const otdoa_cells_l& otdoa_cells() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// OTDOA-Information-Type ::= SEQUENCE (SIZE (1..63)) OF ProtocolIE-Single-Container{NRPPA-PROTOCOL-IES : IEsSetParam} -using otdoa_info_type_l = dyn_array>; - -// PositioningActivationFailureIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_activation_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningActivationRequestIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_activation_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { srs_type, activation_time, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - srs_type_c& srs_type(); - fixed_bitstring<64, false, true>& activation_time(); - const srs_type_c& srs_type() const; - const fixed_bitstring<64, false, true>& activation_time() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningActivationResponseIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_activation_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { crit_diagnostics, sys_frame_num, slot_num, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - crit_diagnostics_s& crit_diagnostics(); - uint16_t& sys_frame_num(); - uint8_t& slot_num(); - const crit_diagnostics_s& crit_diagnostics() const; - const uint16_t& sys_frame_num() const; - const uint8_t& slot_num() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningInformationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_info_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningInformationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_info_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { - requested_srs_tx_characteristics, - ue_report_info, - ue_teg_info_request, - ue_teg_report_periodicity, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - requested_srs_tx_characteristics_s& requested_srs_tx_characteristics(); - ue_report_info_s& ue_report_info(); - ue_teg_info_request_e& ue_teg_info_request(); - ue_teg_report_periodicity_e& ue_teg_report_periodicity(); - const requested_srs_tx_characteristics_s& requested_srs_tx_characteristics() const; - const ue_report_info_s& ue_report_info() const; - const ue_teg_info_request_e& ue_teg_info_request() const; - const ue_teg_report_periodicity_e& ue_teg_report_periodicity() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningInformationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_info_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { srscfg, sfn_initisation_time, crit_diagnostics, ue_tx_teg_assoc_list, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - srscfg_s& srscfg(); - fixed_bitstring<64, false, true>& sfn_initisation_time(); - crit_diagnostics_s& crit_diagnostics(); - ue_tx_teg_assoc_list_l& ue_tx_teg_assoc_list(); - const srscfg_s& srscfg() const; - const fixed_bitstring<64, false, true>& sfn_initisation_time() const; - const crit_diagnostics_s& crit_diagnostics() const; - const ue_tx_teg_assoc_list_l& ue_tx_teg_assoc_list() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningInformationUpdate-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_info_upd_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { srscfg, sfn_initisation_time, ue_tx_teg_assoc_list, srs_tx_status, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - srscfg_s& srscfg(); - fixed_bitstring<64, false, true>& sfn_initisation_time(); - ue_tx_teg_assoc_list_l& ue_tx_teg_assoc_list(); - srs_tx_status_e& srs_tx_status(); - const srscfg_s& srscfg() const; - const fixed_bitstring<64, false, true>& sfn_initisation_time() const; - const ue_tx_teg_assoc_list_l& ue_tx_teg_assoc_list() const; - const srs_tx_status_e& srs_tx_status() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PRSConfigurationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct prs_cfg_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PRSConfigurationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct prs_cfg_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { prs_cfg_request_type, prstrp_list, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - prs_cfg_request_type_e& prs_cfg_request_type(); - prstrp_list_l& prstrp_list(); - const prs_cfg_request_type_e& prs_cfg_request_type() const; - const prstrp_list_l& prstrp_list() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PRSConfigurationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct prs_cfg_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { prs_tx_trp_list, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - prs_tx_trp_list_l& prs_tx_trp_list(); - crit_diagnostics_s& crit_diagnostics(); - const prs_tx_trp_list_l& prs_tx_trp_list() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TRPInformationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct trp_info_fail_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { cause, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - cause_c& cause(); - crit_diagnostics_s& crit_diagnostics(); - const cause_c& cause() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TRPInformationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct trp_info_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { trp_list, trp_info_type_list_trp_req, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_list_l& trp_list(); - trp_info_type_list_trp_req_l& trp_info_type_list_trp_req(); - const trp_list_l& trp_list() const; - const trp_info_type_list_trp_req_l& trp_info_type_list_trp_req() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TRPInformationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct trp_info_resp_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { trp_info_list_trp_resp, crit_diagnostics, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - value_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_info_list_trp_resp_l& trp_info_list_trp_resp(); - crit_diagnostics_s& crit_diagnostics(); - const trp_info_list_trp_resp_l& trp_info_list_trp_resp() const; - const crit_diagnostics_s& crit_diagnostics() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// TRP-PRS-Information-List ::= SEQUENCE (SIZE (1..256)) OF TRP-PRS-Information-List-Item -using trp_prs_info_list_l = dyn_array; - -// MeasurementPreconfigurationRequired-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct meas_precfg_required_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { trp_prs_info_list, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::trp_prs_info_list; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - trp_prs_info_list_l& trp_prs_info_list() { return c; } - const trp_prs_info_list_l& trp_prs_info_list() const { return c; } - - private: - trp_prs_info_list_l c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// OTDOAInformationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct otdoa_info_request_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { otdoa_info_type_group, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::otdoa_info_type_group; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - otdoa_info_type_l& otdoa_info_type_group() { return c; } - const otdoa_info_type_l& otdoa_info_type_group() const { return c; } - - private: - otdoa_info_type_l c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -// PositioningDeactivationIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -struct positioning_deactivation_ies_o { - // Value ::= OPEN TYPE - struct value_c { - struct types_opts { - enum options { abort_tx, nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::abort_tx; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - abort_tx_c& abort_tx() { return c; } - const abort_tx_c& abort_tx() const { return c; } - - private: - abort_tx_c c; - }; - - // members lookup methods - static uint32_t idx_to_id(uint32_t idx); - static bool is_id_valid(const uint32_t& id); - static crit_e get_crit(const uint32_t& id); - static value_c get_value(const uint32_t& id); - static presence_e get_presence(const uint32_t& id); -}; - -struct private_ie_container_empty_l { - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct assist_info_ctrl_ies_container { - bool assist_info_present = false; - bool broadcast_present = false; - bool positioning_broadcast_cells_present = false; - assist_info_s assist_info; - broadcast_e broadcast; - positioning_broadcast_cells_l positioning_broadcast_cells; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct assist_info_feedback_ies_container { - bool assist_info_fail_list_present = false; - bool positioning_broadcast_cells_present = false; - bool crit_diagnostics_present = false; - assist_info_fail_list_l assist_info_fail_list; - positioning_broadcast_cells_l positioning_broadcast_cells; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct e_c_id_meas_fail_ind_ies_container { - uint8_t lmf_ue_meas_id; - uint8_t ran_ue_meas_id; - cause_c cause; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct e_c_id_meas_initiation_fail_ies_container { - bool crit_diagnostics_present = false; - uint8_t lmf_ue_meas_id; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct e_c_id_meas_initiation_request_ies_container { - bool meas_periodicity_present = false; - bool other_rat_meas_quantities_present = false; - bool wlan_meas_quantities_present = false; - bool meas_periodicity_nr_ao_a_present = false; - uint8_t lmf_ue_meas_id; - report_characteristics_e report_characteristics; - meas_periodicity_e meas_periodicity; - meas_quantities_l meas_quantities; - other_rat_meas_quantities_l other_rat_meas_quantities; - wlan_meas_quantities_l wlan_meas_quantities; - meas_periodicity_nr_ao_a_e meas_periodicity_nr_ao_a; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct e_c_id_meas_initiation_resp_ies_container { - bool e_c_id_meas_result_present = false; - bool crit_diagnostics_present = false; - bool cell_portion_id_present = false; - bool other_rat_meas_result_present = false; - bool wlan_meas_result_present = false; - uint8_t lmf_ue_meas_id; - uint8_t ran_ue_meas_id; - e_c_id_meas_result_s e_c_id_meas_result; - crit_diagnostics_s crit_diagnostics; - uint16_t cell_portion_id; - other_rat_meas_result_l other_rat_meas_result; - wlan_meas_result_l wlan_meas_result; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct e_c_id_meas_report_ies_container { - bool cell_portion_id_present = false; - uint8_t lmf_ue_meas_id; - uint8_t ran_ue_meas_id; - e_c_id_meas_result_s e_c_id_meas_result; - uint16_t cell_portion_id; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct e_c_id_meas_termination_cmd_ies_container { - uint8_t lmf_ue_meas_id; - uint8_t ran_ue_meas_id; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct error_ind_ies_container { - bool cause_present = false; - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_abort_ies_container { - uint32_t lmf_meas_id; - uint32_t ran_meas_id; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_activation_ies_container { - bool prs_meass_info_list_present = false; - request_type_e request_type; - prs_meass_info_list_l prs_meass_info_list; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_fail_ies_container { - bool crit_diagnostics_present = false; - uint32_t lmf_meas_id; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_fail_ind_ies_container { - uint32_t lmf_meas_id; - uint32_t ran_meas_id; - cause_c cause; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_precfg_confirm_ies_container { - bool crit_diagnostics_present = false; - fixed_bitstring<8, false, true> precfg_result; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_precfg_refuse_ies_container { - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_report_ies_container { - uint32_t lmf_meas_id; - uint32_t ran_meas_id; - trp_meas_resp_list_l trp_meas_report_list; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_request_ies_container { - bool meas_periodicity_present = false; - bool sfn_initisation_time_present = false; - bool srscfg_present = false; - bool meas_beam_info_request_present = false; - bool sys_frame_num_present = false; - bool slot_num_present = false; - bool meas_periodicity_extended_present = false; - bool resp_time_present = false; - bool meas_characteristics_request_ind_present = false; - bool meas_time_occasion_present = false; - bool meas_amount_present = false; - uint32_t lmf_meas_id; - trp_meas_request_list_l trp_meas_request_list; - report_characteristics_e report_characteristics; - meas_periodicity_e meas_periodicity; - trp_meas_quantities_l trp_meas_quantities; - fixed_bitstring<64, false, true> sfn_initisation_time; - srscfg_s srscfg; - meas_beam_info_request_e meas_beam_info_request; - uint16_t sys_frame_num; - uint8_t slot_num; - meas_periodicity_extended_e meas_periodicity_extended; - resp_time_s resp_time; - fixed_bitstring<16, false, true> meas_characteristics_request_ind; - meas_time_occasion_e meas_time_occasion; - meas_amount_e meas_amount; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_resp_ies_container { - bool trp_meas_resp_list_present = false; - bool crit_diagnostics_present = false; - uint32_t lmf_meas_id; - uint32_t ran_meas_id; - trp_meas_resp_list_l trp_meas_resp_list; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct meas_upd_ies_container { - bool srscfg_present = false; - bool trp_meas_upd_list_present = false; - bool meas_characteristics_request_ind_present = false; - bool meas_time_occasion_present = false; - uint32_t lmf_meas_id; - uint32_t ran_meas_id; - srscfg_s srscfg; - trp_meas_upd_list_l trp_meas_upd_list; - fixed_bitstring<16, false, true> meas_characteristics_request_ind; - meas_time_occasion_e meas_time_occasion; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct otdoa_info_fail_ies_container { - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct otdoa_info_resp_ies_container { - bool crit_diagnostics_present = false; - otdoa_cells_l otdoa_cells; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_activation_fail_ies_container { - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_activation_request_ies_container { - bool activation_time_present = false; - srs_type_c srs_type; - fixed_bitstring<64, false, true> activation_time; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_activation_resp_ies_container { - bool crit_diagnostics_present = false; - bool sys_frame_num_present = false; - bool slot_num_present = false; - crit_diagnostics_s crit_diagnostics; - uint16_t sys_frame_num; - uint8_t slot_num; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_info_fail_ies_container { - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_info_request_ies_container { - bool requested_srs_tx_characteristics_present = false; - bool ue_report_info_present = false; - bool ue_teg_info_request_present = false; - bool ue_teg_report_periodicity_present = false; - requested_srs_tx_characteristics_s requested_srs_tx_characteristics; - ue_report_info_s ue_report_info; - ue_teg_info_request_e ue_teg_info_request; - ue_teg_report_periodicity_e ue_teg_report_periodicity; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_info_resp_ies_container { - bool srscfg_present = false; - bool sfn_initisation_time_present = false; - bool crit_diagnostics_present = false; - bool ue_tx_teg_assoc_list_present = false; - srscfg_s srscfg; - fixed_bitstring<64, false, true> sfn_initisation_time; - crit_diagnostics_s crit_diagnostics; - ue_tx_teg_assoc_list_l ue_tx_teg_assoc_list; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct positioning_info_upd_ies_container { - bool srscfg_present = false; - bool sfn_initisation_time_present = false; - bool ue_tx_teg_assoc_list_present = false; - bool srs_tx_status_present = false; - srscfg_s srscfg; - fixed_bitstring<64, false, true> sfn_initisation_time; - ue_tx_teg_assoc_list_l ue_tx_teg_assoc_list; - srs_tx_status_e srs_tx_status; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -using private_msg_ies_container = private_ie_container_empty_l; - -struct prs_cfg_fail_ies_container { - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct prs_cfg_request_ies_container { - prs_cfg_request_type_e prs_cfg_request_type; - prstrp_list_l prstrp_list; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct prs_cfg_resp_ies_container { - bool prs_tx_trp_list_present = false; - bool crit_diagnostics_present = false; - prs_tx_trp_list_l prs_tx_trp_list; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct trp_info_fail_ies_container { - bool crit_diagnostics_present = false; - cause_c cause; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct trp_info_request_ies_container { - bool trp_list_present = false; - trp_list_l trp_list; - trp_info_type_list_trp_req_l trp_info_type_list_trp_req; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -struct trp_info_resp_ies_container { - bool crit_diagnostics_present = false; - trp_info_list_trp_resp_l trp_info_list_trp_resp; - crit_diagnostics_s crit_diagnostics; - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// AssistanceInformationControl ::= SEQUENCE -using assist_info_ctrl_s = elementary_procedure_option; - -// AssistanceInformationFeedback ::= SEQUENCE -using assist_info_feedback_s = elementary_procedure_option; - -// E-CIDMeasurementFailureIndication ::= SEQUENCE -using e_c_id_meas_fail_ind_s = elementary_procedure_option; - -// E-CIDMeasurementInitiationFailure ::= SEQUENCE -using e_c_id_meas_initiation_fail_s = elementary_procedure_option; - -// E-CIDMeasurementInitiationRequest ::= SEQUENCE -using e_c_id_meas_initiation_request_s = elementary_procedure_option; - -// E-CIDMeasurementInitiationResponse ::= SEQUENCE -using e_c_id_meas_initiation_resp_s = elementary_procedure_option; - -// E-CIDMeasurementReport ::= SEQUENCE -using e_c_id_meas_report_s = elementary_procedure_option; - -// E-CIDMeasurementTerminationCommand ::= SEQUENCE -using e_c_id_meas_termination_cmd_s = elementary_procedure_option; - -// ErrorIndication ::= SEQUENCE -using error_ind_s = elementary_procedure_option; - -// MeasurementAbort ::= SEQUENCE -using meas_abort_s = elementary_procedure_option; - -// MeasurementActivation ::= SEQUENCE -using meas_activation_s = elementary_procedure_option; - -// MeasurementFailureIndication ::= SEQUENCE -using meas_fail_ind_s = elementary_procedure_option; - -// MeasurementFailure ::= SEQUENCE -using meas_fail_s = elementary_procedure_option; - -// MeasurementPreconfigurationConfirm ::= SEQUENCE -using meas_precfg_confirm_s = elementary_procedure_option; - -// MeasurementPreconfigurationRefuse ::= SEQUENCE -using meas_precfg_refuse_s = elementary_procedure_option; - -// MeasurementPreconfigurationRequired ::= SEQUENCE -using meas_precfg_required_s = elementary_procedure_option>; - -// MeasurementReport ::= SEQUENCE -using meas_report_s = elementary_procedure_option; - -// MeasurementRequest ::= SEQUENCE -using meas_request_s = elementary_procedure_option; - -// MeasurementResponse ::= SEQUENCE -using meas_resp_s = elementary_procedure_option; - -// MeasurementUpdate ::= SEQUENCE -using meas_upd_s = elementary_procedure_option; - -// OTDOAInformationFailure ::= SEQUENCE -using otdoa_info_fail_s = elementary_procedure_option; - -// OTDOAInformationRequest ::= SEQUENCE -using otdoa_info_request_s = elementary_procedure_option>; - -// OTDOAInformationResponse ::= SEQUENCE -using otdoa_info_resp_s = elementary_procedure_option; - -// PositioningActivationFailure ::= SEQUENCE -using positioning_activation_fail_s = elementary_procedure_option; - -// PositioningActivationRequest ::= SEQUENCE -using positioning_activation_request_s = elementary_procedure_option; - -// PositioningActivationResponse ::= SEQUENCE -using positioning_activation_resp_s = elementary_procedure_option; - -// PositioningDeactivation ::= SEQUENCE -using positioning_deactivation_s = elementary_procedure_option>; - -// PositioningInformationFailure ::= SEQUENCE -using positioning_info_fail_s = elementary_procedure_option; - -// PositioningInformationRequest ::= SEQUENCE -using positioning_info_request_s = elementary_procedure_option; - -// PositioningInformationResponse ::= SEQUENCE -using positioning_info_resp_s = elementary_procedure_option; - -// PositioningInformationUpdate ::= SEQUENCE -using positioning_info_upd_s = elementary_procedure_option; - -// PrivateMessage ::= SEQUENCE -struct private_msg_s { - bool ext = false; - private_msg_ies_container private_ies; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -// PRSConfigurationFailure ::= SEQUENCE -using prs_cfg_fail_s = elementary_procedure_option; - -// PRSConfigurationRequest ::= SEQUENCE -using prs_cfg_request_s = elementary_procedure_option; - -// PRSConfigurationResponse ::= SEQUENCE -using prs_cfg_resp_s = elementary_procedure_option; - -// TRPInformationFailure ::= SEQUENCE -using trp_info_fail_s = elementary_procedure_option; - -// TRPInformationRequest ::= SEQUENCE -using trp_info_request_s = elementary_procedure_option; - -// TRPInformationResponse ::= SEQUENCE -using trp_info_resp_s = elementary_procedure_option; - -// NRPPA-ELEMENTARY-PROCEDURES ::= OBJECT SET OF NRPPA-ELEMENTARY-PROCEDURE -struct nr_ppa_elem_procs_o { - // InitiatingMessage ::= OPEN TYPE - struct init_msg_c { - struct types_opts { - enum options { - e_c_id_meas_initiation_request, - otdoa_info_request, - positioning_info_request, - meas_request, - trp_info_request, - positioning_activation_request, - prs_cfg_request, - meas_precfg_required, - e_c_id_meas_fail_ind, - e_c_id_meas_report, - e_c_id_meas_termination_cmd, - error_ind, - private_msg, - assist_info_ctrl, - assist_info_feedback, - positioning_info_upd, - meas_report, - meas_upd, - meas_abort, - meas_fail_ind, - positioning_deactivation, - meas_activation, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - init_msg_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_initiation_request_s& e_c_id_meas_initiation_request(); - otdoa_info_request_s& otdoa_info_request(); - positioning_info_request_s& positioning_info_request(); - meas_request_s& meas_request(); - trp_info_request_s& trp_info_request(); - positioning_activation_request_s& positioning_activation_request(); - prs_cfg_request_s& prs_cfg_request(); - meas_precfg_required_s& meas_precfg_required(); - e_c_id_meas_fail_ind_s& e_c_id_meas_fail_ind(); - e_c_id_meas_report_s& e_c_id_meas_report(); - e_c_id_meas_termination_cmd_s& e_c_id_meas_termination_cmd(); - error_ind_s& error_ind(); - private_msg_s& private_msg(); - assist_info_ctrl_s& assist_info_ctrl(); - assist_info_feedback_s& assist_info_feedback(); - positioning_info_upd_s& positioning_info_upd(); - meas_report_s& meas_report(); - meas_upd_s& meas_upd(); - meas_abort_s& meas_abort(); - meas_fail_ind_s& meas_fail_ind(); - positioning_deactivation_s& positioning_deactivation(); - meas_activation_s& meas_activation(); - const e_c_id_meas_initiation_request_s& e_c_id_meas_initiation_request() const; - const otdoa_info_request_s& otdoa_info_request() const; - const positioning_info_request_s& positioning_info_request() const; - const meas_request_s& meas_request() const; - const trp_info_request_s& trp_info_request() const; - const positioning_activation_request_s& positioning_activation_request() const; - const prs_cfg_request_s& prs_cfg_request() const; - const meas_precfg_required_s& meas_precfg_required() const; - const e_c_id_meas_fail_ind_s& e_c_id_meas_fail_ind() const; - const e_c_id_meas_report_s& e_c_id_meas_report() const; - const e_c_id_meas_termination_cmd_s& e_c_id_meas_termination_cmd() const; - const error_ind_s& error_ind() const; - const private_msg_s& private_msg() const; - const assist_info_ctrl_s& assist_info_ctrl() const; - const assist_info_feedback_s& assist_info_feedback() const; - const positioning_info_upd_s& positioning_info_upd() const; - const meas_report_s& meas_report() const; - const meas_upd_s& meas_upd() const; - const meas_abort_s& meas_abort() const; - const meas_fail_ind_s& meas_fail_ind() const; - const positioning_deactivation_s& positioning_deactivation() const; - const meas_activation_s& meas_activation() const; - - private: - types type_; - choice_buffer_ptr c; - }; - // SuccessfulOutcome ::= OPEN TYPE - struct successful_outcome_c { - struct types_opts { - enum options { - e_c_id_meas_initiation_resp, - otdoa_info_resp, - positioning_info_resp, - meas_resp, - trp_info_resp, - positioning_activation_resp, - prs_cfg_resp, - meas_precfg_confirm, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - successful_outcome_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_initiation_resp_s& e_c_id_meas_initiation_resp(); - otdoa_info_resp_s& otdoa_info_resp(); - positioning_info_resp_s& positioning_info_resp(); - meas_resp_s& meas_resp(); - trp_info_resp_s& trp_info_resp(); - positioning_activation_resp_s& positioning_activation_resp(); - prs_cfg_resp_s& prs_cfg_resp(); - meas_precfg_confirm_s& meas_precfg_confirm(); - const e_c_id_meas_initiation_resp_s& e_c_id_meas_initiation_resp() const; - const otdoa_info_resp_s& otdoa_info_resp() const; - const positioning_info_resp_s& positioning_info_resp() const; - const meas_resp_s& meas_resp() const; - const trp_info_resp_s& trp_info_resp() const; - const positioning_activation_resp_s& positioning_activation_resp() const; - const prs_cfg_resp_s& prs_cfg_resp() const; - const meas_precfg_confirm_s& meas_precfg_confirm() const; - - private: - types type_; - choice_buffer_ptr c; - }; - // UnsuccessfulOutcome ::= OPEN TYPE - struct unsuccessful_outcome_c { - struct types_opts { - enum options { - e_c_id_meas_initiation_fail, - otdoa_info_fail, - positioning_info_fail, - meas_fail, - trp_info_fail, - positioning_activation_fail, - prs_cfg_fail, - meas_precfg_refuse, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - unsuccessful_outcome_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_initiation_fail_s& e_c_id_meas_initiation_fail(); - otdoa_info_fail_s& otdoa_info_fail(); - positioning_info_fail_s& positioning_info_fail(); - meas_fail_s& meas_fail(); - trp_info_fail_s& trp_info_fail(); - positioning_activation_fail_s& positioning_activation_fail(); - prs_cfg_fail_s& prs_cfg_fail(); - meas_precfg_refuse_s& meas_precfg_refuse(); - const e_c_id_meas_initiation_fail_s& e_c_id_meas_initiation_fail() const; - const otdoa_info_fail_s& otdoa_info_fail() const; - const positioning_info_fail_s& positioning_info_fail() const; - const meas_fail_s& meas_fail() const; - const trp_info_fail_s& trp_info_fail() const; - const positioning_activation_fail_s& positioning_activation_fail() const; - const prs_cfg_fail_s& prs_cfg_fail() const; - const meas_precfg_refuse_s& meas_precfg_refuse() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint16_t idx_to_proc_code(uint32_t idx); - static bool is_proc_code_valid(const uint16_t& proc_code); - static init_msg_c get_init_msg(const uint16_t& proc_code); - static successful_outcome_c get_successful_outcome(const uint16_t& proc_code); - static unsuccessful_outcome_c get_unsuccessful_outcome(const uint16_t& proc_code); - static crit_e get_crit(const uint16_t& proc_code); -}; - -// InitiatingMessage ::= SEQUENCE{{NRPPA-ELEMENTARY-PROCEDURE}} -struct init_msg_s { - uint16_t proc_code = 0; - crit_e crit; - uint16_t nrppatransaction_id = 0; - nr_ppa_elem_procs_o::init_msg_c value; - - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - bool load_info_obj(const uint16_t& proc_code_); -}; - -using srs_res_id_item_ext_ies_container = protocol_ext_container_empty_l; - -// SuccessfulOutcome ::= SEQUENCE{{NRPPA-ELEMENTARY-PROCEDURE}} -struct successful_outcome_s { - uint16_t proc_code = 0; - crit_e crit; - uint16_t nrppatransaction_id = 0; - nr_ppa_elem_procs_o::successful_outcome_c value; - - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - bool load_info_obj(const uint16_t& proc_code_); -}; - -// UnsuccessfulOutcome ::= SEQUENCE{{NRPPA-ELEMENTARY-PROCEDURE}} -struct unsuccessful_outcome_s { - uint16_t proc_code = 0; - crit_e crit; - uint16_t nrppatransaction_id = 0; - nr_ppa_elem_procs_o::unsuccessful_outcome_c value; - - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - bool load_info_obj(const uint16_t& proc_code_); -}; - -// NRPPA-ELEMENTARY-PROCEDURES-CLASS-1 ::= OBJECT SET OF NRPPA-ELEMENTARY-PROCEDURE -struct nr_ppa_elem_procs_class_1_o { - // InitiatingMessage ::= OPEN TYPE - struct init_msg_c { - struct types_opts { - enum options { - e_c_id_meas_initiation_request, - otdoa_info_request, - positioning_info_request, - meas_request, - trp_info_request, - positioning_activation_request, - prs_cfg_request, - meas_precfg_required, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - init_msg_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_initiation_request_s& e_c_id_meas_initiation_request(); - otdoa_info_request_s& otdoa_info_request(); - positioning_info_request_s& positioning_info_request(); - meas_request_s& meas_request(); - trp_info_request_s& trp_info_request(); - positioning_activation_request_s& positioning_activation_request(); - prs_cfg_request_s& prs_cfg_request(); - meas_precfg_required_s& meas_precfg_required(); - const e_c_id_meas_initiation_request_s& e_c_id_meas_initiation_request() const; - const otdoa_info_request_s& otdoa_info_request() const; - const positioning_info_request_s& positioning_info_request() const; - const meas_request_s& meas_request() const; - const trp_info_request_s& trp_info_request() const; - const positioning_activation_request_s& positioning_activation_request() const; - const prs_cfg_request_s& prs_cfg_request() const; - const meas_precfg_required_s& meas_precfg_required() const; - - private: - types type_; - choice_buffer_ptr c; - }; - // SuccessfulOutcome ::= OPEN TYPE - struct successful_outcome_c { - struct types_opts { - enum options { - e_c_id_meas_initiation_resp, - otdoa_info_resp, - positioning_info_resp, - meas_resp, - trp_info_resp, - positioning_activation_resp, - prs_cfg_resp, - meas_precfg_confirm, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - successful_outcome_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_initiation_resp_s& e_c_id_meas_initiation_resp(); - otdoa_info_resp_s& otdoa_info_resp(); - positioning_info_resp_s& positioning_info_resp(); - meas_resp_s& meas_resp(); - trp_info_resp_s& trp_info_resp(); - positioning_activation_resp_s& positioning_activation_resp(); - prs_cfg_resp_s& prs_cfg_resp(); - meas_precfg_confirm_s& meas_precfg_confirm(); - const e_c_id_meas_initiation_resp_s& e_c_id_meas_initiation_resp() const; - const otdoa_info_resp_s& otdoa_info_resp() const; - const positioning_info_resp_s& positioning_info_resp() const; - const meas_resp_s& meas_resp() const; - const trp_info_resp_s& trp_info_resp() const; - const positioning_activation_resp_s& positioning_activation_resp() const; - const prs_cfg_resp_s& prs_cfg_resp() const; - const meas_precfg_confirm_s& meas_precfg_confirm() const; - - private: - types type_; - choice_buffer_ptr c; - }; - // UnsuccessfulOutcome ::= OPEN TYPE - struct unsuccessful_outcome_c { - struct types_opts { - enum options { - e_c_id_meas_initiation_fail, - otdoa_info_fail, - positioning_info_fail, - meas_fail, - trp_info_fail, - positioning_activation_fail, - prs_cfg_fail, - meas_precfg_refuse, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - unsuccessful_outcome_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_initiation_fail_s& e_c_id_meas_initiation_fail(); - otdoa_info_fail_s& otdoa_info_fail(); - positioning_info_fail_s& positioning_info_fail(); - meas_fail_s& meas_fail(); - trp_info_fail_s& trp_info_fail(); - positioning_activation_fail_s& positioning_activation_fail(); - prs_cfg_fail_s& prs_cfg_fail(); - meas_precfg_refuse_s& meas_precfg_refuse(); - const e_c_id_meas_initiation_fail_s& e_c_id_meas_initiation_fail() const; - const otdoa_info_fail_s& otdoa_info_fail() const; - const positioning_info_fail_s& positioning_info_fail() const; - const meas_fail_s& meas_fail() const; - const trp_info_fail_s& trp_info_fail() const; - const positioning_activation_fail_s& positioning_activation_fail() const; - const prs_cfg_fail_s& prs_cfg_fail() const; - const meas_precfg_refuse_s& meas_precfg_refuse() const; - - private: - types type_; - choice_buffer_ptr c; - }; - - // members lookup methods - static uint16_t idx_to_proc_code(uint32_t idx); - static bool is_proc_code_valid(const uint16_t& proc_code); - static init_msg_c get_init_msg(const uint16_t& proc_code); - static successful_outcome_c get_successful_outcome(const uint16_t& proc_code); - static unsuccessful_outcome_c get_unsuccessful_outcome(const uint16_t& proc_code); - static crit_e get_crit(const uint16_t& proc_code); -}; - -// NRPPA-ELEMENTARY-PROCEDURES-CLASS-2 ::= OBJECT SET OF NRPPA-ELEMENTARY-PROCEDURE -struct nr_ppa_elem_procs_class_2_o { - // InitiatingMessage ::= OPEN TYPE - struct init_msg_c { - struct types_opts { - enum options { - e_c_id_meas_fail_ind, - e_c_id_meas_report, - e_c_id_meas_termination_cmd, - error_ind, - private_msg, - assist_info_ctrl, - assist_info_feedback, - positioning_info_upd, - meas_report, - meas_upd, - meas_abort, - meas_fail_ind, - positioning_deactivation, - meas_activation, - nulltype - } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - init_msg_c() = default; - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - e_c_id_meas_fail_ind_s& e_c_id_meas_fail_ind(); - e_c_id_meas_report_s& e_c_id_meas_report(); - e_c_id_meas_termination_cmd_s& e_c_id_meas_termination_cmd(); - error_ind_s& error_ind(); - private_msg_s& private_msg(); - assist_info_ctrl_s& assist_info_ctrl(); - assist_info_feedback_s& assist_info_feedback(); - positioning_info_upd_s& positioning_info_upd(); - meas_report_s& meas_report(); - meas_upd_s& meas_upd(); - meas_abort_s& meas_abort(); - meas_fail_ind_s& meas_fail_ind(); - positioning_deactivation_s& positioning_deactivation(); - meas_activation_s& meas_activation(); - const e_c_id_meas_fail_ind_s& e_c_id_meas_fail_ind() const; - const e_c_id_meas_report_s& e_c_id_meas_report() const; - const e_c_id_meas_termination_cmd_s& e_c_id_meas_termination_cmd() const; - const error_ind_s& error_ind() const; - const private_msg_s& private_msg() const; - const assist_info_ctrl_s& assist_info_ctrl() const; - const assist_info_feedback_s& assist_info_feedback() const; - const positioning_info_upd_s& positioning_info_upd() const; - const meas_report_s& meas_report() const; - const meas_upd_s& meas_upd() const; - const meas_abort_s& meas_abort() const; - const meas_fail_ind_s& meas_fail_ind() const; - const positioning_deactivation_s& positioning_deactivation() const; - const meas_activation_s& meas_activation() const; - - private: - types type_; - choice_buffer_ptr c; - }; - // SuccessfulOutcome ::= OPEN TYPE - struct successful_outcome_c { - struct types_opts { - enum options { nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::nulltype; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - }; - // UnsuccessfulOutcome ::= OPEN TYPE - struct unsuccessful_outcome_c { - struct types_opts { - enum options { nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - types type() const { return types::nulltype; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - }; - - // members lookup methods - static uint16_t idx_to_proc_code(uint32_t idx); - static bool is_proc_code_valid(const uint16_t& proc_code); - static init_msg_c get_init_msg(const uint16_t& proc_code); - static successful_outcome_c get_successful_outcome(const uint16_t& proc_code); - static unsuccessful_outcome_c get_unsuccessful_outcome(const uint16_t& proc_code); - static crit_e get_crit(const uint16_t& proc_code); -}; - -// NRPPA-PDU ::= CHOICE -struct nr_ppa_pdu_c { - struct types_opts { - enum options { init_msg, successful_outcome, unsuccessful_outcome, /*...*/ nulltype } value; - - const char* to_string() const; - }; - using types = enumerated; - - // choice methods - nr_ppa_pdu_c() = default; - nr_ppa_pdu_c(const nr_ppa_pdu_c& other); - nr_ppa_pdu_c& operator=(const nr_ppa_pdu_c& other); - ~nr_ppa_pdu_c() { destroy_(); } - void set(types::options e = types::nulltype); - types type() const { return type_; } - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; - // getters - init_msg_s& init_msg() - { - assert_choice_type(types::init_msg, type_, "NRPPA-PDU"); - return c.get(); - } - successful_outcome_s& successful_outcome() - { - assert_choice_type(types::successful_outcome, type_, "NRPPA-PDU"); - return c.get(); - } - unsuccessful_outcome_s& unsuccessful_outcome() - { - assert_choice_type(types::unsuccessful_outcome, type_, "NRPPA-PDU"); - return c.get(); - } - const init_msg_s& init_msg() const - { - assert_choice_type(types::init_msg, type_, "NRPPA-PDU"); - return c.get(); - } - const successful_outcome_s& successful_outcome() const - { - assert_choice_type(types::successful_outcome, type_, "NRPPA-PDU"); - return c.get(); - } - const unsuccessful_outcome_s& unsuccessful_outcome() const - { - assert_choice_type(types::unsuccessful_outcome, type_, "NRPPA-PDU"); - return c.get(); - } - init_msg_s& set_init_msg(); - successful_outcome_s& set_successful_outcome(); - unsuccessful_outcome_s& set_unsuccessful_outcome(); - -private: - types type_; - choice_buffer_t c; - - void destroy_(); -}; - -// PrivateIE-Container{NRPPA-PRIVATE-IES : IEsSetParam} ::= SEQUENCE (SIZE (1..65535)) OF PrivateIE-Field -template -using private_ie_container_l = dyn_seq_of, 1, 65535, true>; - -// SRSResourceID-Item ::= SEQUENCE -struct srs_res_id_item_s { - bool ext = false; - bool ie_exts_present = false; - uint8_t srs_res_id = 0; - srs_res_id_item_ext_ies_container ie_exts; - // ... - - // sequence methods - SRSASN_CODE pack(bit_ref& bref) const; - SRSASN_CODE unpack(cbit_ref& bref); - void to_json(json_writer& j) const; -}; - -} // namespace nrppa -} // namespace asn1 - -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ext_field_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_single_container_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; -extern template struct asn1::protocol_ie_field_s; diff --git a/lib/asn1/CMakeLists.txt b/lib/asn1/CMakeLists.txt index 117c7517e5..de79c2127b 100644 --- a/lib/asn1/CMakeLists.txt +++ b/lib/asn1/CMakeLists.txt @@ -34,9 +34,3 @@ target_link_libraries(e2ap_asn1 asn1_utils) add_library(ngap_asn1 STATIC ngap/common.cpp ngap/ngap_ies.cpp ngap/ngap_pdu_contents.cpp ngap/ngap.cpp) target_compile_options(ngap_asn1 PRIVATE -Os -fno-exceptions) target_link_libraries(ngap_asn1 asn1_utils) - -# NRPPa ASN1 -add_library(nrppa_asn1 STATIC nrppa/nrppa.cpp) -target_compile_options(nrppa_asn1 PRIVATE -Os -fno-exceptions) -target_link_libraries(nrppa_asn1 asn1_utils) - diff --git a/lib/asn1/nrppa/nrppa.cpp b/lib/asn1/nrppa/nrppa.cpp deleted file mode 100644 index 54550f6480..0000000000 --- a/lib/asn1/nrppa/nrppa.cpp +++ /dev/null @@ -1,34158 +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/asn1/nrppa/nrppa.h" -using namespace asn1; -using namespace asn1::nrppa; - -/******************************************************************************* - * Struct Methods - ******************************************************************************/ - -// LCS-to-GCS-Translation ::= SEQUENCE -SRSASN_CODE lcs_to_gcs_translation_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, alpha, (uint16_t)0u, (uint16_t)3599u, false, true)); - HANDLE_CODE(pack_integer(bref, beta, (uint16_t)0u, (uint16_t)3599u, false, true)); - HANDLE_CODE(pack_integer(bref, gamma, (uint16_t)0u, (uint16_t)3599u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE lcs_to_gcs_translation_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(alpha, bref, (uint16_t)0u, (uint16_t)3599u, false, true)); - HANDLE_CODE(unpack_integer(beta, bref, (uint16_t)0u, (uint16_t)3599u, false, true)); - HANDLE_CODE(unpack_integer(gamma, bref, (uint16_t)0u, (uint16_t)3599u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void lcs_to_gcs_translation_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("alpha", alpha); - j.write_int("beta", beta); - j.write_int("gamma", gamma); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// UL-AoA ::= SEQUENCE -SRSASN_CODE ul_ao_a_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(zenith_ao_a_present, 1)); - HANDLE_CODE(bref.pack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, azimuth_ao_a, (uint16_t)0u, (uint16_t)3599u, false, true)); - if (zenith_ao_a_present) { - HANDLE_CODE(pack_integer(bref, zenith_ao_a, (uint16_t)0u, (uint16_t)1799u, false, true)); - } - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ul_ao_a_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(zenith_ao_a_present, 1)); - HANDLE_CODE(bref.unpack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(azimuth_ao_a, bref, (uint16_t)0u, (uint16_t)3599u, false, true)); - if (zenith_ao_a_present) { - HANDLE_CODE(unpack_integer(zenith_ao_a, bref, (uint16_t)0u, (uint16_t)1799u, false, true)); - } - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ul_ao_a_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("azimuthAoA", azimuth_ao_a); - if (zenith_ao_a_present) { - j.write_int("zenithAoA", zenith_ao_a); - } - if (lcs_to_gcs_translation_present) { - j.write_fieldname("lCS-to-GCS-Translation"); - lcs_to_gcs_translation.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ZoA ::= SEQUENCE -SRSASN_CODE zo_a_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, zenith_ao_a, (uint16_t)0u, (uint16_t)1799u, false, true)); - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE zo_a_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(zenith_ao_a, bref, (uint16_t)0u, (uint16_t)1799u, false, true)); - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void zo_a_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("zenithAoA", zenith_ao_a); - if (lcs_to_gcs_translation_present) { - j.write_fieldname("lCS-to-GCS-Translation"); - lcs_to_gcs_translation.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// MultipleULAoA-Item ::= CHOICE -void multiple_ul_ao_a_item_c::destroy_() -{ - switch (type_) { - case types::ul_ao_a: - c.destroy(); - break; - case types::ul_zo_a: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void multiple_ul_ao_a_item_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::ul_ao_a: - c.init(); - break; - case types::ul_zo_a: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "multiple_ul_ao_a_item_c"); - } -} -multiple_ul_ao_a_item_c::multiple_ul_ao_a_item_c(const multiple_ul_ao_a_item_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::ul_ao_a: - c.init(other.c.get()); - break; - case types::ul_zo_a: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "multiple_ul_ao_a_item_c"); - } -} -multiple_ul_ao_a_item_c& multiple_ul_ao_a_item_c::operator=(const multiple_ul_ao_a_item_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::ul_ao_a: - c.set(other.c.get()); - break; - case types::ul_zo_a: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "multiple_ul_ao_a_item_c"); - } - - return *this; -} -ul_ao_a_s& multiple_ul_ao_a_item_c::set_ul_ao_a() -{ - set(types::ul_ao_a); - return c.get(); -} -zo_a_s& multiple_ul_ao_a_item_c::set_ul_zo_a() -{ - set(types::ul_zo_a); - return c.get(); -} -protocol_ie_single_container_s& multiple_ul_ao_a_item_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void multiple_ul_ao_a_item_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::ul_ao_a: - j.write_fieldname("uL-AoA"); - c.get().to_json(j); - break; - case types::ul_zo_a: - j.write_fieldname("ul-ZoA"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "multiple_ul_ao_a_item_c"); - } - j.end_obj(); -} -SRSASN_CODE multiple_ul_ao_a_item_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::ul_ao_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ul_zo_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "multiple_ul_ao_a_item_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE multiple_ul_ao_a_item_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::ul_ao_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ul_zo_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "multiple_ul_ao_a_item_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* multiple_ul_ao_a_item_c::types_opts::to_string() const -{ - static const char* names[] = {"uL-AoA", "ul-ZoA", "choice-extension"}; - return convert_enum_idx(names, 3, value, "multiple_ul_ao_a_item_c::types"); -} - -// TRP-Beam-Power-Item ::= SEQUENCE -SRSASN_CODE trp_beam_pwr_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(prs_res_set_id_present, 1)); - HANDLE_CODE(bref.pack(relative_pwr_fine_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (prs_res_set_id_present) { - HANDLE_CODE(pack_integer(bref, prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - } - HANDLE_CODE(pack_integer(bref, prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(pack_integer(bref, relative_pwr, (uint8_t)0u, (uint8_t)30u, false, true)); - if (relative_pwr_fine_present) { - HANDLE_CODE(pack_integer(bref, relative_pwr_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_beam_pwr_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(prs_res_set_id_present, 1)); - HANDLE_CODE(bref.unpack(relative_pwr_fine_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (prs_res_set_id_present) { - HANDLE_CODE(unpack_integer(prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - } - HANDLE_CODE(unpack_integer(prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(unpack_integer(relative_pwr, bref, (uint8_t)0u, (uint8_t)30u, false, true)); - if (relative_pwr_fine_present) { - HANDLE_CODE(unpack_integer(relative_pwr_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_beam_pwr_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (prs_res_set_id_present) { - j.write_int("pRSResourceSetID", prs_res_set_id); - } - j.write_int("pRSResourceID", prs_res_id); - j.write_int("relativePower", relative_pwr); - if (relative_pwr_fine_present) { - j.write_int("relativePowerFine", relative_pwr_fine); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// LocationUncertainty ::= SEQUENCE -SRSASN_CODE location_uncertainty_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, horizontal_uncertainty, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, horizontal_confidence, (uint8_t)0u, (uint8_t)100u, false, true)); - HANDLE_CODE(pack_integer(bref, vertical_uncertainty, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, vertical_confidence, (uint8_t)0u, (uint8_t)100u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE location_uncertainty_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(horizontal_uncertainty, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(horizontal_confidence, bref, (uint8_t)0u, (uint8_t)100u, false, true)); - HANDLE_CODE(unpack_integer(vertical_uncertainty, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(vertical_confidence, bref, (uint8_t)0u, (uint8_t)100u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void location_uncertainty_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("horizontalUncertainty", horizontal_uncertainty); - j.write_int("horizontalConfidence", horizontal_confidence); - j.write_int("verticalUncertainty", vertical_uncertainty); - j.write_int("verticalConfidence", vertical_confidence); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// RxTxTimingErrorMargin ::= ENUMERATED -const char* rx_tx_timing_error_margin_opts::to_string() const -{ - static const char* names[] = {"tc0dot5", - "tc1", - "tc2", - "tc4", - "tc8", - "tc12", - "tc16", - "tc20", - "tc24", - "tc32", - "tc40", - "tc48", - "tc64", - "tc80", - "tc96", - "tc128"}; - return convert_enum_idx(names, 16, value, "rx_tx_timing_error_margin_e"); -} -float rx_tx_timing_error_margin_opts::to_number() const -{ - static const float numbers[] = { - 0.5, 1.0, 2.0, 4.0, 8.0, 12.0, 16.0, 20.0, 24.0, 32.0, 40.0, 48.0, 64.0, 80.0, 96.0, 128.0}; - return map_enum_number(numbers, 16, value, "rx_tx_timing_error_margin_e"); -} -const char* rx_tx_timing_error_margin_opts::to_number_string() const -{ - static const char* number_strs[] = { - "0.5", "1", "2", "4", "8", "12", "16", "20", "24", "32", "40", "48", "64", "80", "96", "128"}; - return convert_enum_idx(number_strs, 16, value, "rx_tx_timing_error_margin_e"); -} - -// TimingErrorMargin ::= ENUMERATED -const char* timing_error_margin_opts::to_string() const -{ - static const char* names[] = {"tc0", - "tc2", - "tc4", - "tc6", - "tc8", - "tc12", - "tc16", - "tc20", - "tc24", - "tc32", - "tc40", - "tc48", - "tc56", - "tc64", - "tc72", - "tc80"}; - return convert_enum_idx(names, 16, value, "timing_error_margin_e"); -} -uint8_t timing_error_margin_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 56, 64, 72, 80}; - return map_enum_number(numbers, 16, value, "timing_error_margin_e"); -} - -// TRP-ElevationAngleList-Item ::= SEQUENCE -SRSASN_CODE trp_elevation_angle_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(trp_elevation_angle_fine_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_elevation_angle, (uint8_t)0u, (uint8_t)180u, false, true)); - if (trp_elevation_angle_fine_present) { - HANDLE_CODE(pack_integer(bref, trp_elevation_angle_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(pack_dyn_seq_of(bref, trp_beam_pwr_list, 2, 24, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_elevation_angle_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(trp_elevation_angle_fine_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_elevation_angle, bref, (uint8_t)0u, (uint8_t)180u, false, true)); - if (trp_elevation_angle_fine_present) { - HANDLE_CODE(unpack_integer(trp_elevation_angle_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(unpack_dyn_seq_of(trp_beam_pwr_list, bref, 2, 24, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_elevation_angle_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("trp-elevation-angle", trp_elevation_angle); - if (trp_elevation_angle_fine_present) { - j.write_int("trp-elevation-angle-fine", trp_elevation_angle_fine); - } - j.start_array("trp-beam-power-list"); - for (const auto& e1 : trp_beam_pwr_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TrpMeasurementAngleQuality ::= SEQUENCE -SRSASN_CODE trp_meas_angle_quality_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(zenith_quality_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, azimuth_quality, (uint16_t)0u, (uint16_t)255u, false, true)); - if (zenith_quality_present) { - HANDLE_CODE(pack_integer(bref, zenith_quality, (uint16_t)0u, (uint16_t)255u, false, true)); - } - HANDLE_CODE(resolution.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_angle_quality_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(zenith_quality_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(azimuth_quality, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - if (zenith_quality_present) { - HANDLE_CODE(unpack_integer(zenith_quality, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - } - HANDLE_CODE(resolution.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_angle_quality_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("azimuthQuality", azimuth_quality); - if (zenith_quality_present) { - j.write_int("zenithQuality", zenith_quality); - } - j.write_str("resolution", "deg0dot1"); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* trp_meas_angle_quality_s::resolution_opts::to_string() const -{ - static const char* names[] = {"deg0dot1"}; - return convert_enum_idx(names, 1, value, "trp_meas_angle_quality_s::resolution_e_"); -} -float trp_meas_angle_quality_s::resolution_opts::to_number() const -{ - static const float numbers[] = {0.1}; - return map_enum_number(numbers, 1, value, "trp_meas_angle_quality_s::resolution_e_"); -} -const char* trp_meas_angle_quality_s::resolution_opts::to_number_string() const -{ - static const char* number_strs[] = {"0.1"}; - return convert_enum_idx(number_strs, 1, value, "trp_meas_angle_quality_s::resolution_e_"); -} - -// TrpMeasurementTimingQuality ::= SEQUENCE -SRSASN_CODE trp_meas_timing_quality_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, meas_quality, (uint8_t)0u, (uint8_t)31u, false, true)); - HANDLE_CODE(resolution.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_timing_quality_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(meas_quality, bref, (uint8_t)0u, (uint8_t)31u, false, true)); - HANDLE_CODE(resolution.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_timing_quality_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("measurementQuality", meas_quality); - j.write_str("resolution", resolution.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* trp_meas_timing_quality_s::resolution_opts::to_string() const -{ - static const char* names[] = {"m0dot1", "m1", "m10", "m30"}; - return convert_enum_idx(names, 4, value, "trp_meas_timing_quality_s::resolution_e_"); -} -float trp_meas_timing_quality_s::resolution_opts::to_number() const -{ - static const float numbers[] = {0.1, 1.0, 10.0, 30.0}; - return map_enum_number(numbers, 4, value, "trp_meas_timing_quality_s::resolution_e_"); -} -const char* trp_meas_timing_quality_s::resolution_opts::to_number_string() const -{ - static const char* number_strs[] = {"0.1", "1", "10", "30"}; - return convert_enum_idx(number_strs, 4, value, "trp_meas_timing_quality_s::resolution_e_"); -} - -// MultipleULAoA ::= SEQUENCE -SRSASN_CODE multiple_ul_ao_a_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, multiple_ul_ao_a, 1, 8, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE multiple_ul_ao_a_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(multiple_ul_ao_a, bref, 1, 8, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void multiple_ul_ao_a_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("multipleULAoA"); - for (const auto& e1 : multiple_ul_ao_a) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSResource-QCLSourcePRS ::= SEQUENCE -SRSASN_CODE prs_res_qcl_source_prs_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(qcl_source_prs_res_id_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, qcl_source_prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - if (qcl_source_prs_res_id_present) { - HANDLE_CODE(pack_integer(bref, qcl_source_prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_res_qcl_source_prs_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(qcl_source_prs_res_id_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(qcl_source_prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - if (qcl_source_prs_res_id_present) { - HANDLE_CODE(unpack_integer(qcl_source_prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_res_qcl_source_prs_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("qCLSourcePRSResourceSetID", qcl_source_prs_res_set_id); - if (qcl_source_prs_res_id_present) { - j.write_int("qCLSourcePRSResourceID", qcl_source_prs_res_id); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSResource-QCLSourceSSB ::= SEQUENCE -SRSASN_CODE prs_res_qcl_source_ssb_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ssb_idx_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, pci_nr, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (ssb_idx_present) { - HANDLE_CODE(pack_integer(bref, ssb_idx, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_res_qcl_source_ssb_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ssb_idx_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(pci_nr, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (ssb_idx_present) { - HANDLE_CODE(unpack_integer(ssb_idx, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_res_qcl_source_ssb_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pCI-NR", pci_nr); - if (ssb_idx_present) { - j.write_int("sSB-Index", ssb_idx); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// RelativeCartesianLocation ::= SEQUENCE -SRSASN_CODE relative_cartesian_location_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(xy_zunit.pack(bref)); - HANDLE_CODE(pack_integer(bref, xvalue, (int32_t)-65536, (int32_t)65535, false, true)); - HANDLE_CODE(pack_integer(bref, yvalue, (int32_t)-65536, (int32_t)65535, false, true)); - HANDLE_CODE(pack_integer(bref, zvalue, (int32_t)-32768, (int32_t)32767, false, true)); - HANDLE_CODE(location_uncertainty.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE relative_cartesian_location_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(xy_zunit.unpack(bref)); - HANDLE_CODE(unpack_integer(xvalue, bref, (int32_t)-65536, (int32_t)65535, false, true)); - HANDLE_CODE(unpack_integer(yvalue, bref, (int32_t)-65536, (int32_t)65535, false, true)); - HANDLE_CODE(unpack_integer(zvalue, bref, (int32_t)-32768, (int32_t)32767, false, true)); - HANDLE_CODE(location_uncertainty.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void relative_cartesian_location_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("xYZunit", xy_zunit.to_string()); - j.write_int("xvalue", xvalue); - j.write_int("yvalue", yvalue); - j.write_int("zvalue", zvalue); - j.write_fieldname("locationUncertainty"); - location_uncertainty.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* relative_cartesian_location_s::xy_zunit_opts::to_string() const -{ - static const char* names[] = {"mm", "cm", "dm"}; - return convert_enum_idx(names, 3, value, "relative_cartesian_location_s::xy_zunit_e_"); -} - -// RelativeGeodeticLocation ::= SEQUENCE -SRSASN_CODE relative_geodetic_location_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(milli_arc_second_units.pack(bref)); - HANDLE_CODE(height_units.pack(bref)); - HANDLE_CODE(pack_integer(bref, delta_latitude, (int16_t)-1024, (int16_t)1023, false, true)); - HANDLE_CODE(pack_integer(bref, delta_longitude, (int16_t)-1024, (int16_t)1023, false, true)); - HANDLE_CODE(pack_integer(bref, delta_height, (int16_t)-1024, (int16_t)1023, false, true)); - HANDLE_CODE(location_uncertainty.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE relative_geodetic_location_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(milli_arc_second_units.unpack(bref)); - HANDLE_CODE(height_units.unpack(bref)); - HANDLE_CODE(unpack_integer(delta_latitude, bref, (int16_t)-1024, (int16_t)1023, false, true)); - HANDLE_CODE(unpack_integer(delta_longitude, bref, (int16_t)-1024, (int16_t)1023, false, true)); - HANDLE_CODE(unpack_integer(delta_height, bref, (int16_t)-1024, (int16_t)1023, false, true)); - HANDLE_CODE(location_uncertainty.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void relative_geodetic_location_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("milli-Arc-SecondUnits", milli_arc_second_units.to_string()); - j.write_str("heightUnits", height_units.to_string()); - j.write_int("deltaLatitude", delta_latitude); - j.write_int("deltaLongitude", delta_longitude); - j.write_int("deltaHeight", delta_height); - j.write_fieldname("locationUncertainty"); - location_uncertainty.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* relative_geodetic_location_s::milli_arc_second_units_opts::to_string() const -{ - static const char* names[] = {"zerodot03", "zerodot3", "three"}; - return convert_enum_idx(names, 3, value, "relative_geodetic_location_s::milli_arc_second_units_e_"); -} - -const char* relative_geodetic_location_s::height_units_opts::to_string() const -{ - static const char* names[] = {"mm", "cm", "m"}; - return convert_enum_idx(names, 3, value, "relative_geodetic_location_s::height_units_e_"); -} - -// RelativePathDelay ::= CHOICE -void relative_path_delay_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void relative_path_delay_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::k0: - break; - case types::k1: - break; - case types::k2: - break; - case types::k3: - break; - case types::k4: - break; - case types::k5: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "relative_path_delay_c"); - } -} -relative_path_delay_c::relative_path_delay_c(const relative_path_delay_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::k0: - c.init(other.c.get()); - break; - case types::k1: - c.init(other.c.get()); - break; - case types::k2: - c.init(other.c.get()); - break; - case types::k3: - c.init(other.c.get()); - break; - case types::k4: - c.init(other.c.get()); - break; - case types::k5: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "relative_path_delay_c"); - } -} -relative_path_delay_c& relative_path_delay_c::operator=(const relative_path_delay_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::k0: - c.set(other.c.get()); - break; - case types::k1: - c.set(other.c.get()); - break; - case types::k2: - c.set(other.c.get()); - break; - case types::k3: - c.set(other.c.get()); - break; - case types::k4: - c.set(other.c.get()); - break; - case types::k5: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "relative_path_delay_c"); - } - - return *this; -} -uint16_t& relative_path_delay_c::set_k0() -{ - set(types::k0); - return c.get(); -} -uint16_t& relative_path_delay_c::set_k1() -{ - set(types::k1); - return c.get(); -} -uint16_t& relative_path_delay_c::set_k2() -{ - set(types::k2); - return c.get(); -} -uint16_t& relative_path_delay_c::set_k3() -{ - set(types::k3); - return c.get(); -} -uint16_t& relative_path_delay_c::set_k4() -{ - set(types::k4); - return c.get(); -} -uint16_t& relative_path_delay_c::set_k5() -{ - set(types::k5); - return c.get(); -} -protocol_ie_single_container_s& relative_path_delay_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void relative_path_delay_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::k0: - j.write_int("k0", c.get()); - break; - case types::k1: - j.write_int("k1", c.get()); - break; - case types::k2: - j.write_int("k2", c.get()); - break; - case types::k3: - j.write_int("k3", c.get()); - break; - case types::k4: - j.write_int("k4", c.get()); - break; - case types::k5: - j.write_int("k5", c.get()); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "relative_path_delay_c"); - } - j.end_obj(); -} -SRSASN_CODE relative_path_delay_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::k0: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)16351u, false, true)); - break; - case types::k1: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)8176u, false, true)); - break; - case types::k2: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)4088u, false, true)); - break; - case types::k3: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)2044u, false, true)); - break; - case types::k4: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)1022u, false, true)); - break; - case types::k5: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)511u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "relative_path_delay_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE relative_path_delay_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::k0: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)16351u, false, true)); - break; - case types::k1: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)8176u, false, true)); - break; - case types::k2: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)4088u, false, true)); - break; - case types::k3: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)2044u, false, true)); - break; - case types::k4: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)1022u, false, true)); - break; - case types::k5: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)511u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "relative_path_delay_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* relative_path_delay_c::types_opts::to_string() const -{ - static const char* names[] = {"k0", "k1", "k2", "k3", "k4", "k5", "choice-Extension"}; - return convert_enum_idx(names, 7, value, "relative_path_delay_c::types"); -} -uint8_t relative_path_delay_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 1, 2, 3, 4, 5}; - return map_enum_number(numbers, 6, value, "relative_path_delay_c::types"); -} - -// TRP-BeamAntennaAnglesList-Item ::= SEQUENCE -SRSASN_CODE trp_beam_ant_angles_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(trp_azimuth_angle_fine_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_azimuth_angle, (uint16_t)0u, (uint16_t)359u, false, true)); - if (trp_azimuth_angle_fine_present) { - HANDLE_CODE(pack_integer(bref, trp_azimuth_angle_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(pack_dyn_seq_of(bref, trp_elevation_angle_list, 1, 1801, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_beam_ant_angles_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(trp_azimuth_angle_fine_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_azimuth_angle, bref, (uint16_t)0u, (uint16_t)359u, false, true)); - if (trp_azimuth_angle_fine_present) { - HANDLE_CODE(unpack_integer(trp_azimuth_angle_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(unpack_dyn_seq_of(trp_elevation_angle_list, bref, 1, 1801, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_beam_ant_angles_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("trp-azimuth-angle", trp_azimuth_angle); - if (trp_azimuth_angle_fine_present) { - j.write_int("trp-azimuth-angle-fine", trp_azimuth_angle_fine); - } - j.start_array("trp-elevation-angle-list"); - for (const auto& e1 : trp_elevation_angle_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TrpMeasurementQuality ::= CHOICE -void trp_meas_quality_c::destroy_() -{ - switch (type_) { - case types::timing_meas_quality: - c.destroy(); - break; - case types::angle_meas_quality: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trp_meas_quality_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::timing_meas_quality: - c.init(); - break; - case types::angle_meas_quality: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_meas_quality_c"); - } -} -trp_meas_quality_c::trp_meas_quality_c(const trp_meas_quality_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::timing_meas_quality: - c.init(other.c.get()); - break; - case types::angle_meas_quality: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_meas_quality_c"); - } -} -trp_meas_quality_c& trp_meas_quality_c::operator=(const trp_meas_quality_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::timing_meas_quality: - c.set(other.c.get()); - break; - case types::angle_meas_quality: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_meas_quality_c"); - } - - return *this; -} -trp_meas_timing_quality_s& trp_meas_quality_c::set_timing_meas_quality() -{ - set(types::timing_meas_quality); - return c.get(); -} -trp_meas_angle_quality_s& trp_meas_quality_c::set_angle_meas_quality() -{ - set(types::angle_meas_quality); - return c.get(); -} -protocol_ie_single_container_s& trp_meas_quality_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trp_meas_quality_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::timing_meas_quality: - j.write_fieldname("timingMeasQuality"); - c.get().to_json(j); - break; - case types::angle_meas_quality: - j.write_fieldname("angleMeasQuality"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_meas_quality_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_meas_quality_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::timing_meas_quality: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::angle_meas_quality: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_quality_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_quality_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::timing_meas_quality: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::angle_meas_quality: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_quality_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_meas_quality_c::types_opts::to_string() const -{ - static const char* names[] = {"timingMeasQuality", "angleMeasQuality", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "trp_meas_quality_c::types"); -} - -// TRP-Rx-TEGInformation ::= SEQUENCE -SRSASN_CODE trp_rx_teg_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_rx_teg_id, (uint8_t)0u, (uint8_t)31u, false, true)); - HANDLE_CODE(trp_rx_timing_error_margin.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_rx_teg_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_rx_teg_id, bref, (uint8_t)0u, (uint8_t)31u, false, true)); - HANDLE_CODE(trp_rx_timing_error_margin.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_rx_teg_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-Rx-TEGID", trp_rx_teg_id); - j.write_str("tRP-Rx-TimingErrorMargin", trp_rx_timing_error_margin.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRP-RxTx-TEGInformation ::= SEQUENCE -SRSASN_CODE trp_rx_tx_teg_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_rx_tx_teg_id, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(trp_rx_tx_timing_error_margin.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_rx_tx_teg_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_rx_tx_teg_id, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(trp_rx_tx_timing_error_margin.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_rx_tx_teg_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-RxTx-TEGID", trp_rx_tx_teg_id); - j.write_str("tRP-RxTx-TimingErrorMargin", trp_rx_tx_timing_error_margin.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRP-Tx-TEGInformation ::= SEQUENCE -SRSASN_CODE trp_tx_teg_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_tx_teg_id, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(trp_tx_timing_error_margin.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_tx_teg_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_tx_teg_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(trp_tx_timing_error_margin.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_tx_teg_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-Tx-TEGID", trp_tx_teg_id); - j.write_str("tRP-Tx-TimingErrorMargin", trp_tx_timing_error_margin.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// UL-SRS-RSRPP ::= SEQUENCE -SRSASN_CODE ul_srs_rsrp_p_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, first_path_rsrp_p, (uint8_t)0u, (uint8_t)126u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ul_srs_rsrp_p_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(first_path_rsrp_p, bref, (uint8_t)0u, (uint8_t)126u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ul_srs_rsrp_p_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("firstPathRSRPP", first_path_rsrp_p); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// AdditionalPathListItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t add_path_list_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {74, 96}; - return map_enum_number(names, 2, idx, "id"); -} -bool add_path_list_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {74, 96}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e add_path_list_item_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 74: - return crit_e::ignore; - case 96: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -add_path_list_item_ext_ies_o::ext_c add_path_list_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 74: - ret.set(ext_c::types::multiple_ul_ao_a); - break; - case 96: - ret.set(ext_c::types::path_pwr); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e add_path_list_item_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 74: - return presence_e::optional; - case 96: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void add_path_list_item_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::multiple_ul_ao_a: - c = multiple_ul_ao_a_s{}; - break; - case types::path_pwr: - c = ul_srs_rsrp_p_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "add_path_list_item_ext_ies_o::ext_c"); - } -} -multiple_ul_ao_a_s& add_path_list_item_ext_ies_o::ext_c::multiple_ul_ao_a() -{ - assert_choice_type(types::multiple_ul_ao_a, type_, "Extension"); - return c.get(); -} -ul_srs_rsrp_p_s& add_path_list_item_ext_ies_o::ext_c::path_pwr() -{ - assert_choice_type(types::path_pwr, type_, "Extension"); - return c.get(); -} -const multiple_ul_ao_a_s& add_path_list_item_ext_ies_o::ext_c::multiple_ul_ao_a() const -{ - assert_choice_type(types::multiple_ul_ao_a, type_, "Extension"); - return c.get(); -} -const ul_srs_rsrp_p_s& add_path_list_item_ext_ies_o::ext_c::path_pwr() const -{ - assert_choice_type(types::path_pwr, type_, "Extension"); - return c.get(); -} -void add_path_list_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::multiple_ul_ao_a: - j.write_fieldname("MultipleULAoA"); - c.get().to_json(j); - break; - case types::path_pwr: - j.write_fieldname("UL-SRS-RSRPP"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "add_path_list_item_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE add_path_list_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::multiple_ul_ao_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::path_pwr: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "add_path_list_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE add_path_list_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::multiple_ul_ao_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::path_pwr: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "add_path_list_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* add_path_list_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"MultipleULAoA", "UL-SRS-RSRPP"}; - return convert_enum_idx(names, 2, value, "add_path_list_item_ext_ies_o::ext_c::types"); -} - -// ARPLocationType ::= CHOICE -void arp_location_type_c::destroy_() -{ - switch (type_) { - case types::arp_position_relative_geodetic: - c.destroy(); - break; - case types::arp_position_relative_cartesian: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void arp_location_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::arp_position_relative_geodetic: - c.init(); - break; - case types::arp_position_relative_cartesian: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "arp_location_type_c"); - } -} -arp_location_type_c::arp_location_type_c(const arp_location_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::arp_position_relative_geodetic: - c.init(other.c.get()); - break; - case types::arp_position_relative_cartesian: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "arp_location_type_c"); - } -} -arp_location_type_c& arp_location_type_c::operator=(const arp_location_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::arp_position_relative_geodetic: - c.set(other.c.get()); - break; - case types::arp_position_relative_cartesian: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "arp_location_type_c"); - } - - return *this; -} -relative_geodetic_location_s& arp_location_type_c::set_arp_position_relative_geodetic() -{ - set(types::arp_position_relative_geodetic); - return c.get(); -} -relative_cartesian_location_s& arp_location_type_c::set_arp_position_relative_cartesian() -{ - set(types::arp_position_relative_cartesian); - return c.get(); -} -protocol_ie_single_container_s& arp_location_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void arp_location_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::arp_position_relative_geodetic: - j.write_fieldname("aRPPositionRelativeGeodetic"); - c.get().to_json(j); - break; - case types::arp_position_relative_cartesian: - j.write_fieldname("aRPPositionRelativeCartesian"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "arp_location_type_c"); - } - j.end_obj(); -} -SRSASN_CODE arp_location_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::arp_position_relative_geodetic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::arp_position_relative_cartesian: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "arp_location_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE arp_location_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::arp_position_relative_geodetic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::arp_position_relative_cartesian: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "arp_location_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* arp_location_type_c::types_opts::to_string() const -{ - static const char* names[] = {"aRPPositionRelativeGeodetic", "aRPPositionRelativeCartesian", "choice-extension"}; - return convert_enum_idx(names, 3, value, "arp_location_type_c::types"); -} - -// DL-PRSMutingPattern ::= CHOICE -void dl_prs_muting_pattern_c::destroy_() -{ - switch (type_) { - case types::two: - c.destroy>(); - break; - case types::four: - c.destroy>(); - break; - case types::six: - c.destroy>(); - break; - case types::eight: - c.destroy>(); - break; - case types::sixteen: - c.destroy>(); - break; - case types::thirty_two: - c.destroy>(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void dl_prs_muting_pattern_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::two: - c.init>(); - break; - case types::four: - c.init>(); - break; - case types::six: - c.init>(); - break; - case types::eight: - c.init>(); - break; - case types::sixteen: - c.init>(); - break; - case types::thirty_two: - c.init>(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_muting_pattern_c"); - } -} -dl_prs_muting_pattern_c::dl_prs_muting_pattern_c(const dl_prs_muting_pattern_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::two: - c.init(other.c.get>()); - break; - case types::four: - c.init(other.c.get>()); - break; - case types::six: - c.init(other.c.get>()); - break; - case types::eight: - c.init(other.c.get>()); - break; - case types::sixteen: - c.init(other.c.get>()); - break; - case types::thirty_two: - c.init(other.c.get>()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_muting_pattern_c"); - } -} -dl_prs_muting_pattern_c& dl_prs_muting_pattern_c::operator=(const dl_prs_muting_pattern_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::two: - c.set(other.c.get>()); - break; - case types::four: - c.set(other.c.get>()); - break; - case types::six: - c.set(other.c.get>()); - break; - case types::eight: - c.set(other.c.get>()); - break; - case types::sixteen: - c.set(other.c.get>()); - break; - case types::thirty_two: - c.set(other.c.get>()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_muting_pattern_c"); - } - - return *this; -} -fixed_bitstring<2, false, true>& dl_prs_muting_pattern_c::set_two() -{ - set(types::two); - return c.get>(); -} -fixed_bitstring<4, false, true>& dl_prs_muting_pattern_c::set_four() -{ - set(types::four); - return c.get>(); -} -fixed_bitstring<6, false, true>& dl_prs_muting_pattern_c::set_six() -{ - set(types::six); - return c.get>(); -} -fixed_bitstring<8, false, true>& dl_prs_muting_pattern_c::set_eight() -{ - set(types::eight); - return c.get>(); -} -fixed_bitstring<16, false, true>& dl_prs_muting_pattern_c::set_sixteen() -{ - set(types::sixteen); - return c.get>(); -} -fixed_bitstring<32, false, true>& dl_prs_muting_pattern_c::set_thirty_two() -{ - set(types::thirty_two); - return c.get>(); -} -protocol_ie_single_container_s& dl_prs_muting_pattern_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void dl_prs_muting_pattern_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::two: - j.write_str("two", c.get>().to_string()); - break; - case types::four: - j.write_str("four", c.get>().to_string()); - break; - case types::six: - j.write_str("six", c.get>().to_string()); - break; - case types::eight: - j.write_str("eight", c.get>().to_string()); - break; - case types::sixteen: - j.write_str("sixteen", c.get>().to_string()); - break; - case types::thirty_two: - j.write_str("thirty-two", c.get>().to_string()); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "dl_prs_muting_pattern_c"); - } - j.end_obj(); -} -SRSASN_CODE dl_prs_muting_pattern_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::two: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::four: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::six: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::eight: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::sixteen: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::thirty_two: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "dl_prs_muting_pattern_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_muting_pattern_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::two: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::four: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::six: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::eight: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::sixteen: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::thirty_two: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "dl_prs_muting_pattern_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* dl_prs_muting_pattern_c::types_opts::to_string() const -{ - static const char* names[] = {"two", "four", "six", "eight", "sixteen", "thirty-two", "choice-extension"}; - return convert_enum_idx(names, 7, value, "dl_prs_muting_pattern_c::types"); -} - -// ExtendedAdditionalPathList-Item ::= SEQUENCE -SRSASN_CODE extended_add_path_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(path_quality_present, 1)); - HANDLE_CODE(bref.pack(multiple_ul_ao_a_present, 1)); - HANDLE_CODE(bref.pack(path_pwr_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(relative_time_of_path.pack(bref)); - if (path_quality_present) { - HANDLE_CODE(path_quality.pack(bref)); - } - if (multiple_ul_ao_a_present) { - HANDLE_CODE(multiple_ul_ao_a.pack(bref)); - } - if (path_pwr_present) { - HANDLE_CODE(path_pwr.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE extended_add_path_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(path_quality_present, 1)); - HANDLE_CODE(bref.unpack(multiple_ul_ao_a_present, 1)); - HANDLE_CODE(bref.unpack(path_pwr_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(relative_time_of_path.unpack(bref)); - if (path_quality_present) { - HANDLE_CODE(path_quality.unpack(bref)); - } - if (multiple_ul_ao_a_present) { - HANDLE_CODE(multiple_ul_ao_a.unpack(bref)); - } - if (path_pwr_present) { - HANDLE_CODE(path_pwr.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void extended_add_path_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("relativeTimeOfPath"); - relative_time_of_path.to_json(j); - if (path_quality_present) { - j.write_fieldname("pathQuality"); - path_quality.to_json(j); - } - if (multiple_ul_ao_a_present) { - j.write_fieldname("multipleULAoA"); - multiple_ul_ao_a.to_json(j); - } - if (path_pwr_present) { - j.write_fieldname("pathPower"); - path_pwr.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSAngleItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t prs_angle_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {65}; - return map_enum_number(names, 1, idx, "id"); -} -bool prs_angle_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 65 == id; -} -crit_e prs_angle_item_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 65) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -prs_angle_item_ext_ies_o::ext_c prs_angle_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 65) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e prs_angle_item_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 65) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void prs_angle_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("INTEGER (0..63)", c); - j.end_obj(); -} -SRSASN_CODE prs_angle_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, c, (uint8_t)0u, (uint8_t)63u, false, true)); - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_angle_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(c, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - return SRSASN_SUCCESS; -} - -const char* prs_angle_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (0..63)"}; - return convert_enum_idx(names, 1, value, "prs_angle_item_ext_ies_o::ext_c::types"); -} -uint8_t prs_angle_item_ext_ies_o::ext_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {0}; - return map_enum_number(numbers, 1, value, "prs_angle_item_ext_ies_o::ext_c::types"); -} - -// PRSResource-QCLInfo ::= CHOICE -void prs_res_qcl_info_c::destroy_() -{ - switch (type_) { - case types::qcl_source_ssb: - c.destroy(); - break; - case types::qcl_source_prs: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void prs_res_qcl_info_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::qcl_source_ssb: - c.init(); - break; - case types::qcl_source_prs: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_res_qcl_info_c"); - } -} -prs_res_qcl_info_c::prs_res_qcl_info_c(const prs_res_qcl_info_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::qcl_source_ssb: - c.init(other.c.get()); - break; - case types::qcl_source_prs: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_res_qcl_info_c"); - } -} -prs_res_qcl_info_c& prs_res_qcl_info_c::operator=(const prs_res_qcl_info_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::qcl_source_ssb: - c.set(other.c.get()); - break; - case types::qcl_source_prs: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_res_qcl_info_c"); - } - - return *this; -} -prs_res_qcl_source_ssb_s& prs_res_qcl_info_c::set_qcl_source_ssb() -{ - set(types::qcl_source_ssb); - return c.get(); -} -prs_res_qcl_source_prs_s& prs_res_qcl_info_c::set_qcl_source_prs() -{ - set(types::qcl_source_prs); - return c.get(); -} -protocol_ie_single_container_s& prs_res_qcl_info_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void prs_res_qcl_info_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::qcl_source_ssb: - j.write_fieldname("qCLSourceSSB"); - c.get().to_json(j); - break; - case types::qcl_source_prs: - j.write_fieldname("qCLSourcePRS"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "prs_res_qcl_info_c"); - } - j.end_obj(); -} -SRSASN_CODE prs_res_qcl_info_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::qcl_source_ssb: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::qcl_source_prs: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_res_qcl_info_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_res_qcl_info_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::qcl_source_ssb: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::qcl_source_prs: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_res_qcl_info_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* prs_res_qcl_info_c::types_opts::to_string() const -{ - static const char* names[] = {"qCLSourceSSB", "qCLSourcePRS", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "prs_res_qcl_info_c::types"); -} - -// RxTEG ::= SEQUENCE -SRSASN_CODE rx_teg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(trp_rx_teg_info.pack(bref)); - HANDLE_CODE(trp_tx_teg_info.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE rx_teg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(trp_rx_teg_info.unpack(bref)); - HANDLE_CODE(trp_tx_teg_info.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void rx_teg_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("tRP-Rx-TEGInformation"); - trp_rx_teg_info.to_json(j); - j.write_fieldname("tRP-Tx-TEGInformation"); - trp_tx_teg_info.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// RxTxTEG ::= SEQUENCE -SRSASN_CODE rx_tx_teg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(trp_tx_teg_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(trp_rx_tx_teg_info.pack(bref)); - if (trp_tx_teg_info_present) { - HANDLE_CODE(trp_tx_teg_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE rx_tx_teg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(trp_tx_teg_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(trp_rx_tx_teg_info.unpack(bref)); - if (trp_tx_teg_info_present) { - HANDLE_CODE(trp_tx_teg_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void rx_tx_teg_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("tRP-RxTx-TEGInformation"); - trp_rx_tx_teg_info.to_json(j); - if (trp_tx_teg_info_present) { - j.write_fieldname("tRP-Tx-TEGInformation"); - trp_tx_teg_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSPortIndex ::= ENUMERATED -const char* srs_port_idx_opts::to_string() const -{ - static const char* names[] = {"id1000", "id1001", "id1002", "id1003"}; - return convert_enum_idx(names, 4, value, "srs_port_idx_e"); -} -uint16_t srs_port_idx_opts::to_number() const -{ - static const uint16_t numbers[] = {1000, 1001, 1002, 1003}; - return map_enum_number(numbers, 4, value, "srs_port_idx_e"); -} - -// ARPLocationInformation-Item ::= SEQUENCE -SRSASN_CODE arp_location_info_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, arp_id, (uint8_t)1u, (uint8_t)16u, true, true)); - HANDLE_CODE(arp_location_type.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE arp_location_info_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(arp_id, bref, (uint8_t)1u, (uint8_t)16u, true, true)); - HANDLE_CODE(arp_location_type.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void arp_location_info_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("aRP-ID", arp_id); - j.write_fieldname("aRPLocationType"); - arp_location_type.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// DL-PRSResourceARPLocation ::= CHOICE -void dl_prs_res_arp_location_c::destroy_() -{ - switch (type_) { - case types::relative_geodetic_location: - c.destroy(); - break; - case types::relative_cartesian_location: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void dl_prs_res_arp_location_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::relative_geodetic_location: - c.init(); - break; - case types::relative_cartesian_location: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_arp_location_c"); - } -} -dl_prs_res_arp_location_c::dl_prs_res_arp_location_c(const dl_prs_res_arp_location_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::relative_geodetic_location: - c.init(other.c.get()); - break; - case types::relative_cartesian_location: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_arp_location_c"); - } -} -dl_prs_res_arp_location_c& dl_prs_res_arp_location_c::operator=(const dl_prs_res_arp_location_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::relative_geodetic_location: - c.set(other.c.get()); - break; - case types::relative_cartesian_location: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_arp_location_c"); - } - - return *this; -} -relative_geodetic_location_s& dl_prs_res_arp_location_c::set_relative_geodetic_location() -{ - set(types::relative_geodetic_location); - return c.get(); -} -relative_cartesian_location_s& dl_prs_res_arp_location_c::set_relative_cartesian_location() -{ - set(types::relative_cartesian_location); - return c.get(); -} -protocol_ie_single_container_s& dl_prs_res_arp_location_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void dl_prs_res_arp_location_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::relative_geodetic_location: - j.write_fieldname("relativeGeodeticLocation"); - c.get().to_json(j); - break; - case types::relative_cartesian_location: - j.write_fieldname("relativeCartesianLocation"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_arp_location_c"); - } - j.end_obj(); -} -SRSASN_CODE dl_prs_res_arp_location_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::relative_geodetic_location: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::relative_cartesian_location: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_arp_location_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_res_arp_location_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::relative_geodetic_location: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::relative_cartesian_location: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_arp_location_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* dl_prs_res_arp_location_c::types_opts::to_string() const -{ - static const char* names[] = {"relativeGeodeticLocation", "relativeCartesianLocation", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "dl_prs_res_arp_location_c::types"); -} - -// DLPRSResourceID-Item ::= SEQUENCE -SRSASN_CODE dl_prs_res_id_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, dl_prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_res_id_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(dl_prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void dl_prs_res_id_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("dl-PRSResourceID", dl_prs_res_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// DL-PRS ::= SEQUENCE -SRSASN_CODE dl_prs_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(dl_prs_res_id_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prsid, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, dl_prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - if (dl_prs_res_id_present) { - HANDLE_CODE(pack_integer(bref, dl_prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(dl_prs_res_id_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prsid, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(dl_prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - if (dl_prs_res_id_present) { - HANDLE_CODE(unpack_integer(dl_prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void dl_prs_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("prsid", prsid); - j.write_int("dl-PRSResourceSetID", dl_prs_res_set_id); - if (dl_prs_res_id_present) { - j.write_int("dl-PRSResourceID", dl_prs_res_id); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// NG-RANAccessPointPosition ::= SEQUENCE -SRSASN_CODE ng_ran_access_point_position_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(latitude_sign.pack(bref)); - HANDLE_CODE(pack_integer(bref, latitude, (uint32_t)0u, (uint32_t)8388607u, false, true)); - HANDLE_CODE(pack_integer(bref, longitude, (int32_t)-8388608, (int32_t)8388607, false, true)); - HANDLE_CODE(direction_of_altitude.pack(bref)); - HANDLE_CODE(pack_integer(bref, altitude, (uint16_t)0u, (uint16_t)32767u, false, true)); - HANDLE_CODE(pack_integer(bref, uncertainty_semi_major, (uint8_t)0u, (uint8_t)127u, false, true)); - HANDLE_CODE(pack_integer(bref, uncertainty_semi_minor, (uint8_t)0u, (uint8_t)127u, false, true)); - HANDLE_CODE(pack_integer(bref, orientation_of_major_axis, (uint8_t)0u, (uint8_t)179u, false, true)); - HANDLE_CODE(pack_integer(bref, uncertainty_altitude, (uint8_t)0u, (uint8_t)127u, false, true)); - HANDLE_CODE(pack_integer(bref, confidence, (uint8_t)0u, (uint8_t)100u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ng_ran_access_point_position_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(latitude_sign.unpack(bref)); - HANDLE_CODE(unpack_integer(latitude, bref, (uint32_t)0u, (uint32_t)8388607u, false, true)); - HANDLE_CODE(unpack_integer(longitude, bref, (int32_t)-8388608, (int32_t)8388607, false, true)); - HANDLE_CODE(direction_of_altitude.unpack(bref)); - HANDLE_CODE(unpack_integer(altitude, bref, (uint16_t)0u, (uint16_t)32767u, false, true)); - HANDLE_CODE(unpack_integer(uncertainty_semi_major, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - HANDLE_CODE(unpack_integer(uncertainty_semi_minor, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - HANDLE_CODE(unpack_integer(orientation_of_major_axis, bref, (uint8_t)0u, (uint8_t)179u, false, true)); - HANDLE_CODE(unpack_integer(uncertainty_altitude, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - HANDLE_CODE(unpack_integer(confidence, bref, (uint8_t)0u, (uint8_t)100u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ng_ran_access_point_position_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("latitudeSign", latitude_sign.to_string()); - j.write_int("latitude", latitude); - j.write_int("longitude", longitude); - j.write_str("directionOfAltitude", direction_of_altitude.to_string()); - j.write_int("altitude", altitude); - j.write_int("uncertaintySemi-major", uncertainty_semi_major); - j.write_int("uncertaintySemi-minor", uncertainty_semi_minor); - j.write_int("orientationOfMajorAxis", orientation_of_major_axis); - j.write_int("uncertaintyAltitude", uncertainty_altitude); - j.write_int("confidence", confidence); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* ng_ran_access_point_position_s::latitude_sign_opts::to_string() const -{ - static const char* names[] = {"north", "south"}; - return convert_enum_idx(names, 2, value, "ng_ran_access_point_position_s::latitude_sign_e_"); -} - -const char* ng_ran_access_point_position_s::direction_of_altitude_opts::to_string() const -{ - static const char* names[] = {"height", "depth"}; - return convert_enum_idx(names, 2, value, "ng_ran_access_point_position_s::direction_of_altitude_e_"); -} -uint8_t ng_ran_access_point_position_s::direction_of_altitude_opts::to_number() const -{ - static const uint8_t numbers[] = {8}; - return map_enum_number(numbers, 1, value, "ng_ran_access_point_position_s::direction_of_altitude_e_"); -} - -// NGRANHighAccuracyAccessPointPosition ::= SEQUENCE -SRSASN_CODE ngran_high_accuracy_access_point_position_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, latitude, (int64_t)-2147483648, (int64_t)2147483647, false, true)); - HANDLE_CODE(pack_integer(bref, longitude, (int64_t)-2147483648, (int64_t)2147483647, false, true)); - HANDLE_CODE(pack_integer(bref, altitude, (int32_t)-64000, (int32_t)1280000, false, true)); - HANDLE_CODE(pack_integer(bref, uncertainty_semi_major, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, uncertainty_semi_minor, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, orientation_of_major_axis, (uint8_t)0u, (uint8_t)179u, false, true)); - HANDLE_CODE(pack_integer(bref, horizontal_confidence, (uint8_t)0u, (uint8_t)100u, false, true)); - HANDLE_CODE(pack_integer(bref, uncertainty_altitude, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, vertical_confidence, (uint8_t)0u, (uint8_t)100u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ngran_high_accuracy_access_point_position_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(latitude, bref, (int64_t)-2147483648, (int64_t)2147483647, false, true)); - HANDLE_CODE(unpack_integer(longitude, bref, (int64_t)-2147483648, (int64_t)2147483647, false, true)); - HANDLE_CODE(unpack_integer(altitude, bref, (int32_t)-64000, (int32_t)1280000, false, true)); - HANDLE_CODE(unpack_integer(uncertainty_semi_major, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(uncertainty_semi_minor, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(orientation_of_major_axis, bref, (uint8_t)0u, (uint8_t)179u, false, true)); - HANDLE_CODE(unpack_integer(horizontal_confidence, bref, (uint8_t)0u, (uint8_t)100u, false, true)); - HANDLE_CODE(unpack_integer(uncertainty_altitude, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(vertical_confidence, bref, (uint8_t)0u, (uint8_t)100u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ngran_high_accuracy_access_point_position_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("latitude", latitude); - j.write_int("longitude", longitude); - j.write_int("altitude", altitude); - j.write_int("uncertaintySemi-major", uncertainty_semi_major); - j.write_int("uncertaintySemi-minor", uncertainty_semi_minor); - j.write_int("orientationOfMajorAxis", orientation_of_major_axis); - j.write_int("horizontalConfidence", horizontal_confidence); - j.write_int("uncertaintyAltitude", uncertainty_altitude); - j.write_int("verticalConfidence", vertical_confidence); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PosSRSInfo ::= SEQUENCE -SRSASN_CODE pos_srs_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(pack_integer(bref, pos_srs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_srs_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(unpack_integer(pos_srs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - - return SRSASN_SUCCESS; -} -void pos_srs_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("posSRSResourceID", pos_srs_res_id); - j.end_obj(); -} - -template struct asn1::protocol_ext_field_s; - -// PRSMutingOption1 ::= SEQUENCE -SRSASN_CODE prs_muting_option1_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(muting_pattern.pack(bref)); - HANDLE_CODE(muting_bit_repeat_factor.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_muting_option1_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(muting_pattern.unpack(bref)); - HANDLE_CODE(muting_bit_repeat_factor.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_muting_option1_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("mutingPattern"); - muting_pattern.to_json(j); - j.write_str("mutingBitRepetitionFactor", muting_bit_repeat_factor.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* prs_muting_option1_s::muting_bit_repeat_factor_opts::to_string() const -{ - static const char* names[] = {"n1", "n2", "n4", "n8"}; - return convert_enum_idx(names, 4, value, "prs_muting_option1_s::muting_bit_repeat_factor_e_"); -} -uint8_t prs_muting_option1_s::muting_bit_repeat_factor_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4, 8}; - return map_enum_number(numbers, 4, value, "prs_muting_option1_s::muting_bit_repeat_factor_e_"); -} - -// PRSMutingOption2 ::= SEQUENCE -SRSASN_CODE prs_muting_option2_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(muting_pattern.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_muting_option2_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(muting_pattern.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_muting_option2_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("mutingPattern"); - muting_pattern.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSResource-Item ::= SEQUENCE -SRSASN_CODE prs_res_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(qcl_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(pack_integer(bref, seq_id, (uint16_t)0u, (uint16_t)4095u, false, true)); - HANDLE_CODE(pack_integer(bref, re_offset, (uint8_t)0u, (uint8_t)11u, true, true)); - HANDLE_CODE(pack_integer(bref, res_slot_offset, (uint16_t)0u, (uint16_t)511u, false, true)); - HANDLE_CODE(pack_integer(bref, res_symbol_offset, (uint8_t)0u, (uint8_t)12u, false, true)); - if (qcl_info_present) { - HANDLE_CODE(qcl_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_res_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(qcl_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(unpack_integer(seq_id, bref, (uint16_t)0u, (uint16_t)4095u, false, true)); - HANDLE_CODE(unpack_integer(re_offset, bref, (uint8_t)0u, (uint8_t)11u, true, true)); - HANDLE_CODE(unpack_integer(res_slot_offset, bref, (uint16_t)0u, (uint16_t)511u, false, true)); - HANDLE_CODE(unpack_integer(res_symbol_offset, bref, (uint8_t)0u, (uint8_t)12u, false, true)); - if (qcl_info_present) { - HANDLE_CODE(qcl_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_res_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRSResourceID", prs_res_id); - j.write_int("sequenceID", seq_id); - j.write_int("rEOffset", re_offset); - j.write_int("resourceSlotOffset", res_slot_offset); - j.write_int("resourceSymbolOffset", res_symbol_offset); - if (qcl_info_present) { - j.write_fieldname("qCLInfo"); - qcl_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSInfo ::= SEQUENCE -SRSASN_CODE srs_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(pack_integer(bref, srs_res, (uint8_t)0u, (uint8_t)63u, false, true)); - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(unpack_integer(srs_res, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - - return SRSASN_SUCCESS; -} -void srs_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResource", srs_res); - j.end_obj(); -} - -// SRSResourcetype-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t srs_restype_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {100}; - return map_enum_number(names, 1, idx, "id"); -} -bool srs_restype_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 100 == id; -} -crit_e srs_restype_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 100) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -srs_restype_ext_ies_o::ext_c srs_restype_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 100) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e srs_restype_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 100) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void srs_restype_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("SRSPortIndex", c.to_string()); - j.end_obj(); -} -SRSASN_CODE srs_restype_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_restype_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* srs_restype_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"SRSPortIndex"}; - return convert_enum_idx(names, 1, value, "srs_restype_ext_ies_o::ext_c::types"); -} - -// SSB ::= SEQUENCE -SRSASN_CODE ssb_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ssb_idx_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, pci_nr, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (ssb_idx_present) { - HANDLE_CODE(pack_integer(bref, ssb_idx, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ssb_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ssb_idx_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(pci_nr, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (ssb_idx_present) { - HANDLE_CODE(unpack_integer(ssb_idx, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ssb_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pCI-NR", pci_nr); - if (ssb_idx_present) { - j.write_int("ssb-index", ssb_idx); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRP-BeamAntennaExplicitInformation ::= SEQUENCE -SRSASN_CODE trp_beam_ant_explicit_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, trp_beam_ant_angles, 1, 3600, true)); - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_beam_ant_explicit_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(trp_beam_ant_angles, bref, 1, 3600, true)); - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_beam_ant_explicit_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("trp-BeamAntennaAngles"); - for (const auto& e1 : trp_beam_ant_angles) { - e1.to_json(j); - } - j.end_array(); - if (lcs_to_gcs_translation_present) { - j.write_fieldname("lcs-to-gcs-translation"); - lcs_to_gcs_translation.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPTEGInformation ::= CHOICE -void trpteg_info_c::destroy_() -{ - switch (type_) { - case types::rx_tx_teg: - c.destroy(); - break; - case types::rx_teg: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trpteg_info_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::rx_tx_teg: - c.init(); - break; - case types::rx_teg: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trpteg_info_c"); - } -} -trpteg_info_c::trpteg_info_c(const trpteg_info_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::rx_tx_teg: - c.init(other.c.get()); - break; - case types::rx_teg: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trpteg_info_c"); - } -} -trpteg_info_c& trpteg_info_c::operator=(const trpteg_info_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::rx_tx_teg: - c.set(other.c.get()); - break; - case types::rx_teg: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trpteg_info_c"); - } - - return *this; -} -rx_tx_teg_s& trpteg_info_c::set_rx_tx_teg() -{ - set(types::rx_tx_teg); - return c.get(); -} -rx_teg_s& trpteg_info_c::set_rx_teg() -{ - set(types::rx_teg); - return c.get(); -} -protocol_ie_single_container_s& trpteg_info_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trpteg_info_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::rx_tx_teg: - j.write_fieldname("rxTx-TEG"); - c.get().to_json(j); - break; - case types::rx_teg: - j.write_fieldname("rx-TEG"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trpteg_info_c"); - } - j.end_obj(); -} -SRSASN_CODE trpteg_info_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::rx_tx_teg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::rx_teg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trpteg_info_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trpteg_info_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::rx_tx_teg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::rx_teg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trpteg_info_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trpteg_info_c::types_opts::to_string() const -{ - static const char* names[] = {"rxTx-TEG", "rx-TEG", "choice-extension"}; - return convert_enum_idx(names, 3, value, "trpteg_info_c::types"); -} - -SRSASN_CODE add_path_list_item_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += multiple_ul_ao_a_present ? 1 : 0; - nof_ies += path_pwr_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (multiple_ul_ao_a_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)74, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(multiple_ul_ao_a.pack(bref)); - } - if (path_pwr_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)96, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(path_pwr.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE add_path_list_item_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 74: { - multiple_ul_ao_a_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(multiple_ul_ao_a.unpack(bref)); - break; - } - case 96: { - path_pwr_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(path_pwr.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void add_path_list_item_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (multiple_ul_ao_a_present) { - j.write_int("id", 74); - j.write_str("criticality", "ignore"); - multiple_ul_ao_a.to_json(j); - } - if (path_pwr_present) { - j.write_int("id", 96); - j.write_str("criticality", "ignore"); - path_pwr.to_json(j); - } - j.end_obj(); -} - -// Choice-TRP-Beam-Antenna-Info-Item ::= CHOICE -void choice_trp_beam_ant_info_item_c::destroy_() -{ - switch (type_) { - case types::explicit_type: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void choice_trp_beam_ant_info_item_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::ref: - break; - case types::explicit_type: - c.init(); - break; - case types::no_change: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "choice_trp_beam_ant_info_item_c"); - } -} -choice_trp_beam_ant_info_item_c::choice_trp_beam_ant_info_item_c(const choice_trp_beam_ant_info_item_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::ref: - c.init(other.c.get()); - break; - case types::explicit_type: - c.init(other.c.get()); - break; - case types::no_change: - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "choice_trp_beam_ant_info_item_c"); - } -} -choice_trp_beam_ant_info_item_c& -choice_trp_beam_ant_info_item_c::operator=(const choice_trp_beam_ant_info_item_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::ref: - c.set(other.c.get()); - break; - case types::explicit_type: - c.set(other.c.get()); - break; - case types::no_change: - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "choice_trp_beam_ant_info_item_c"); - } - - return *this; -} -uint32_t& choice_trp_beam_ant_info_item_c::set_ref() -{ - set(types::ref); - return c.get(); -} -trp_beam_ant_explicit_info_s& choice_trp_beam_ant_info_item_c::set_explicit_type() -{ - set(types::explicit_type); - return c.get(); -} -void choice_trp_beam_ant_info_item_c::set_no_change() -{ - set(types::no_change); -} -protocol_ie_single_container_s& choice_trp_beam_ant_info_item_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void choice_trp_beam_ant_info_item_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::ref: - j.write_int("reference", c.get()); - break; - case types::explicit_type: - j.write_fieldname("explicit"); - c.get().to_json(j); - break; - case types::no_change: - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "choice_trp_beam_ant_info_item_c"); - } - j.end_obj(); -} -SRSASN_CODE choice_trp_beam_ant_info_item_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::ref: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65535u, true, true)); - break; - case types::explicit_type: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::no_change: - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "choice_trp_beam_ant_info_item_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE choice_trp_beam_ant_info_item_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::ref: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - break; - case types::explicit_type: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::no_change: - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "choice_trp_beam_ant_info_item_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* choice_trp_beam_ant_info_item_c::types_opts::to_string() const -{ - static const char* names[] = {"reference", "explicit", "noChange", "choice-extension"}; - return convert_enum_idx(names, 4, value, "choice_trp_beam_ant_info_item_c::types"); -} - -// DLPRSResourceARP ::= SEQUENCE -SRSASN_CODE dl_prs_res_arp_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, dl_prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(dl_prs_res_arp_location.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_res_arp_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(dl_prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(dl_prs_res_arp_location.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void dl_prs_res_arp_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("dl-PRSResourceID", dl_prs_res_id); - j.write_fieldname("dL-PRSResourceARPLocation"); - dl_prs_res_arp_location.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// DL-PRSResourceSetARPLocation ::= CHOICE -void dl_prs_res_set_arp_location_c::destroy_() -{ - switch (type_) { - case types::relative_geodetic_location: - c.destroy(); - break; - case types::relative_cartesian_location: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void dl_prs_res_set_arp_location_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::relative_geodetic_location: - c.init(); - break; - case types::relative_cartesian_location: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_set_arp_location_c"); - } -} -dl_prs_res_set_arp_location_c::dl_prs_res_set_arp_location_c(const dl_prs_res_set_arp_location_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::relative_geodetic_location: - c.init(other.c.get()); - break; - case types::relative_cartesian_location: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_set_arp_location_c"); - } -} -dl_prs_res_set_arp_location_c& dl_prs_res_set_arp_location_c::operator=(const dl_prs_res_set_arp_location_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::relative_geodetic_location: - c.set(other.c.get()); - break; - case types::relative_cartesian_location: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_set_arp_location_c"); - } - - return *this; -} -relative_geodetic_location_s& dl_prs_res_set_arp_location_c::set_relative_geodetic_location() -{ - set(types::relative_geodetic_location); - return c.get(); -} -relative_cartesian_location_s& dl_prs_res_set_arp_location_c::set_relative_cartesian_location() -{ - set(types::relative_cartesian_location); - return c.get(); -} -protocol_ie_single_container_s& dl_prs_res_set_arp_location_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void dl_prs_res_set_arp_location_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::relative_geodetic_location: - j.write_fieldname("relativeGeodeticLocation"); - c.get().to_json(j); - break; - case types::relative_cartesian_location: - j.write_fieldname("relativeCartesianLocation"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_set_arp_location_c"); - } - j.end_obj(); -} -SRSASN_CODE dl_prs_res_set_arp_location_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::relative_geodetic_location: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::relative_cartesian_location: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_set_arp_location_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_res_set_arp_location_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::relative_geodetic_location: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::relative_cartesian_location: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "dl_prs_res_set_arp_location_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* dl_prs_res_set_arp_location_c::types_opts::to_string() const -{ - static const char* names[] = {"relativeGeodeticLocation", "relativeCartesianLocation", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "dl_prs_res_set_arp_location_c::types"); -} - -// Expected-Azimuth-AoA ::= SEQUENCE -SRSASN_CODE expected_azimuth_ao_a_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, expected_azimuth_ao_a_value, (uint16_t)0u, (uint16_t)3599u, false, true)); - HANDLE_CODE(pack_integer(bref, expected_azimuth_ao_a_uncertainty, (uint16_t)0u, (uint16_t)3599u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE expected_azimuth_ao_a_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(expected_azimuth_ao_a_value, bref, (uint16_t)0u, (uint16_t)3599u, false, true)); - HANDLE_CODE(unpack_integer(expected_azimuth_ao_a_uncertainty, bref, (uint16_t)0u, (uint16_t)3599u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void expected_azimuth_ao_a_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("expected-Azimuth-AoA-value", expected_azimuth_ao_a_value); - j.write_int("expected-Azimuth-AoA-uncertainty", expected_azimuth_ao_a_uncertainty); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// Expected-Zenith-AoA ::= SEQUENCE -SRSASN_CODE expected_zenith_ao_a_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, expected_zenith_ao_a_value, (uint16_t)0u, (uint16_t)1799u, false, true)); - HANDLE_CODE(pack_integer(bref, expected_zenith_ao_a_uncertainty, (uint16_t)0u, (uint16_t)1799u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE expected_zenith_ao_a_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(expected_zenith_ao_a_value, bref, (uint16_t)0u, (uint16_t)1799u, false, true)); - HANDLE_CODE(unpack_integer(expected_zenith_ao_a_uncertainty, bref, (uint16_t)0u, (uint16_t)1799u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void expected_zenith_ao_a_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("expected-Zenith-AoA-value", expected_zenith_ao_a_value); - j.write_int("expected-Zenith-AoA-uncertainty", expected_zenith_ao_a_uncertainty); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// GNB-RxTxTimeDiff-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t gnb_rx_tx_time_diff_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {77, 85}; - return map_enum_number(names, 2, idx, "id"); -} -bool gnb_rx_tx_time_diff_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {77, 85}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e gnb_rx_tx_time_diff_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 77: - return crit_e::ignore; - case 85: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -gnb_rx_tx_time_diff_ext_ies_o::ext_c gnb_rx_tx_time_diff_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 77: - ret.set(ext_c::types::extended_add_path_list); - break; - case 85: - ret.set(ext_c::types::trpteg_info); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e gnb_rx_tx_time_diff_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 77: - return presence_e::optional; - case 85: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void gnb_rx_tx_time_diff_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::extended_add_path_list: - c = extended_add_path_list_l{}; - break; - case types::trpteg_info: - c = trpteg_info_c{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_ext_ies_o::ext_c"); - } -} -extended_add_path_list_l& gnb_rx_tx_time_diff_ext_ies_o::ext_c::extended_add_path_list() -{ - assert_choice_type(types::extended_add_path_list, type_, "Extension"); - return c.get(); -} -trpteg_info_c& gnb_rx_tx_time_diff_ext_ies_o::ext_c::trpteg_info() -{ - assert_choice_type(types::trpteg_info, type_, "Extension"); - return c.get(); -} -const extended_add_path_list_l& gnb_rx_tx_time_diff_ext_ies_o::ext_c::extended_add_path_list() const -{ - assert_choice_type(types::extended_add_path_list, type_, "Extension"); - return c.get(); -} -const trpteg_info_c& gnb_rx_tx_time_diff_ext_ies_o::ext_c::trpteg_info() const -{ - assert_choice_type(types::trpteg_info, type_, "Extension"); - return c.get(); -} -void gnb_rx_tx_time_diff_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::extended_add_path_list: - j.start_array("ExtendedAdditionalPathList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::trpteg_info: - j.write_fieldname("TRPTEGInformation"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE gnb_rx_tx_time_diff_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::extended_add_path_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::trpteg_info: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE gnb_rx_tx_time_diff_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::extended_add_path_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::trpteg_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* gnb_rx_tx_time_diff_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"ExtendedAdditionalPathList", "TRPTEGInformation"}; - return convert_enum_idx(names, 2, value, "gnb_rx_tx_time_diff_ext_ies_o::ext_c::types"); -} - -// LoS-NLoSIndicatorHard ::= ENUMERATED -const char* lo_s_n_lo_si_ndicator_hard_opts::to_string() const -{ - static const char* names[] = {"nlos", "los"}; - return convert_enum_idx(names, 2, value, "lo_s_n_lo_si_ndicator_hard_e"); -} - -// PosResourceSetTypeAperiodic ::= SEQUENCE -SRSASN_CODE pos_res_set_type_aperiodic_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_res_trigger, (uint8_t)1u, (uint8_t)3u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_res_set_type_aperiodic_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_res_trigger, bref, (uint8_t)1u, (uint8_t)3u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_res_set_type_aperiodic_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResourceTrigger", srs_res_trigger); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PosResourceSetTypePeriodic ::= SEQUENCE -SRSASN_CODE pos_res_set_type_periodic_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(posperiodic_set.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_res_set_type_periodic_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(posperiodic_set.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_res_set_type_periodic_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("posperiodicSet", "true"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* pos_res_set_type_periodic_s::posperiodic_set_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "pos_res_set_type_periodic_s::posperiodic_set_e_"); -} - -// PosResourceSetTypeSemi-persistent ::= SEQUENCE -SRSASN_CODE pos_res_set_type_semi_persistent_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(possemi_persistent_set.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_res_set_type_semi_persistent_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(possemi_persistent_set.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_res_set_type_semi_persistent_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("possemi-persistentSet", "true"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* pos_res_set_type_semi_persistent_s::possemi_persistent_set_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "pos_res_set_type_semi_persistent_s::possemi_persistent_set_e_"); -} - -// PRSInformationPos ::= SEQUENCE -SRSASN_CODE pr_si_nformation_pos_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(prs_res_id_pos_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prs_id_pos, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(pack_integer(bref, prs_res_set_id_pos, (uint8_t)0u, (uint8_t)7u, false, true)); - if (prs_res_id_pos_present) { - HANDLE_CODE(pack_integer(bref, prs_res_id_pos, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pr_si_nformation_pos_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(prs_res_id_pos_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prs_id_pos, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(unpack_integer(prs_res_set_id_pos, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - if (prs_res_id_pos_present) { - HANDLE_CODE(unpack_integer(prs_res_id_pos, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pr_si_nformation_pos_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRS-IDPos", prs_id_pos); - j.write_int("pRS-Resource-Set-IDPos", prs_res_set_id_pos); - if (prs_res_id_pos_present) { - j.write_int("pRS-Resource-IDPos", prs_res_id_pos); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSAngleItem ::= SEQUENCE -SRSASN_CODE prs_angle_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(nr_prs_azimuth_fine_present, 1)); - HANDLE_CODE(bref.pack(nr_prs_elevation_present, 1)); - HANDLE_CODE(bref.pack(nr_prs_elevation_fine_present, 1)); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - HANDLE_CODE(pack_integer(bref, nr_prs_azimuth, (uint16_t)0u, (uint16_t)359u, false, true)); - if (nr_prs_azimuth_fine_present) { - HANDLE_CODE(pack_integer(bref, nr_prs_azimuth_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (nr_prs_elevation_present) { - HANDLE_CODE(pack_integer(bref, nr_prs_elevation, (uint8_t)0u, (uint8_t)180u, false, true)); - } - if (nr_prs_elevation_fine_present) { - HANDLE_CODE(pack_integer(bref, nr_prs_elevation_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_angle_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(nr_prs_azimuth_fine_present, 1)); - HANDLE_CODE(bref.unpack(nr_prs_elevation_present, 1)); - HANDLE_CODE(bref.unpack(nr_prs_elevation_fine_present, 1)); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(nr_prs_azimuth, bref, (uint16_t)0u, (uint16_t)359u, false, true)); - if (nr_prs_azimuth_fine_present) { - HANDLE_CODE(unpack_integer(nr_prs_azimuth_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (nr_prs_elevation_present) { - HANDLE_CODE(unpack_integer(nr_prs_elevation, bref, (uint8_t)0u, (uint8_t)180u, false, true)); - } - if (nr_prs_elevation_fine_present) { - HANDLE_CODE(unpack_integer(nr_prs_elevation_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void prs_angle_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("nRPRSAzimuth", nr_prs_azimuth); - if (nr_prs_azimuth_fine_present) { - j.write_int("nRPRSAzimuthFine", nr_prs_azimuth_fine); - } - if (nr_prs_elevation_present) { - j.write_int("nRPRSElevation", nr_prs_elevation); - } - if (nr_prs_elevation_fine_present) { - j.write_int("nRPRSElevationFine", nr_prs_elevation_fine); - } - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -// PRSMuting ::= SEQUENCE -SRSASN_CODE prs_muting_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(prs_muting_option1_present, 1)); - HANDLE_CODE(bref.pack(prs_muting_option2_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (prs_muting_option1_present) { - HANDLE_CODE(prs_muting_option1.pack(bref)); - } - if (prs_muting_option2_present) { - HANDLE_CODE(prs_muting_option2.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_muting_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(prs_muting_option1_present, 1)); - HANDLE_CODE(bref.unpack(prs_muting_option2_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (prs_muting_option1_present) { - HANDLE_CODE(prs_muting_option1.unpack(bref)); - } - if (prs_muting_option2_present) { - HANDLE_CODE(prs_muting_option2.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_muting_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (prs_muting_option1_present) { - j.write_fieldname("pRSMutingOption1"); - prs_muting_option1.to_json(j); - } - if (prs_muting_option2_present) { - j.write_fieldname("pRSMutingOption2"); - prs_muting_option2.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ReferencePoint ::= CHOICE -void ref_point_c::destroy_() -{ - switch (type_) { - case types::ref_point_coordinate: - c.destroy(); - break; - case types::ref_point_coordinate_ha: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void ref_point_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::relative_coordinate_id: - break; - case types::ref_point_coordinate: - c.init(); - break; - case types::ref_point_coordinate_ha: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ref_point_c"); - } -} -ref_point_c::ref_point_c(const ref_point_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::relative_coordinate_id: - c.init(other.c.get()); - break; - case types::ref_point_coordinate: - c.init(other.c.get()); - break; - case types::ref_point_coordinate_ha: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ref_point_c"); - } -} -ref_point_c& ref_point_c::operator=(const ref_point_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::relative_coordinate_id: - c.set(other.c.get()); - break; - case types::ref_point_coordinate: - c.set(other.c.get()); - break; - case types::ref_point_coordinate_ha: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ref_point_c"); - } - - return *this; -} -uint16_t& ref_point_c::set_relative_coordinate_id() -{ - set(types::relative_coordinate_id); - return c.get(); -} -ng_ran_access_point_position_s& ref_point_c::set_ref_point_coordinate() -{ - set(types::ref_point_coordinate); - return c.get(); -} -ngran_high_accuracy_access_point_position_s& ref_point_c::set_ref_point_coordinate_ha() -{ - set(types::ref_point_coordinate_ha); - return c.get(); -} -protocol_ie_single_container_s& ref_point_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void ref_point_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::relative_coordinate_id: - j.write_int("relativeCoordinateID", c.get()); - break; - case types::ref_point_coordinate: - j.write_fieldname("referencePointCoordinate"); - c.get().to_json(j); - break; - case types::ref_point_coordinate_ha: - j.write_fieldname("referencePointCoordinateHA"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "ref_point_c"); - } - j.end_obj(); -} -SRSASN_CODE ref_point_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::relative_coordinate_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)511u, true, true)); - break; - case types::ref_point_coordinate: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ref_point_coordinate_ha: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "ref_point_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE ref_point_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::relative_coordinate_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)511u, true, true)); - break; - case types::ref_point_coordinate: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ref_point_coordinate_ha: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "ref_point_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* ref_point_c::types_opts::to_string() const -{ - static const char* names[] = { - "relativeCoordinateID", "referencePointCoordinate", "referencePointCoordinateHA", "choice-Extension"}; - return convert_enum_idx(names, 4, value, "ref_point_c::types"); -} - -// ReferenceSignal ::= CHOICE -void ref_sig_c::destroy_() -{ - switch (type_) { - case types::ssb: - c.destroy(); - break; - case types::dl_prs: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void ref_sig_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::nzp_csi_rs: - break; - case types::ssb: - c.init(); - break; - case types::srs: - break; - case types::positioning_srs: - break; - case types::dl_prs: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ref_sig_c"); - } -} -ref_sig_c::ref_sig_c(const ref_sig_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::nzp_csi_rs: - c.init(other.c.get()); - break; - case types::ssb: - c.init(other.c.get()); - break; - case types::srs: - c.init(other.c.get()); - break; - case types::positioning_srs: - c.init(other.c.get()); - break; - case types::dl_prs: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ref_sig_c"); - } -} -ref_sig_c& ref_sig_c::operator=(const ref_sig_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::nzp_csi_rs: - c.set(other.c.get()); - break; - case types::ssb: - c.set(other.c.get()); - break; - case types::srs: - c.set(other.c.get()); - break; - case types::positioning_srs: - c.set(other.c.get()); - break; - case types::dl_prs: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ref_sig_c"); - } - - return *this; -} -uint8_t& ref_sig_c::set_nzp_csi_rs() -{ - set(types::nzp_csi_rs); - return c.get(); -} -ssb_s& ref_sig_c::set_ssb() -{ - set(types::ssb); - return c.get(); -} -uint8_t& ref_sig_c::set_srs() -{ - set(types::srs); - return c.get(); -} -uint8_t& ref_sig_c::set_positioning_srs() -{ - set(types::positioning_srs); - return c.get(); -} -dl_prs_s& ref_sig_c::set_dl_prs() -{ - set(types::dl_prs); - return c.get(); -} -protocol_ie_single_container_s& ref_sig_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void ref_sig_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::nzp_csi_rs: - j.write_int("nZP-CSI-RS", c.get()); - break; - case types::ssb: - j.write_fieldname("sSB"); - c.get().to_json(j); - break; - case types::srs: - j.write_int("sRS", c.get()); - break; - case types::positioning_srs: - j.write_int("positioningSRS", c.get()); - break; - case types::dl_prs: - j.write_fieldname("dL-PRS"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "ref_sig_c"); - } - j.end_obj(); -} -SRSASN_CODE ref_sig_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::nzp_csi_rs: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)191u, false, true)); - break; - case types::ssb: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::srs: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)63u, false, true)); - break; - case types::positioning_srs: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)63u, false, true)); - break; - case types::dl_prs: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "ref_sig_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE ref_sig_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::nzp_csi_rs: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)191u, false, true)); - break; - case types::ssb: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::srs: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)63u, false, true)); - break; - case types::positioning_srs: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)63u, false, true)); - break; - case types::dl_prs: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "ref_sig_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* ref_sig_c::types_opts::to_string() const -{ - static const char* names[] = {"nZP-CSI-RS", "sSB", "sRS", "positioningSRS", "dL-PRS", "choice-Extension"}; - return convert_enum_idx(names, 6, value, "ref_sig_c::types"); -} - -// ResourceSetTypeAperiodic ::= SEQUENCE -SRSASN_CODE res_set_type_aperiodic_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_res_trigger, (uint8_t)1u, (uint8_t)3u, false, true)); - HANDLE_CODE(pack_integer(bref, slotoffset, (uint8_t)0u, (uint8_t)32u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_set_type_aperiodic_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_res_trigger, bref, (uint8_t)1u, (uint8_t)3u, false, true)); - HANDLE_CODE(unpack_integer(slotoffset, bref, (uint8_t)0u, (uint8_t)32u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_set_type_aperiodic_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResourceTrigger", srs_res_trigger); - j.write_int("slotoffset", slotoffset); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResourceSetTypePeriodic ::= SEQUENCE -SRSASN_CODE res_set_type_periodic_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(periodic_set.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_set_type_periodic_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(periodic_set.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_set_type_periodic_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("periodicSet", "true"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_set_type_periodic_s::periodic_set_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "res_set_type_periodic_s::periodic_set_e_"); -} - -// ResourceSetTypeSemi-persistent ::= SEQUENCE -SRSASN_CODE res_set_type_semi_persistent_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(semi_persistent_set.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_set_type_semi_persistent_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(semi_persistent_set.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_set_type_semi_persistent_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("semi-persistentSet", "true"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_set_type_semi_persistent_s::semi_persistent_set_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "res_set_type_semi_persistent_s::semi_persistent_set_e_"); -} - -// ResourceTypeAperiodicPos ::= SEQUENCE -SRSASN_CODE res_type_aperiodic_pos_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, slot_offset, (uint8_t)0u, (uint8_t)32u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_aperiodic_pos_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(slot_offset, bref, (uint8_t)0u, (uint8_t)32u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_type_aperiodic_pos_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("slotOffset", slot_offset); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResourceTypeAperiodic ::= SEQUENCE -SRSASN_CODE res_type_aperiodic_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(aperiodic_res_type.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_aperiodic_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(aperiodic_res_type.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_type_aperiodic_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("aperiodicResourceType", "true"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_type_aperiodic_s::aperiodic_res_type_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "res_type_aperiodic_s::aperiodic_res_type_e_"); -} - -// ResourceTypePeriodicPos ::= SEQUENCE -SRSASN_CODE res_type_periodic_pos_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, offset, (uint32_t)0u, (uint32_t)81919u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_periodic_pos_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(offset, bref, (uint32_t)0u, (uint32_t)81919u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_type_periodic_pos_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("periodicity", periodicity.to_string()); - j.write_int("offset", offset); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_type_periodic_pos_s::periodicity_opts::to_string() const -{ - static const char* names[] = {"slot1", "slot2", "slot4", "slot5", "slot8", "slot10", "slot16", - "slot20", "slot32", "slot40", "slot64", "slot80", "slot160", "slot320", - "slot640", "slot1280", "slot2560", "slot5120", "slot10240", "slot40960", "slot81920", - "slot128", "slot256", "slot512", "slot20480"}; - return convert_enum_idx(names, 25, value, "res_type_periodic_pos_s::periodicity_e_"); -} -uint32_t res_type_periodic_pos_s::periodicity_opts::to_number() const -{ - static const uint32_t numbers[] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, - 320, 640, 1280, 2560, 5120, 10240, 40960, 81920, 128, 256, 512, 20480}; - return map_enum_number(numbers, 25, value, "res_type_periodic_pos_s::periodicity_e_"); -} - -// ResourceTypePeriodic ::= SEQUENCE -SRSASN_CODE res_type_periodic_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, offset, (uint16_t)0u, (uint16_t)2559u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_periodic_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(offset, bref, (uint16_t)0u, (uint16_t)2559u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_type_periodic_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("periodicity", periodicity.to_string()); - j.write_int("offset", offset); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_type_periodic_s::periodicity_opts::to_string() const -{ - static const char* names[] = {"slot1", - "slot2", - "slot4", - "slot5", - "slot8", - "slot10", - "slot16", - "slot20", - "slot32", - "slot40", - "slot64", - "slot80", - "slot160", - "slot320", - "slot640", - "slot1280", - "slot2560"}; - return convert_enum_idx(names, 17, value, "res_type_periodic_s::periodicity_e_"); -} -uint16_t res_type_periodic_s::periodicity_opts::to_number() const -{ - static const uint16_t numbers[] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; - return map_enum_number(numbers, 17, value, "res_type_periodic_s::periodicity_e_"); -} - -// ResourceTypeSemi-persistentPos ::= SEQUENCE -SRSASN_CODE res_type_semi_persistent_pos_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, offset, (uint32_t)0u, (uint32_t)81919u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_semi_persistent_pos_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(offset, bref, (uint32_t)0u, (uint32_t)81919u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_type_semi_persistent_pos_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("periodicity", periodicity.to_string()); - j.write_int("offset", offset); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_type_semi_persistent_pos_s::periodicity_opts::to_string() const -{ - static const char* names[] = {"slot1", "slot2", "slot4", "slot5", "slot8", "slot10", "slot16", - "slot20", "slot32", "slot40", "slot64", "slot80", "slot160", "slot320", - "slot640", "slot1280", "slot2560", "slot5120", "slot10240", "slot40960", "slot81920", - "slot128", "slot256", "slot512", "slot20480"}; - return convert_enum_idx(names, 25, value, "res_type_semi_persistent_pos_s::periodicity_e_"); -} -uint32_t res_type_semi_persistent_pos_s::periodicity_opts::to_number() const -{ - static const uint32_t numbers[] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, - 320, 640, 1280, 2560, 5120, 10240, 40960, 81920, 128, 256, 512, 20480}; - return map_enum_number(numbers, 25, value, "res_type_semi_persistent_pos_s::periodicity_e_"); -} - -// ResourceTypeSemi-persistent ::= SEQUENCE -SRSASN_CODE res_type_semi_persistent_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, offset, (uint16_t)0u, (uint16_t)2559u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_semi_persistent_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(offset, bref, (uint16_t)0u, (uint16_t)2559u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void res_type_semi_persistent_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("periodicity", periodicity.to_string()); - j.write_int("offset", offset); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* res_type_semi_persistent_s::periodicity_opts::to_string() const -{ - static const char* names[] = {"slot1", - "slot2", - "slot4", - "slot5", - "slot8", - "slot10", - "slot16", - "slot20", - "slot32", - "slot40", - "slot64", - "slot80", - "slot160", - "slot320", - "slot640", - "slot1280", - "slot2560"}; - return convert_enum_idx(names, 17, value, "res_type_semi_persistent_s::periodicity_e_"); -} -uint16_t res_type_semi_persistent_s::periodicity_opts::to_number() const -{ - static const uint16_t numbers[] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; - return map_enum_number(numbers, 17, value, "res_type_semi_persistent_s::periodicity_e_"); -} - -// ResultCSI-RSRP-PerCSI-RS-Item ::= SEQUENCE -SRSASN_CODE result_csi_rsrp_per_csi_rs_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, csi_rs_idx, (uint8_t)0u, (uint8_t)95u, false, true)); - HANDLE_CODE(pack_integer(bref, value_csi_rsrp, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_csi_rsrp_per_csi_rs_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(csi_rs_idx, bref, (uint8_t)0u, (uint8_t)95u, false, true)); - HANDLE_CODE(unpack_integer(value_csi_rsrp, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_csi_rsrp_per_csi_rs_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("cSI-RS-Index", csi_rs_idx); - j.write_int("valueCSI-RSRP", value_csi_rsrp); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultCSI-RSRQ-PerCSI-RS-Item ::= SEQUENCE -SRSASN_CODE result_csi_rsrq_per_csi_rs_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, csi_rs_idx, (uint8_t)0u, (uint8_t)95u, false, true)); - HANDLE_CODE(pack_integer(bref, value_csi_rsrq, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_csi_rsrq_per_csi_rs_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(csi_rs_idx, bref, (uint8_t)0u, (uint8_t)95u, false, true)); - HANDLE_CODE(unpack_integer(value_csi_rsrq, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_csi_rsrq_per_csi_rs_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("cSI-RS-Index", csi_rs_idx); - j.write_int("valueCSI-RSRQ", value_csi_rsrq); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultSS-RSRP-PerSSB-Item ::= SEQUENCE -SRSASN_CODE result_ss_rsrp_per_ssb_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, ssb_idx, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(pack_integer(bref, value_ss_rsrp, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_ss_rsrp_per_ssb_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(ssb_idx, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(unpack_integer(value_ss_rsrp, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_ss_rsrp_per_ssb_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sSB-Index", ssb_idx); - j.write_int("valueSS-RSRP", value_ss_rsrp); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultSS-RSRQ-PerSSB-Item ::= SEQUENCE -SRSASN_CODE result_ss_rsrq_per_ssb_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, ssb_idx, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(pack_integer(bref, value_ss_rsrq, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_ss_rsrq_per_ssb_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(ssb_idx, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(unpack_integer(value_ss_rsrq, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_ss_rsrq_per_ssb_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sSB-Index", ssb_idx); - j.write_int("valueSS-RSRQ", value_ss_rsrq); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSResourceTypeChoice ::= CHOICE -void srs_res_type_choice_c::destroy_() -{ - switch (type_) { - case types::srs_res_info: - c.destroy(); - break; - case types::pos_srs_res_info: - c.destroy(); - break; - default: - break; - } -} -void srs_res_type_choice_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::srs_res_info: - c.init(); - break; - case types::pos_srs_res_info: - c.init(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "srs_res_type_choice_c"); - } -} -srs_res_type_choice_c::srs_res_type_choice_c(const srs_res_type_choice_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::srs_res_info: - c.init(other.c.get()); - break; - case types::pos_srs_res_info: - c.init(other.c.get()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "srs_res_type_choice_c"); - } -} -srs_res_type_choice_c& srs_res_type_choice_c::operator=(const srs_res_type_choice_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::srs_res_info: - c.set(other.c.get()); - break; - case types::pos_srs_res_info: - c.set(other.c.get()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "srs_res_type_choice_c"); - } - - return *this; -} -srs_info_s& srs_res_type_choice_c::set_srs_res_info() -{ - set(types::srs_res_info); - return c.get(); -} -pos_srs_info_s& srs_res_type_choice_c::set_pos_srs_res_info() -{ - set(types::pos_srs_res_info); - return c.get(); -} -void srs_res_type_choice_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::srs_res_info: - j.write_fieldname("sRSResourceInfo"); - c.get().to_json(j); - break; - case types::pos_srs_res_info: - j.write_fieldname("posSRSResourceInfo"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "srs_res_type_choice_c"); - } - j.end_obj(); -} -SRSASN_CODE srs_res_type_choice_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::srs_res_info: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::pos_srs_res_info: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "srs_res_type_choice_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_type_choice_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::srs_res_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::pos_srs_res_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "srs_res_type_choice_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* srs_res_type_choice_c::types_opts::to_string() const -{ - static const char* names[] = {"sRSResourceInfo", "posSRSResourceInfo"}; - return convert_enum_idx(names, 2, value, "srs_res_type_choice_c::types"); -} - -// SSBBurstPosition ::= CHOICE -void ssb_burst_position_c::destroy_() -{ - switch (type_) { - case types::short_bitmap: - c.destroy>(); - break; - case types::medium_bitmap: - c.destroy>(); - break; - case types::long_bitmap: - c.destroy>(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void ssb_burst_position_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::short_bitmap: - c.init>(); - break; - case types::medium_bitmap: - c.init>(); - break; - case types::long_bitmap: - c.init>(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ssb_burst_position_c"); - } -} -ssb_burst_position_c::ssb_burst_position_c(const ssb_burst_position_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::short_bitmap: - c.init(other.c.get>()); - break; - case types::medium_bitmap: - c.init(other.c.get>()); - break; - case types::long_bitmap: - c.init(other.c.get>()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ssb_burst_position_c"); - } -} -ssb_burst_position_c& ssb_burst_position_c::operator=(const ssb_burst_position_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::short_bitmap: - c.set(other.c.get>()); - break; - case types::medium_bitmap: - c.set(other.c.get>()); - break; - case types::long_bitmap: - c.set(other.c.get>()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ssb_burst_position_c"); - } - - return *this; -} -fixed_bitstring<4, false, true>& ssb_burst_position_c::set_short_bitmap() -{ - set(types::short_bitmap); - return c.get>(); -} -fixed_bitstring<8, false, true>& ssb_burst_position_c::set_medium_bitmap() -{ - set(types::medium_bitmap); - return c.get>(); -} -fixed_bitstring<64, false, true>& ssb_burst_position_c::set_long_bitmap() -{ - set(types::long_bitmap); - return c.get>(); -} -protocol_ie_single_container_s& ssb_burst_position_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void ssb_burst_position_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::short_bitmap: - j.write_str("shortBitmap", c.get>().to_string()); - break; - case types::medium_bitmap: - j.write_str("mediumBitmap", c.get>().to_string()); - break; - case types::long_bitmap: - j.write_str("longBitmap", c.get>().to_string()); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "ssb_burst_position_c"); - } - j.end_obj(); -} -SRSASN_CODE ssb_burst_position_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::short_bitmap: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::medium_bitmap: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::long_bitmap: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "ssb_burst_position_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE ssb_burst_position_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::short_bitmap: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::medium_bitmap: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::long_bitmap: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "ssb_burst_position_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* ssb_burst_position_c::types_opts::to_string() const -{ - static const char* names[] = {"shortBitmap", "mediumBitmap", "longBitmap", "choice-extension"}; - return convert_enum_idx(names, 4, value, "ssb_burst_position_c::types"); -} - -// TRPPositionDirectAccuracy ::= CHOICE -void trp_position_direct_accuracy_c::destroy_() -{ - switch (type_) { - case types::trp_position: - c.destroy(); - break; - case types::trph_aposition: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trp_position_direct_accuracy_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::trp_position: - c.init(); - break; - case types::trph_aposition: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_position_direct_accuracy_c"); - } -} -trp_position_direct_accuracy_c::trp_position_direct_accuracy_c(const trp_position_direct_accuracy_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::trp_position: - c.init(other.c.get()); - break; - case types::trph_aposition: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_position_direct_accuracy_c"); - } -} -trp_position_direct_accuracy_c& trp_position_direct_accuracy_c::operator=(const trp_position_direct_accuracy_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::trp_position: - c.set(other.c.get()); - break; - case types::trph_aposition: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_position_direct_accuracy_c"); - } - - return *this; -} -ng_ran_access_point_position_s& trp_position_direct_accuracy_c::set_trp_position() -{ - set(types::trp_position); - return c.get(); -} -ngran_high_accuracy_access_point_position_s& trp_position_direct_accuracy_c::set_trph_aposition() -{ - set(types::trph_aposition); - return c.get(); -} -protocol_ie_single_container_s& trp_position_direct_accuracy_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trp_position_direct_accuracy_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::trp_position: - j.write_fieldname("tRPPosition"); - c.get().to_json(j); - break; - case types::trph_aposition: - j.write_fieldname("tRPHAposition"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_position_direct_accuracy_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_position_direct_accuracy_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::trp_position: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trph_aposition: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_position_direct_accuracy_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_position_direct_accuracy_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::trp_position: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trph_aposition: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_position_direct_accuracy_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_position_direct_accuracy_c::types_opts::to_string() const -{ - static const char* names[] = {"tRPPosition", "tRPHAposition", "choice-extension"}; - return convert_enum_idx(names, 3, value, "trp_position_direct_accuracy_c::types"); -} - -// TRPReferencePointType ::= CHOICE -void trp_ref_point_type_c::destroy_() -{ - switch (type_) { - case types::trp_position_relative_geodetic: - c.destroy(); - break; - case types::trp_position_relative_cartesian: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trp_ref_point_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::trp_position_relative_geodetic: - c.init(); - break; - case types::trp_position_relative_cartesian: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_ref_point_type_c"); - } -} -trp_ref_point_type_c::trp_ref_point_type_c(const trp_ref_point_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::trp_position_relative_geodetic: - c.init(other.c.get()); - break; - case types::trp_position_relative_cartesian: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_ref_point_type_c"); - } -} -trp_ref_point_type_c& trp_ref_point_type_c::operator=(const trp_ref_point_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::trp_position_relative_geodetic: - c.set(other.c.get()); - break; - case types::trp_position_relative_cartesian: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_ref_point_type_c"); - } - - return *this; -} -relative_geodetic_location_s& trp_ref_point_type_c::set_trp_position_relative_geodetic() -{ - set(types::trp_position_relative_geodetic); - return c.get(); -} -relative_cartesian_location_s& trp_ref_point_type_c::set_trp_position_relative_cartesian() -{ - set(types::trp_position_relative_cartesian); - return c.get(); -} -protocol_ie_single_container_s& trp_ref_point_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trp_ref_point_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::trp_position_relative_geodetic: - j.write_fieldname("tRPPositionRelativeGeodetic"); - c.get().to_json(j); - break; - case types::trp_position_relative_cartesian: - j.write_fieldname("tRPPositionRelativeCartesian"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_ref_point_type_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_ref_point_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::trp_position_relative_geodetic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_position_relative_cartesian: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_ref_point_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_ref_point_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::trp_position_relative_geodetic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_position_relative_cartesian: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_ref_point_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_ref_point_type_c::types_opts::to_string() const -{ - static const char* names[] = {"tRPPositionRelativeGeodetic", "tRPPositionRelativeCartesian", "choice-extension"}; - return convert_enum_idx(names, 3, value, "trp_ref_point_type_c::types"); -} - -// TRPTEGItem ::= SEQUENCE -SRSASN_CODE trpteg_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(dl_prs_res_id_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(trp_tx_teg_info.pack(bref)); - HANDLE_CODE(pack_integer(bref, dl_prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - if (dl_prs_res_id_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, dl_prs_res_id_list, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trpteg_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool dl_prs_res_id_list_present; - HANDLE_CODE(bref.unpack(dl_prs_res_id_list_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(trp_tx_teg_info.unpack(bref)); - HANDLE_CODE(unpack_integer(dl_prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - if (dl_prs_res_id_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(dl_prs_res_id_list, bref, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trpteg_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("tRP-Tx-TEGInformation"); - trp_tx_teg_info.to_json(j); - j.write_int("dl-PRSResourceSetID", dl_prs_res_set_id); - if (dl_prs_res_id_list.size() > 0) { - j.start_array("dl-PRSResourceID-List"); - for (const auto& e1 : dl_prs_res_id_list) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// UL-RTOAMeasurement-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t ul_rtoameas_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {77, 86}; - return map_enum_number(names, 2, idx, "id"); -} -bool ul_rtoameas_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {77, 86}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e ul_rtoameas_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 77: - return crit_e::ignore; - case 86: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -ul_rtoameas_ext_ies_o::ext_c ul_rtoameas_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 77: - ret.set(ext_c::types::extended_add_path_list); - break; - case 86: - ret.set(ext_c::types::trp_rx_teg_info); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e ul_rtoameas_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 77: - return presence_e::optional; - case 86: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void ul_rtoameas_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::extended_add_path_list: - c = extended_add_path_list_l{}; - break; - case types::trp_rx_teg_info: - c = trp_rx_teg_info_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ul_rtoameas_ext_ies_o::ext_c"); - } -} -extended_add_path_list_l& ul_rtoameas_ext_ies_o::ext_c::extended_add_path_list() -{ - assert_choice_type(types::extended_add_path_list, type_, "Extension"); - return c.get(); -} -trp_rx_teg_info_s& ul_rtoameas_ext_ies_o::ext_c::trp_rx_teg_info() -{ - assert_choice_type(types::trp_rx_teg_info, type_, "Extension"); - return c.get(); -} -const extended_add_path_list_l& ul_rtoameas_ext_ies_o::ext_c::extended_add_path_list() const -{ - assert_choice_type(types::extended_add_path_list, type_, "Extension"); - return c.get(); -} -const trp_rx_teg_info_s& ul_rtoameas_ext_ies_o::ext_c::trp_rx_teg_info() const -{ - assert_choice_type(types::trp_rx_teg_info, type_, "Extension"); - return c.get(); -} -void ul_rtoameas_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::extended_add_path_list: - j.start_array("ExtendedAdditionalPathList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::trp_rx_teg_info: - j.write_fieldname("TRP-Rx-TEGInformation"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "ul_rtoameas_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE ul_rtoameas_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::extended_add_path_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::trp_rx_teg_info: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "ul_rtoameas_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE ul_rtoameas_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::extended_add_path_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::trp_rx_teg_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "ul_rtoameas_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* ul_rtoameas_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"ExtendedAdditionalPathList", "TRP-Rx-TEGInformation"}; - return convert_enum_idx(names, 2, value, "ul_rtoameas_ext_ies_o::ext_c::types"); -} - -// AdditionalPathListItem ::= SEQUENCE -SRSASN_CODE add_path_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(path_quality_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(relative_time_of_path.pack(bref)); - if (path_quality_present) { - HANDLE_CODE(path_quality.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE add_path_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(path_quality_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(relative_time_of_path.unpack(bref)); - if (path_quality_present) { - HANDLE_CODE(path_quality.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void add_path_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("relativeTimeOfPath"); - relative_time_of_path.to_json(j); - if (path_quality_present) { - j.write_fieldname("pathQuality"); - path_quality.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// CGI-NR ::= SEQUENCE -SRSASN_CODE cgi_nr_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(plmn_id.pack(bref)); - HANDLE_CODE(nr_cell_id.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE cgi_nr_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(plmn_id.unpack(bref)); - HANDLE_CODE(nr_cell_id.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void cgi_nr_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("pLMN-Identity", plmn_id.to_string()); - j.write_str("nRcellIdentifier", nr_cell_id.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// DLPRSResourceSetARP ::= SEQUENCE -SRSASN_CODE dl_prs_res_set_arp_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, dl_prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(dl_prs_res_set_arp_location.pack(bref)); - HANDLE_CODE(pack_dyn_seq_of(bref, listof_dl_prs_res_arp, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_res_set_arp_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(dl_prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(dl_prs_res_set_arp_location.unpack(bref)); - HANDLE_CODE(unpack_dyn_seq_of(listof_dl_prs_res_arp, bref, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void dl_prs_res_set_arp_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("dl-PRSResourceSetID", dl_prs_res_set_id); - j.write_fieldname("dL-PRSResourceSetARPLocation"); - dl_prs_res_set_arp_location.to_json(j); - j.start_array("listofDL-PRSResourceARP"); - for (const auto& e1 : listof_dl_prs_res_arp) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// Expected-UL-AoA ::= SEQUENCE -SRSASN_CODE expected_ul_ao_a_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(expected_zenith_ao_a_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(expected_azimuth_ao_a.pack(bref)); - if (expected_zenith_ao_a_present) { - HANDLE_CODE(expected_zenith_ao_a.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE expected_ul_ao_a_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(expected_zenith_ao_a_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(expected_azimuth_ao_a.unpack(bref)); - if (expected_zenith_ao_a_present) { - HANDLE_CODE(expected_zenith_ao_a.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void expected_ul_ao_a_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("expected-Azimuth-AoA"); - expected_azimuth_ao_a.to_json(j); - if (expected_zenith_ao_a_present) { - j.write_fieldname("expected-Zenith-AoA"); - expected_zenith_ao_a.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// Expected-ZoA-only ::= SEQUENCE -SRSASN_CODE expected_zo_a_only_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(expected_zo_a_only.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE expected_zo_a_only_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(expected_zo_a_only.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void expected_zo_a_only_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("expected-ZoA-only"); - expected_zo_a_only.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// GeographicalCoordinates-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t geographical_coordinates_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {78}; - return map_enum_number(names, 1, idx, "id"); -} -bool geographical_coordinates_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 78 == id; -} -crit_e geographical_coordinates_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 78) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -geographical_coordinates_ext_ies_o::ext_c geographical_coordinates_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 78) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e geographical_coordinates_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 78) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void geographical_coordinates_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("ARPLocationInformation"); - for (const auto& e1 : c) { - e1.to_json(j); - } - j.end_array(); - j.end_obj(); -} -SRSASN_CODE geographical_coordinates_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, c, 1, 16, true)); - return SRSASN_SUCCESS; -} -SRSASN_CODE geographical_coordinates_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(c, bref, 1, 16, true)); - return SRSASN_SUCCESS; -} - -const char* geographical_coordinates_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"ARPLocationInformation"}; - return convert_enum_idx(names, 1, value, "geographical_coordinates_ext_ies_o::ext_c::types"); -} - -// LCS-to-GCS-TranslationItem ::= SEQUENCE -SRSASN_CODE lcs_to_gcs_translation_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(alpha_fine_present, 1)); - HANDLE_CODE(bref.pack(beta_fine_present, 1)); - HANDLE_CODE(bref.pack(gamma_fine_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, alpha, (uint16_t)0u, (uint16_t)359u, false, true)); - if (alpha_fine_present) { - HANDLE_CODE(pack_integer(bref, alpha_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(pack_integer(bref, beta, (uint16_t)0u, (uint16_t)359u, false, true)); - if (beta_fine_present) { - HANDLE_CODE(pack_integer(bref, beta_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(pack_integer(bref, gamma, (uint16_t)0u, (uint16_t)359u, false, true)); - if (gamma_fine_present) { - HANDLE_CODE(pack_integer(bref, gamma_fine, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE lcs_to_gcs_translation_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(alpha_fine_present, 1)); - HANDLE_CODE(bref.unpack(beta_fine_present, 1)); - HANDLE_CODE(bref.unpack(gamma_fine_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(alpha, bref, (uint16_t)0u, (uint16_t)359u, false, true)); - if (alpha_fine_present) { - HANDLE_CODE(unpack_integer(alpha_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(unpack_integer(beta, bref, (uint16_t)0u, (uint16_t)359u, false, true)); - if (beta_fine_present) { - HANDLE_CODE(unpack_integer(beta_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - HANDLE_CODE(unpack_integer(gamma, bref, (uint16_t)0u, (uint16_t)359u, false, true)); - if (gamma_fine_present) { - HANDLE_CODE(unpack_integer(gamma_fine, bref, (uint8_t)0u, (uint8_t)9u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void lcs_to_gcs_translation_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("alpha", alpha); - if (alpha_fine_present) { - j.write_int("alphaFine", alpha_fine); - } - j.write_int("beta", beta); - if (beta_fine_present) { - j.write_int("betaFine", beta_fine); - } - j.write_int("gamma", gamma); - if (gamma_fine_present) { - j.write_int("gammaFine", gamma_fine); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// LoS-NLoSInformation ::= CHOICE -void lo_s_n_lo_si_nformation_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void lo_s_n_lo_si_nformation_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::lo_s_n_lo_si_ndicator_soft: - break; - case types::lo_s_n_lo_si_ndicator_hard: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "lo_s_n_lo_si_nformation_c"); - } -} -lo_s_n_lo_si_nformation_c::lo_s_n_lo_si_nformation_c(const lo_s_n_lo_si_nformation_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::lo_s_n_lo_si_ndicator_soft: - c.init(other.c.get()); - break; - case types::lo_s_n_lo_si_ndicator_hard: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "lo_s_n_lo_si_nformation_c"); - } -} -lo_s_n_lo_si_nformation_c& lo_s_n_lo_si_nformation_c::operator=(const lo_s_n_lo_si_nformation_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::lo_s_n_lo_si_ndicator_soft: - c.set(other.c.get()); - break; - case types::lo_s_n_lo_si_ndicator_hard: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "lo_s_n_lo_si_nformation_c"); - } - - return *this; -} -uint8_t& lo_s_n_lo_si_nformation_c::set_lo_s_n_lo_si_ndicator_soft() -{ - set(types::lo_s_n_lo_si_ndicator_soft); - return c.get(); -} -lo_s_n_lo_si_ndicator_hard_e& lo_s_n_lo_si_nformation_c::set_lo_s_n_lo_si_ndicator_hard() -{ - set(types::lo_s_n_lo_si_ndicator_hard); - return c.get(); -} -protocol_ie_single_container_s& lo_s_n_lo_si_nformation_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void lo_s_n_lo_si_nformation_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lo_s_n_lo_si_ndicator_soft: - j.write_int("loS-NLoSIndicatorSoft", c.get()); - break; - case types::lo_s_n_lo_si_ndicator_hard: - j.write_str("loS-NLoSIndicatorHard", c.get().to_string()); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "lo_s_n_lo_si_nformation_c"); - } - j.end_obj(); -} -SRSASN_CODE lo_s_n_lo_si_nformation_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::lo_s_n_lo_si_ndicator_soft: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)10u, false, true)); - break; - case types::lo_s_n_lo_si_ndicator_hard: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "lo_s_n_lo_si_nformation_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE lo_s_n_lo_si_nformation_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::lo_s_n_lo_si_ndicator_soft: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)10u, false, true)); - break; - case types::lo_s_n_lo_si_ndicator_hard: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "lo_s_n_lo_si_nformation_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* lo_s_n_lo_si_nformation_c::types_opts::to_string() const -{ - static const char* names[] = {"loS-NLoSIndicatorSoft", "loS-NLoSIndicatorHard", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "lo_s_n_lo_si_nformation_c::types"); -} - -// NR-PRS-Beam-InformationItem ::= SEQUENCE -SRSASN_CODE nr_prs_beam_info_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, pr_sres_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, prs_angle, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_prs_beam_info_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(pr_sres_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(prs_angle, bref, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void nr_prs_beam_info_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRSresourceSetID", pr_sres_set_id); - j.start_array("pRSAngle"); - for (const auto& e1 : prs_angle) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// OnDemandPRS-Info ::= SEQUENCE -SRSASN_CODE on_demand_prs_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(allowed_res_set_periodicity_values_present, 1)); - HANDLE_CODE(bref.pack(allowed_prs_bw_values_present, 1)); - HANDLE_CODE(bref.pack(allowed_res_repeat_factor_values_present, 1)); - HANDLE_CODE(bref.pack(allowed_res_nof_symbols_values_present, 1)); - HANDLE_CODE(bref.pack(allowed_comb_size_values_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(on_demand_prs_request_allowed.pack(bref)); - if (allowed_res_set_periodicity_values_present) { - HANDLE_CODE(allowed_res_set_periodicity_values.pack(bref)); - } - if (allowed_prs_bw_values_present) { - HANDLE_CODE(allowed_prs_bw_values.pack(bref)); - } - if (allowed_res_repeat_factor_values_present) { - HANDLE_CODE(allowed_res_repeat_factor_values.pack(bref)); - } - if (allowed_res_nof_symbols_values_present) { - HANDLE_CODE(allowed_res_nof_symbols_values.pack(bref)); - } - if (allowed_comb_size_values_present) { - HANDLE_CODE(allowed_comb_size_values.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE on_demand_prs_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(allowed_res_set_periodicity_values_present, 1)); - HANDLE_CODE(bref.unpack(allowed_prs_bw_values_present, 1)); - HANDLE_CODE(bref.unpack(allowed_res_repeat_factor_values_present, 1)); - HANDLE_CODE(bref.unpack(allowed_res_nof_symbols_values_present, 1)); - HANDLE_CODE(bref.unpack(allowed_comb_size_values_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(on_demand_prs_request_allowed.unpack(bref)); - if (allowed_res_set_periodicity_values_present) { - HANDLE_CODE(allowed_res_set_periodicity_values.unpack(bref)); - } - if (allowed_prs_bw_values_present) { - HANDLE_CODE(allowed_prs_bw_values.unpack(bref)); - } - if (allowed_res_repeat_factor_values_present) { - HANDLE_CODE(allowed_res_repeat_factor_values.unpack(bref)); - } - if (allowed_res_nof_symbols_values_present) { - HANDLE_CODE(allowed_res_nof_symbols_values.unpack(bref)); - } - if (allowed_comb_size_values_present) { - HANDLE_CODE(allowed_comb_size_values.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void on_demand_prs_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("onDemandPRSRequestAllowed", on_demand_prs_request_allowed.to_string()); - if (allowed_res_set_periodicity_values_present) { - j.write_str("allowedResourceSetPeriodicityValues", allowed_res_set_periodicity_values.to_string()); - } - if (allowed_prs_bw_values_present) { - j.write_str("allowedPRSBandwidthValues", allowed_prs_bw_values.to_string()); - } - if (allowed_res_repeat_factor_values_present) { - j.write_str("allowedResourceRepetitionFactorValues", allowed_res_repeat_factor_values.to_string()); - } - if (allowed_res_nof_symbols_values_present) { - j.write_str("allowedResourceNumberOfSymbolsValues", allowed_res_nof_symbols_values.to_string()); - } - if (allowed_comb_size_values_present) { - j.write_str("allowedCombSizeValues", allowed_comb_size_values.to_string()); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PosResourceSetType ::= CHOICE -void pos_res_set_type_c::destroy_() -{ - switch (type_) { - case types::periodic: - c.destroy(); - break; - case types::semi_persistent: - c.destroy(); - break; - case types::aperiodic: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void pos_res_set_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::periodic: - c.init(); - break; - case types::semi_persistent: - c.init(); - break; - case types::aperiodic: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "pos_res_set_type_c"); - } -} -pos_res_set_type_c::pos_res_set_type_c(const pos_res_set_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::periodic: - c.init(other.c.get()); - break; - case types::semi_persistent: - c.init(other.c.get()); - break; - case types::aperiodic: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "pos_res_set_type_c"); - } -} -pos_res_set_type_c& pos_res_set_type_c::operator=(const pos_res_set_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::periodic: - c.set(other.c.get()); - break; - case types::semi_persistent: - c.set(other.c.get()); - break; - case types::aperiodic: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "pos_res_set_type_c"); - } - - return *this; -} -pos_res_set_type_periodic_s& pos_res_set_type_c::set_periodic() -{ - set(types::periodic); - return c.get(); -} -pos_res_set_type_semi_persistent_s& pos_res_set_type_c::set_semi_persistent() -{ - set(types::semi_persistent); - return c.get(); -} -pos_res_set_type_aperiodic_s& pos_res_set_type_c::set_aperiodic() -{ - set(types::aperiodic); - return c.get(); -} -protocol_ie_single_container_s& pos_res_set_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void pos_res_set_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::periodic: - j.write_fieldname("periodic"); - c.get().to_json(j); - break; - case types::semi_persistent: - j.write_fieldname("semi-persistent"); - c.get().to_json(j); - break; - case types::aperiodic: - j.write_fieldname("aperiodic"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "pos_res_set_type_c"); - } - j.end_obj(); -} -SRSASN_CODE pos_res_set_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "pos_res_set_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_res_set_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "pos_res_set_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* pos_res_set_type_c::types_opts::to_string() const -{ - static const char* names[] = {"periodic", "semi-persistent", "aperiodic", "choice-extension"}; - return convert_enum_idx(names, 4, value, "pos_res_set_type_c::types"); -} - -template struct asn1::protocol_ext_field_s; - -template struct asn1::protocol_ext_field_s; - -// PRSResourceSet-Item ::= SEQUENCE -SRSASN_CODE prs_res_set_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(prs_muting_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(subcarrier_spacing.pack(bref)); - HANDLE_CODE(pack_integer(bref, pr_sbw, (uint8_t)1u, (uint8_t)63u, false, true)); - HANDLE_CODE(pack_integer(bref, start_prb, (uint16_t)0u, (uint16_t)2176u, false, true)); - HANDLE_CODE(pack_integer(bref, point_a, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(comb_size.pack(bref)); - HANDLE_CODE(cp_type.pack(bref)); - HANDLE_CODE(res_set_periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, res_set_slot_offset, (uint32_t)0u, (uint32_t)81919u, true, true)); - HANDLE_CODE(res_repeat_factor.pack(bref)); - HANDLE_CODE(res_time_gap.pack(bref)); - HANDLE_CODE(res_numof_symbols.pack(bref)); - if (prs_muting_present) { - HANDLE_CODE(prs_muting.pack(bref)); - } - HANDLE_CODE(pack_integer(bref, prs_res_tx_pwr, (int8_t)-60, (int8_t)50, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, prs_res_list, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_res_set_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(prs_muting_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(subcarrier_spacing.unpack(bref)); - HANDLE_CODE(unpack_integer(pr_sbw, bref, (uint8_t)1u, (uint8_t)63u, false, true)); - HANDLE_CODE(unpack_integer(start_prb, bref, (uint16_t)0u, (uint16_t)2176u, false, true)); - HANDLE_CODE(unpack_integer(point_a, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(comb_size.unpack(bref)); - HANDLE_CODE(cp_type.unpack(bref)); - HANDLE_CODE(res_set_periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(res_set_slot_offset, bref, (uint32_t)0u, (uint32_t)81919u, true, true)); - HANDLE_CODE(res_repeat_factor.unpack(bref)); - HANDLE_CODE(res_time_gap.unpack(bref)); - HANDLE_CODE(res_numof_symbols.unpack(bref)); - if (prs_muting_present) { - HANDLE_CODE(prs_muting.unpack(bref)); - } - HANDLE_CODE(unpack_integer(prs_res_tx_pwr, bref, (int8_t)-60, (int8_t)50, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(prs_res_list, bref, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_res_set_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRSResourceSetID", prs_res_set_id); - j.write_str("subcarrierSpacing", subcarrier_spacing.to_string()); - j.write_int("pRSbandwidth", pr_sbw); - j.write_int("startPRB", start_prb); - j.write_int("pointA", point_a); - j.write_str("combSize", comb_size.to_string()); - j.write_str("cPType", cp_type.to_string()); - j.write_str("resourceSetPeriodicity", res_set_periodicity.to_string()); - j.write_int("resourceSetSlotOffset", res_set_slot_offset); - j.write_str("resourceRepetitionFactor", res_repeat_factor.to_string()); - j.write_str("resourceTimeGap", res_time_gap.to_string()); - j.write_str("resourceNumberofSymbols", res_numof_symbols.to_string()); - if (prs_muting_present) { - j.write_fieldname("pRSMuting"); - prs_muting.to_json(j); - } - j.write_int("pRSResourceTransmitPower", prs_res_tx_pwr); - j.start_array("pRSResource-List"); - for (const auto& e1 : prs_res_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* prs_res_set_item_s::subcarrier_spacing_opts::to_string() const -{ - static const char* names[] = {"kHz15", "kHz30", "kHz60", "kHz120"}; - return convert_enum_idx(names, 4, value, "prs_res_set_item_s::subcarrier_spacing_e_"); -} -uint8_t prs_res_set_item_s::subcarrier_spacing_opts::to_number() const -{ - static const uint8_t numbers[] = {15, 30, 60, 120}; - return map_enum_number(numbers, 4, value, "prs_res_set_item_s::subcarrier_spacing_e_"); -} - -const char* prs_res_set_item_s::comb_size_opts::to_string() const -{ - static const char* names[] = {"n2", "n4", "n6", "n12"}; - return convert_enum_idx(names, 4, value, "prs_res_set_item_s::comb_size_e_"); -} -uint8_t prs_res_set_item_s::comb_size_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4, 6, 12}; - return map_enum_number(numbers, 4, value, "prs_res_set_item_s::comb_size_e_"); -} - -const char* prs_res_set_item_s::cp_type_opts::to_string() const -{ - static const char* names[] = {"normal", "extended"}; - return convert_enum_idx(names, 2, value, "prs_res_set_item_s::cp_type_e_"); -} - -const char* prs_res_set_item_s::res_set_periodicity_opts::to_string() const -{ - static const char* names[] = {"n4", "n5", "n8", "n10", "n16", "n20", "n32", - "n40", "n64", "n80", "n160", "n320", "n640", "n1280", - "n2560", "n5120", "n10240", "n20480", "n40960", "n81920"}; - return convert_enum_idx(names, 20, value, "prs_res_set_item_s::res_set_periodicity_e_"); -} -uint32_t prs_res_set_item_s::res_set_periodicity_opts::to_number() const -{ - static const uint32_t numbers[] = {4, 5, 8, 10, 16, 20, 32, 40, 64, 80, - 160, 320, 640, 1280, 2560, 5120, 10240, 20480, 40960, 81920}; - return map_enum_number(numbers, 20, value, "prs_res_set_item_s::res_set_periodicity_e_"); -} - -const char* prs_res_set_item_s::res_repeat_factor_opts::to_string() const -{ - static const char* names[] = {"rf1", "rf2", "rf4", "rf6", "rf8", "rf16", "rf32"}; - return convert_enum_idx(names, 7, value, "prs_res_set_item_s::res_repeat_factor_e_"); -} -uint8_t prs_res_set_item_s::res_repeat_factor_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4, 6, 8, 16, 32}; - return map_enum_number(numbers, 7, value, "prs_res_set_item_s::res_repeat_factor_e_"); -} - -const char* prs_res_set_item_s::res_time_gap_opts::to_string() const -{ - static const char* names[] = {"tg1", "tg2", "tg4", "tg8", "tg16", "tg32"}; - return convert_enum_idx(names, 6, value, "prs_res_set_item_s::res_time_gap_e_"); -} -uint8_t prs_res_set_item_s::res_time_gap_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4, 8, 16, 32}; - return map_enum_number(numbers, 6, value, "prs_res_set_item_s::res_time_gap_e_"); -} - -const char* prs_res_set_item_s::res_numof_symbols_opts::to_string() const -{ - static const char* names[] = {"n2", "n4", "n6", "n12"}; - return convert_enum_idx(names, 4, value, "prs_res_set_item_s::res_numof_symbols_e_"); -} -uint8_t prs_res_set_item_s::res_numof_symbols_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4, 6, 12}; - return map_enum_number(numbers, 4, value, "prs_res_set_item_s::res_numof_symbols_e_"); -} - -// ResourceSetType ::= CHOICE -void res_set_type_c::destroy_() -{ - switch (type_) { - case types::periodic: - c.destroy(); - break; - case types::semi_persistent: - c.destroy(); - break; - case types::aperiodic: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void res_set_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::periodic: - c.init(); - break; - case types::semi_persistent: - c.init(); - break; - case types::aperiodic: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_set_type_c"); - } -} -res_set_type_c::res_set_type_c(const res_set_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::periodic: - c.init(other.c.get()); - break; - case types::semi_persistent: - c.init(other.c.get()); - break; - case types::aperiodic: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_set_type_c"); - } -} -res_set_type_c& res_set_type_c::operator=(const res_set_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::periodic: - c.set(other.c.get()); - break; - case types::semi_persistent: - c.set(other.c.get()); - break; - case types::aperiodic: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_set_type_c"); - } - - return *this; -} -res_set_type_periodic_s& res_set_type_c::set_periodic() -{ - set(types::periodic); - return c.get(); -} -res_set_type_semi_persistent_s& res_set_type_c::set_semi_persistent() -{ - set(types::semi_persistent); - return c.get(); -} -res_set_type_aperiodic_s& res_set_type_c::set_aperiodic() -{ - set(types::aperiodic); - return c.get(); -} -protocol_ie_single_container_s& res_set_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void res_set_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::periodic: - j.write_fieldname("periodic"); - c.get().to_json(j); - break; - case types::semi_persistent: - j.write_fieldname("semi-persistent"); - c.get().to_json(j); - break; - case types::aperiodic: - j.write_fieldname("aperiodic"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "res_set_type_c"); - } - j.end_obj(); -} -SRSASN_CODE res_set_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "res_set_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE res_set_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "res_set_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* res_set_type_c::types_opts::to_string() const -{ - static const char* names[] = {"periodic", "semi-persistent", "aperiodic", "choice-extension"}; - return convert_enum_idx(names, 4, value, "res_set_type_c::types"); -} - -// ResourceType ::= CHOICE -void res_type_c::destroy_() -{ - switch (type_) { - case types::periodic: - c.destroy(); - break; - case types::semi_persistent: - c.destroy(); - break; - case types::aperiodic: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void res_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::periodic: - c.init(); - break; - case types::semi_persistent: - c.init(); - break; - case types::aperiodic: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_type_c"); - } -} -res_type_c::res_type_c(const res_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::periodic: - c.init(other.c.get()); - break; - case types::semi_persistent: - c.init(other.c.get()); - break; - case types::aperiodic: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_type_c"); - } -} -res_type_c& res_type_c::operator=(const res_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::periodic: - c.set(other.c.get()); - break; - case types::semi_persistent: - c.set(other.c.get()); - break; - case types::aperiodic: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_type_c"); - } - - return *this; -} -res_type_periodic_s& res_type_c::set_periodic() -{ - set(types::periodic); - return c.get(); -} -res_type_semi_persistent_s& res_type_c::set_semi_persistent() -{ - set(types::semi_persistent); - return c.get(); -} -res_type_aperiodic_s& res_type_c::set_aperiodic() -{ - set(types::aperiodic); - return c.get(); -} -protocol_ie_single_container_s& res_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void res_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::periodic: - j.write_fieldname("periodic"); - c.get().to_json(j); - break; - case types::semi_persistent: - j.write_fieldname("semi-persistent"); - c.get().to_json(j); - break; - case types::aperiodic: - j.write_fieldname("aperiodic"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "res_type_c"); - } - j.end_obj(); -} -SRSASN_CODE res_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "res_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "res_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* res_type_c::types_opts::to_string() const -{ - static const char* names[] = {"periodic", "semi-persistent", "aperiodic", "choice-extension"}; - return convert_enum_idx(names, 4, value, "res_type_c::types"); -} - -// ResourceTypePos ::= CHOICE -void res_type_pos_c::destroy_() -{ - switch (type_) { - case types::periodic: - c.destroy(); - break; - case types::semi_persistent: - c.destroy(); - break; - case types::aperiodic: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void res_type_pos_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::periodic: - c.init(); - break; - case types::semi_persistent: - c.init(); - break; - case types::aperiodic: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_type_pos_c"); - } -} -res_type_pos_c::res_type_pos_c(const res_type_pos_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::periodic: - c.init(other.c.get()); - break; - case types::semi_persistent: - c.init(other.c.get()); - break; - case types::aperiodic: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_type_pos_c"); - } -} -res_type_pos_c& res_type_pos_c::operator=(const res_type_pos_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::periodic: - c.set(other.c.get()); - break; - case types::semi_persistent: - c.set(other.c.get()); - break; - case types::aperiodic: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "res_type_pos_c"); - } - - return *this; -} -res_type_periodic_pos_s& res_type_pos_c::set_periodic() -{ - set(types::periodic); - return c.get(); -} -res_type_semi_persistent_pos_s& res_type_pos_c::set_semi_persistent() -{ - set(types::semi_persistent); - return c.get(); -} -res_type_aperiodic_pos_s& res_type_pos_c::set_aperiodic() -{ - set(types::aperiodic); - return c.get(); -} -protocol_ie_single_container_s& res_type_pos_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void res_type_pos_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::periodic: - j.write_fieldname("periodic"); - c.get().to_json(j); - break; - case types::semi_persistent: - j.write_fieldname("semi-persistent"); - c.get().to_json(j); - break; - case types::aperiodic: - j.write_fieldname("aperiodic"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "res_type_pos_c"); - } - j.end_obj(); -} -SRSASN_CODE res_type_pos_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "res_type_pos_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE res_type_pos_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::periodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::semi_persistent: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::aperiodic: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "res_type_pos_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* res_type_pos_c::types_opts::to_string() const -{ - static const char* names[] = {"periodic", "semi-persistent", "aperiodic", "choice-extension"}; - return convert_enum_idx(names, 4, value, "res_type_pos_c::types"); -} - -// SpatialRelationPerSRSResourceItem ::= SEQUENCE -SRSASN_CODE spatial_relation_per_srs_res_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(ref_sig.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE spatial_relation_per_srs_res_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(ref_sig.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void spatial_relation_per_srs_res_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("referenceSignal"); - ref_sig.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SpatialRelationPos ::= CHOICE -void spatial_relation_pos_c::destroy_() -{ - switch (type_) { - case types::ssb_pos: - c.destroy(); - break; - case types::pr_si_nformation_pos: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void spatial_relation_pos_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::ssb_pos: - c.init(); - break; - case types::pr_si_nformation_pos: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "spatial_relation_pos_c"); - } -} -spatial_relation_pos_c::spatial_relation_pos_c(const spatial_relation_pos_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::ssb_pos: - c.init(other.c.get()); - break; - case types::pr_si_nformation_pos: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "spatial_relation_pos_c"); - } -} -spatial_relation_pos_c& spatial_relation_pos_c::operator=(const spatial_relation_pos_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::ssb_pos: - c.set(other.c.get()); - break; - case types::pr_si_nformation_pos: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "spatial_relation_pos_c"); - } - - return *this; -} -ssb_s& spatial_relation_pos_c::set_ssb_pos() -{ - set(types::ssb_pos); - return c.get(); -} -pr_si_nformation_pos_s& spatial_relation_pos_c::set_pr_si_nformation_pos() -{ - set(types::pr_si_nformation_pos); - return c.get(); -} -protocol_ie_single_container_s& spatial_relation_pos_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void spatial_relation_pos_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::ssb_pos: - j.write_fieldname("sSBPos"); - c.get().to_json(j); - break; - case types::pr_si_nformation_pos: - j.write_fieldname("pRSInformationPos"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "spatial_relation_pos_c"); - } - j.end_obj(); -} -SRSASN_CODE spatial_relation_pos_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::ssb_pos: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::pr_si_nformation_pos: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "spatial_relation_pos_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE spatial_relation_pos_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::ssb_pos: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::pr_si_nformation_pos: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "spatial_relation_pos_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* spatial_relation_pos_c::types_opts::to_string() const -{ - static const char* names[] = {"sSBPos", "pRSInformationPos", "choice-extension"}; - return convert_enum_idx(names, 3, value, "spatial_relation_pos_c::types"); -} - -// SpatialRelationforResourceIDItem ::= SEQUENCE -SRSASN_CODE spatial_relationfor_res_id_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(ref_sig.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE spatial_relationfor_res_id_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(ref_sig.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void spatial_relationfor_res_id_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("referenceSignal"); - ref_sig.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSResourcetype ::= SEQUENCE -SRSASN_CODE srs_restype_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - HANDLE_CODE(srs_res_type_choice.pack(bref)); - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_restype_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(srs_res_type_choice.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void srs_restype_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("sRSResourceTypeChoice"); - srs_res_type_choice.to_json(j); - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -// TF-Configuration ::= SEQUENCE -SRSASN_CODE tf_cfg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ssb_burst_position_present, 1)); - HANDLE_CODE(bref.pack(sfn_initisation_time_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, ssb_freq, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(ssb_subcarrier_spacing.pack(bref)); - HANDLE_CODE(pack_integer(bref, ssb_tx_pwr, (int8_t)-60, (int8_t)50, false, true)); - HANDLE_CODE(ssb_periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, ssb_half_frame_offset, (uint8_t)0u, (uint8_t)1u, false, true)); - HANDLE_CODE(pack_integer(bref, ssb_sfn_offset, (uint8_t)0u, (uint8_t)15u, false, true)); - if (ssb_burst_position_present) { - HANDLE_CODE(ssb_burst_position.pack(bref)); - } - if (sfn_initisation_time_present) { - HANDLE_CODE(sfn_initisation_time.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE tf_cfg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ssb_burst_position_present, 1)); - HANDLE_CODE(bref.unpack(sfn_initisation_time_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(ssb_freq, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(ssb_subcarrier_spacing.unpack(bref)); - HANDLE_CODE(unpack_integer(ssb_tx_pwr, bref, (int8_t)-60, (int8_t)50, false, true)); - HANDLE_CODE(ssb_periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(ssb_half_frame_offset, bref, (uint8_t)0u, (uint8_t)1u, false, true)); - HANDLE_CODE(unpack_integer(ssb_sfn_offset, bref, (uint8_t)0u, (uint8_t)15u, false, true)); - if (ssb_burst_position_present) { - HANDLE_CODE(ssb_burst_position.unpack(bref)); - } - if (sfn_initisation_time_present) { - HANDLE_CODE(sfn_initisation_time.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void tf_cfg_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sSB-frequency", ssb_freq); - j.write_str("sSB-subcarrier-spacing", ssb_subcarrier_spacing.to_string()); - j.write_int("sSB-Transmit-power", ssb_tx_pwr); - j.write_str("sSB-periodicity", ssb_periodicity.to_string()); - j.write_int("sSB-half-frame-offset", ssb_half_frame_offset); - j.write_int("sSB-SFN-offset", ssb_sfn_offset); - if (ssb_burst_position_present) { - j.write_fieldname("sSB-BurstPosition"); - ssb_burst_position.to_json(j); - } - if (sfn_initisation_time_present) { - j.write_str("sFN-initialisation-time", sfn_initisation_time.to_string()); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* tf_cfg_s::ssb_subcarrier_spacing_opts::to_string() const -{ - static const char* names[] = {"kHz15", "kHz30", "kHz120", "kHz240", "kHz60"}; - return convert_enum_idx(names, 5, value, "tf_cfg_s::ssb_subcarrier_spacing_e_"); -} -uint8_t tf_cfg_s::ssb_subcarrier_spacing_opts::to_number() const -{ - static const uint8_t numbers[] = {15, 30, 120, 240, 60}; - return map_enum_number(numbers, 5, value, "tf_cfg_s::ssb_subcarrier_spacing_e_"); -} - -const char* tf_cfg_s::ssb_periodicity_opts::to_string() const -{ - static const char* names[] = {"ms5", "ms10", "ms20", "ms40", "ms80", "ms160"}; - return convert_enum_idx(names, 6, value, "tf_cfg_s::ssb_periodicity_e_"); -} -uint8_t tf_cfg_s::ssb_periodicity_opts::to_number() const -{ - static const uint8_t numbers[] = {5, 10, 20, 40, 80, 160}; - return map_enum_number(numbers, 6, value, "tf_cfg_s::ssb_periodicity_e_"); -} - -// TRPBeamAntennaInformation ::= SEQUENCE -SRSASN_CODE trp_beam_ant_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(choice_trp_beam_ant_info_item.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_beam_ant_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(choice_trp_beam_ant_info_item.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_beam_ant_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("choice-TRP-Beam-Antenna-Info-Item"); - choice_trp_beam_ant_info_item.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPPositionDirect ::= SEQUENCE -SRSASN_CODE trp_position_direct_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(accuracy.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_position_direct_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(accuracy.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_position_direct_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("accuracy"); - accuracy.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPPositionReferenced ::= SEQUENCE -SRSASN_CODE trp_position_refd_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(ref_point.pack(bref)); - HANDLE_CODE(ref_point_type.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_position_refd_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(ref_point.unpack(bref)); - HANDLE_CODE(ref_point_type.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_position_refd_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("referencePoint"); - ref_point.to_json(j); - j.write_fieldname("referencePointType"); - ref_point_type.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPType ::= ENUMERATED -const char* trp_type_opts::to_string() const -{ - static const char* names[] = {"prsOnlyTP", "srsOnlyRP", "tp", "rp", "trp"}; - return convert_enum_idx(names, 5, value, "trp_type_e"); -} - -// TransmissionComb ::= CHOICE -void tx_comb_c::destroy_() -{ - switch (type_) { - case types::n2: - c.destroy(); - break; - case types::n4: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void tx_comb_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::n2: - c.init(); - break; - case types::n4: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "tx_comb_c"); - } -} -tx_comb_c::tx_comb_c(const tx_comb_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::n2: - c.init(other.c.get()); - break; - case types::n4: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "tx_comb_c"); - } -} -tx_comb_c& tx_comb_c::operator=(const tx_comb_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::n2: - c.set(other.c.get()); - break; - case types::n4: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "tx_comb_c"); - } - - return *this; -} -tx_comb_c::n2_s_& tx_comb_c::set_n2() -{ - set(types::n2); - return c.get(); -} -tx_comb_c::n4_s_& tx_comb_c::set_n4() -{ - set(types::n4); - return c.get(); -} -protocol_ie_single_container_s& tx_comb_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void tx_comb_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::n2: - j.write_fieldname("n2"); - j.start_obj(); - j.write_int("combOffset-n2", c.get().comb_offset_n2); - j.write_int("cyclicShift-n2", c.get().cyclic_shift_n2); - j.end_obj(); - break; - case types::n4: - j.write_fieldname("n4"); - j.start_obj(); - j.write_int("combOffset-n4", c.get().comb_offset_n4); - j.write_int("cyclicShift-n4", c.get().cyclic_shift_n4); - j.end_obj(); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "tx_comb_c"); - } - j.end_obj(); -} -SRSASN_CODE tx_comb_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::n2: - HANDLE_CODE(pack_integer(bref, c.get().comb_offset_n2, (uint8_t)0u, (uint8_t)1u, false, true)); - HANDLE_CODE(pack_integer(bref, c.get().cyclic_shift_n2, (uint8_t)0u, (uint8_t)7u, false, true)); - break; - case types::n4: - HANDLE_CODE(pack_integer(bref, c.get().comb_offset_n4, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(pack_integer(bref, c.get().cyclic_shift_n4, (uint8_t)0u, (uint8_t)11u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "tx_comb_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE tx_comb_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::n2: - HANDLE_CODE(unpack_integer(c.get().comb_offset_n2, bref, (uint8_t)0u, (uint8_t)1u, false, true)); - HANDLE_CODE(unpack_integer(c.get().cyclic_shift_n2, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - break; - case types::n4: - HANDLE_CODE(unpack_integer(c.get().comb_offset_n4, bref, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(unpack_integer(c.get().cyclic_shift_n4, bref, (uint8_t)0u, (uint8_t)11u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "tx_comb_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* tx_comb_c::types_opts::to_string() const -{ - static const char* names[] = {"n2", "n4", "choice-extension"}; - return convert_enum_idx(names, 3, value, "tx_comb_c::types"); -} -uint8_t tx_comb_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4}; - return map_enum_number(numbers, 2, value, "tx_comb_c::types"); -} - -// TransmissionCombPos ::= CHOICE -void tx_comb_pos_c::destroy_() -{ - switch (type_) { - case types::n2: - c.destroy(); - break; - case types::n4: - c.destroy(); - break; - case types::n8: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void tx_comb_pos_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::n2: - c.init(); - break; - case types::n4: - c.init(); - break; - case types::n8: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "tx_comb_pos_c"); - } -} -tx_comb_pos_c::tx_comb_pos_c(const tx_comb_pos_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::n2: - c.init(other.c.get()); - break; - case types::n4: - c.init(other.c.get()); - break; - case types::n8: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "tx_comb_pos_c"); - } -} -tx_comb_pos_c& tx_comb_pos_c::operator=(const tx_comb_pos_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::n2: - c.set(other.c.get()); - break; - case types::n4: - c.set(other.c.get()); - break; - case types::n8: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "tx_comb_pos_c"); - } - - return *this; -} -tx_comb_pos_c::n2_s_& tx_comb_pos_c::set_n2() -{ - set(types::n2); - return c.get(); -} -tx_comb_pos_c::n4_s_& tx_comb_pos_c::set_n4() -{ - set(types::n4); - return c.get(); -} -tx_comb_pos_c::n8_s_& tx_comb_pos_c::set_n8() -{ - set(types::n8); - return c.get(); -} -protocol_ie_single_container_s& tx_comb_pos_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void tx_comb_pos_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::n2: - j.write_fieldname("n2"); - j.start_obj(); - j.write_int("combOffset-n2", c.get().comb_offset_n2); - j.write_int("cyclicShift-n2", c.get().cyclic_shift_n2); - j.end_obj(); - break; - case types::n4: - j.write_fieldname("n4"); - j.start_obj(); - j.write_int("combOffset-n4", c.get().comb_offset_n4); - j.write_int("cyclicShift-n4", c.get().cyclic_shift_n4); - j.end_obj(); - break; - case types::n8: - j.write_fieldname("n8"); - j.start_obj(); - j.write_int("combOffset-n8", c.get().comb_offset_n8); - j.write_int("cyclicShift-n8", c.get().cyclic_shift_n8); - j.end_obj(); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "tx_comb_pos_c"); - } - j.end_obj(); -} -SRSASN_CODE tx_comb_pos_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::n2: - HANDLE_CODE(pack_integer(bref, c.get().comb_offset_n2, (uint8_t)0u, (uint8_t)1u, false, true)); - HANDLE_CODE(pack_integer(bref, c.get().cyclic_shift_n2, (uint8_t)0u, (uint8_t)7u, false, true)); - break; - case types::n4: - HANDLE_CODE(pack_integer(bref, c.get().comb_offset_n4, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(pack_integer(bref, c.get().cyclic_shift_n4, (uint8_t)0u, (uint8_t)11u, false, true)); - break; - case types::n8: - HANDLE_CODE(pack_integer(bref, c.get().comb_offset_n8, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(pack_integer(bref, c.get().cyclic_shift_n8, (uint8_t)0u, (uint8_t)5u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "tx_comb_pos_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE tx_comb_pos_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::n2: - HANDLE_CODE(unpack_integer(c.get().comb_offset_n2, bref, (uint8_t)0u, (uint8_t)1u, false, true)); - HANDLE_CODE(unpack_integer(c.get().cyclic_shift_n2, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - break; - case types::n4: - HANDLE_CODE(unpack_integer(c.get().comb_offset_n4, bref, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(unpack_integer(c.get().cyclic_shift_n4, bref, (uint8_t)0u, (uint8_t)11u, false, true)); - break; - case types::n8: - HANDLE_CODE(unpack_integer(c.get().comb_offset_n8, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(unpack_integer(c.get().cyclic_shift_n8, bref, (uint8_t)0u, (uint8_t)5u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "tx_comb_pos_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* tx_comb_pos_c::types_opts::to_string() const -{ - static const char* names[] = {"n2", "n4", "n8", "choice-extension"}; - return convert_enum_idx(names, 4, value, "tx_comb_pos_c::types"); -} -uint8_t tx_comb_pos_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4, 8}; - return map_enum_number(numbers, 3, value, "tx_comb_pos_c::types"); -} - -// AngleMeasurementType ::= CHOICE -void angle_meas_type_c::destroy_() -{ - switch (type_) { - case types::expected_ul_ao_a: - c.destroy(); - break; - case types::expected_zo_a: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void angle_meas_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::expected_ul_ao_a: - c.init(); - break; - case types::expected_zo_a: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "angle_meas_type_c"); - } -} -angle_meas_type_c::angle_meas_type_c(const angle_meas_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::expected_ul_ao_a: - c.init(other.c.get()); - break; - case types::expected_zo_a: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "angle_meas_type_c"); - } -} -angle_meas_type_c& angle_meas_type_c::operator=(const angle_meas_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::expected_ul_ao_a: - c.set(other.c.get()); - break; - case types::expected_zo_a: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "angle_meas_type_c"); - } - - return *this; -} -expected_ul_ao_a_s& angle_meas_type_c::set_expected_ul_ao_a() -{ - set(types::expected_ul_ao_a); - return c.get(); -} -expected_zo_a_only_s& angle_meas_type_c::set_expected_zo_a() -{ - set(types::expected_zo_a); - return c.get(); -} -protocol_ie_single_container_s& angle_meas_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void angle_meas_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::expected_ul_ao_a: - j.write_fieldname("expected-ULAoA"); - c.get().to_json(j); - break; - case types::expected_zo_a: - j.write_fieldname("expected-ZoA"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "angle_meas_type_c"); - } - j.end_obj(); -} -SRSASN_CODE angle_meas_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::expected_ul_ao_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::expected_zo_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "angle_meas_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE angle_meas_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::expected_ul_ao_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::expected_zo_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "angle_meas_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* angle_meas_type_c::types_opts::to_string() const -{ - static const char* names[] = {"expected-ULAoA", "expected-ZoA", "choice-extension"}; - return convert_enum_idx(names, 3, value, "angle_meas_type_c::types"); -} - -// CGI-EUTRA ::= SEQUENCE -SRSASN_CODE cgi_eutra_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(plmn_id.pack(bref)); - HANDLE_CODE(eutr_acell_id.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE cgi_eutra_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(plmn_id.unpack(bref)); - HANDLE_CODE(eutr_acell_id.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void cgi_eutra_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("pLMN-Identity", plmn_id.to_string()); - j.write_str("eUTRAcellIdentifier", eutr_acell_id.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// DLPRSResourceCoordinates ::= SEQUENCE -SRSASN_CODE dl_prs_res_coordinates_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, listof_dl_prs_res_set_arp, 1, 2, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE dl_prs_res_coordinates_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(listof_dl_prs_res_set_arp, bref, 1, 2, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void dl_prs_res_coordinates_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("listofDL-PRSResourceSetARP"); - for (const auto& e1 : listof_dl_prs_res_set_arp) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE gnb_rx_tx_time_diff_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += extended_add_path_list_present ? 1 : 0; - nof_ies += trpteg_info_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (extended_add_path_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)77, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, extended_add_path_list, 1, 8, true)); - } - if (trpteg_info_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)85, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(trpteg_info.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE gnb_rx_tx_time_diff_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 77: { - extended_add_path_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(extended_add_path_list, bref, 1, 8, true)); - break; - } - case 85: { - trpteg_info_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(trpteg_info.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void gnb_rx_tx_time_diff_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (extended_add_path_list_present) { - j.write_int("id", 77); - j.write_str("criticality", "ignore"); - j.start_array("Extension"); - for (const auto& e1 : extended_add_path_list) { - e1.to_json(j); - } - j.end_array(); - } - if (trpteg_info_present) { - j.write_int("id", 85); - j.write_str("criticality", "ignore"); - trpteg_info.to_json(j); - } - j.end_obj(); -} - -// GNBRxTxTimeDiffMeas ::= CHOICE -void gnb_rx_tx_time_diff_meas_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void gnb_rx_tx_time_diff_meas_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::k0: - break; - case types::k1: - break; - case types::k2: - break; - case types::k3: - break; - case types::k4: - break; - case types::k5: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_meas_c"); - } -} -gnb_rx_tx_time_diff_meas_c::gnb_rx_tx_time_diff_meas_c(const gnb_rx_tx_time_diff_meas_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::k0: - c.init(other.c.get()); - break; - case types::k1: - c.init(other.c.get()); - break; - case types::k2: - c.init(other.c.get()); - break; - case types::k3: - c.init(other.c.get()); - break; - case types::k4: - c.init(other.c.get()); - break; - case types::k5: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_meas_c"); - } -} -gnb_rx_tx_time_diff_meas_c& gnb_rx_tx_time_diff_meas_c::operator=(const gnb_rx_tx_time_diff_meas_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::k0: - c.set(other.c.get()); - break; - case types::k1: - c.set(other.c.get()); - break; - case types::k2: - c.set(other.c.get()); - break; - case types::k3: - c.set(other.c.get()); - break; - case types::k4: - c.set(other.c.get()); - break; - case types::k5: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_meas_c"); - } - - return *this; -} -uint32_t& gnb_rx_tx_time_diff_meas_c::set_k0() -{ - set(types::k0); - return c.get(); -} -uint32_t& gnb_rx_tx_time_diff_meas_c::set_k1() -{ - set(types::k1); - return c.get(); -} -uint32_t& gnb_rx_tx_time_diff_meas_c::set_k2() -{ - set(types::k2); - return c.get(); -} -uint32_t& gnb_rx_tx_time_diff_meas_c::set_k3() -{ - set(types::k3); - return c.get(); -} -uint32_t& gnb_rx_tx_time_diff_meas_c::set_k4() -{ - set(types::k4); - return c.get(); -} -uint16_t& gnb_rx_tx_time_diff_meas_c::set_k5() -{ - set(types::k5); - return c.get(); -} -protocol_ie_single_container_s& gnb_rx_tx_time_diff_meas_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void gnb_rx_tx_time_diff_meas_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::k0: - j.write_int("k0", c.get()); - break; - case types::k1: - j.write_int("k1", c.get()); - break; - case types::k2: - j.write_int("k2", c.get()); - break; - case types::k3: - j.write_int("k3", c.get()); - break; - case types::k4: - j.write_int("k4", c.get()); - break; - case types::k5: - j.write_int("k5", c.get()); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_meas_c"); - } - j.end_obj(); -} -SRSASN_CODE gnb_rx_tx_time_diff_meas_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::k0: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)1970049u, false, true)); - break; - case types::k1: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)985025u, false, true)); - break; - case types::k2: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)492513u, false, true)); - break; - case types::k3: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)246257u, false, true)); - break; - case types::k4: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)123129u, false, true)); - break; - case types::k5: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)61565u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_meas_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE gnb_rx_tx_time_diff_meas_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::k0: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)1970049u, false, true)); - break; - case types::k1: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)985025u, false, true)); - break; - case types::k2: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)492513u, false, true)); - break; - case types::k3: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)246257u, false, true)); - break; - case types::k4: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)123129u, false, true)); - break; - case types::k5: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)61565u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "gnb_rx_tx_time_diff_meas_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* gnb_rx_tx_time_diff_meas_c::types_opts::to_string() const -{ - static const char* names[] = {"k0", "k1", "k2", "k3", "k4", "k5", "choice-extension"}; - return convert_enum_idx(names, 7, value, "gnb_rx_tx_time_diff_meas_c::types"); -} -uint8_t gnb_rx_tx_time_diff_meas_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 1, 2, 3, 4, 5}; - return map_enum_number(numbers, 6, value, "gnb_rx_tx_time_diff_meas_c::types"); -} - -// NR-PRS-Beam-Information ::= SEQUENCE -SRSASN_CODE nr_prs_beam_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(lcs_to_gcs_translation_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, nr_prs_beam_info_list, 1, 2, true)); - if (lcs_to_gcs_translation_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, lcs_to_gcs_translation_list, 1, 3, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_prs_beam_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool lcs_to_gcs_translation_list_present; - HANDLE_CODE(bref.unpack(lcs_to_gcs_translation_list_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(nr_prs_beam_info_list, bref, 1, 2, true)); - if (lcs_to_gcs_translation_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(lcs_to_gcs_translation_list, bref, 1, 3, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void nr_prs_beam_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("nR-PRS-Beam-InformationList"); - for (const auto& e1 : nr_prs_beam_info_list) { - e1.to_json(j); - } - j.end_array(); - if (lcs_to_gcs_translation_list.size() > 0) { - j.start_array("lCS-to-GCS-TranslationList"); - for (const auto& e1 : lcs_to_gcs_translation_list) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE pos_sib_segments_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(assist_data_sib_elem.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_sib_segments_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(assist_data_sib_elem.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_sib_segments_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("assistanceDataSIBelement", assist_data_sib_elem.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PosSRSResource-Item ::= SEQUENCE -SRSASN_CODE pos_srs_res_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(spatial_relation_pos_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_pos_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(tx_comb_pos.pack(bref)); - HANDLE_CODE(pack_integer(bref, start_position, (uint8_t)0u, (uint8_t)13u, false, true)); - HANDLE_CODE(nrof_symbols.pack(bref)); - HANDLE_CODE(pack_integer(bref, freq_domain_shift, (uint16_t)0u, (uint16_t)268u, false, true)); - HANDLE_CODE(pack_integer(bref, c_srs, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(group_or_seq_hop.pack(bref)); - HANDLE_CODE(res_type_pos.pack(bref)); - HANDLE_CODE(pack_integer(bref, seq_id, (uint32_t)0u, (uint32_t)65535u, false, true)); - if (spatial_relation_pos_present) { - HANDLE_CODE(spatial_relation_pos.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_srs_res_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(spatial_relation_pos_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_pos_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(tx_comb_pos.unpack(bref)); - HANDLE_CODE(unpack_integer(start_position, bref, (uint8_t)0u, (uint8_t)13u, false, true)); - HANDLE_CODE(nrof_symbols.unpack(bref)); - HANDLE_CODE(unpack_integer(freq_domain_shift, bref, (uint16_t)0u, (uint16_t)268u, false, true)); - HANDLE_CODE(unpack_integer(c_srs, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(group_or_seq_hop.unpack(bref)); - HANDLE_CODE(res_type_pos.unpack(bref)); - HANDLE_CODE(unpack_integer(seq_id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - if (spatial_relation_pos_present) { - HANDLE_CODE(spatial_relation_pos.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_srs_res_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("srs-PosResourceId", srs_pos_res_id); - j.write_fieldname("transmissionCombPos"); - tx_comb_pos.to_json(j); - j.write_int("startPosition", start_position); - j.write_str("nrofSymbols", nrof_symbols.to_string()); - j.write_int("freqDomainShift", freq_domain_shift); - j.write_int("c-SRS", c_srs); - j.write_str("groupOrSequenceHopping", group_or_seq_hop.to_string()); - j.write_fieldname("resourceTypePos"); - res_type_pos.to_json(j); - j.write_int("sequenceId", seq_id); - if (spatial_relation_pos_present) { - j.write_fieldname("spatialRelationPos"); - spatial_relation_pos.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* pos_srs_res_item_s::nrof_symbols_opts::to_string() const -{ - static const char* names[] = {"n1", "n2", "n4", "n8", "n12"}; - return convert_enum_idx(names, 5, value, "pos_srs_res_item_s::nrof_symbols_e_"); -} -uint8_t pos_srs_res_item_s::nrof_symbols_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4, 8, 12}; - return map_enum_number(numbers, 5, value, "pos_srs_res_item_s::nrof_symbols_e_"); -} - -const char* pos_srs_res_item_s::group_or_seq_hop_opts::to_string() const -{ - static const char* names[] = {"neither", "groupHopping", "sequenceHopping"}; - return convert_enum_idx(names, 3, value, "pos_srs_res_item_s::group_or_seq_hop_e_"); -} - -// PosSRSResourceSet-Item ::= SEQUENCE -SRSASN_CODE pos_srs_res_set_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, possrs_res_set_id, (uint8_t)0u, (uint8_t)15u, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, poss_rs_res_id_per_set_list, 1, 16, integer_packer(0, 63, false, true))); - HANDLE_CODE(posres_set_type.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_srs_res_set_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(possrs_res_set_id, bref, (uint8_t)0u, (uint8_t)15u, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(poss_rs_res_id_per_set_list, bref, 1, 16, integer_packer(0, 63, false, true))); - HANDLE_CODE(posres_set_type.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_srs_res_set_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("possrsResourceSetID", possrs_res_set_id); - j.start_array("possRSResourceIDPerSet-List"); - for (const auto& e1 : poss_rs_res_id_per_set_list) { - j.write_int(e1); - } - j.end_array(); - j.write_fieldname("posresourceSetType"); - posres_set_type.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSTransmissionOffIndicationPerResource-Item ::= SEQUENCE -SRSASN_CODE prs_tx_off_ind_per_res_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_tx_off_ind_per_res_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_tx_off_ind_per_res_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRSResourceID", prs_res_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// RequestedDLPRSResource-Item ::= SEQUENCE -SRSASN_CODE requested_dl_prs_res_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(qcl_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (qcl_info_present) { - HANDLE_CODE(qcl_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE requested_dl_prs_res_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(qcl_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (qcl_info_present) { - HANDLE_CODE(qcl_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void requested_dl_prs_res_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (qcl_info_present) { - j.write_fieldname("qCLInfo"); - qcl_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultCSI-RSRP-Item ::= SEQUENCE -SRSASN_CODE result_csi_rsrp_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_nr_present, 1)); - HANDLE_CODE(bref.pack(value_csi_rsrp_cell_present, 1)); - HANDLE_CODE(bref.pack(csi_rsrp_per_csi_rs.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, nr_pci, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(pack_integer(bref, nr_arfcn, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.pack(bref)); - } - if (value_csi_rsrp_cell_present) { - HANDLE_CODE(pack_integer(bref, value_csi_rsrp_cell, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (csi_rsrp_per_csi_rs.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, csi_rsrp_per_csi_rs, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_csi_rsrp_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_nr_present, 1)); - HANDLE_CODE(bref.unpack(value_csi_rsrp_cell_present, 1)); - bool csi_rsrp_per_csi_rs_present; - HANDLE_CODE(bref.unpack(csi_rsrp_per_csi_rs_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(nr_pci, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(unpack_integer(nr_arfcn, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.unpack(bref)); - } - if (value_csi_rsrp_cell_present) { - HANDLE_CODE(unpack_integer(value_csi_rsrp_cell, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (csi_rsrp_per_csi_rs_present) { - HANDLE_CODE(unpack_dyn_seq_of(csi_rsrp_per_csi_rs, bref, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_csi_rsrp_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("nR-PCI", nr_pci); - j.write_int("nR-ARFCN", nr_arfcn); - if (cgi_nr_present) { - j.write_fieldname("cGI-NR"); - cgi_nr.to_json(j); - } - if (value_csi_rsrp_cell_present) { - j.write_int("valueCSI-RSRP-Cell", value_csi_rsrp_cell); - } - if (csi_rsrp_per_csi_rs.size() > 0) { - j.start_array("cSI-RSRP-PerCSI-RS"); - for (const auto& e1 : csi_rsrp_per_csi_rs) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultCSI-RSRQ-Item ::= SEQUENCE -SRSASN_CODE result_csi_rsrq_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_nr_present, 1)); - HANDLE_CODE(bref.pack(value_csi_rsrq_cell_present, 1)); - HANDLE_CODE(bref.pack(csi_rsrq_per_csi_rs.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, nr_pci, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(pack_integer(bref, nr_arfcn, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.pack(bref)); - } - if (value_csi_rsrq_cell_present) { - HANDLE_CODE(pack_integer(bref, value_csi_rsrq_cell, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (csi_rsrq_per_csi_rs.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, csi_rsrq_per_csi_rs, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_csi_rsrq_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_nr_present, 1)); - HANDLE_CODE(bref.unpack(value_csi_rsrq_cell_present, 1)); - bool csi_rsrq_per_csi_rs_present; - HANDLE_CODE(bref.unpack(csi_rsrq_per_csi_rs_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(nr_pci, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(unpack_integer(nr_arfcn, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.unpack(bref)); - } - if (value_csi_rsrq_cell_present) { - HANDLE_CODE(unpack_integer(value_csi_rsrq_cell, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (csi_rsrq_per_csi_rs_present) { - HANDLE_CODE(unpack_dyn_seq_of(csi_rsrq_per_csi_rs, bref, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_csi_rsrq_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("nR-PCI", nr_pci); - j.write_int("nR-ARFCN", nr_arfcn); - if (cgi_nr_present) { - j.write_fieldname("cGI-NR"); - cgi_nr.to_json(j); - } - if (value_csi_rsrq_cell_present) { - j.write_int("valueCSI-RSRQ-Cell", value_csi_rsrq_cell); - } - if (csi_rsrq_per_csi_rs.size() > 0) { - j.start_array("cSI-RSRQ-PerCSI-RS"); - for (const auto& e1 : csi_rsrq_per_csi_rs) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultSS-RSRP-Item ::= SEQUENCE -SRSASN_CODE result_ss_rsrp_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_nr_present, 1)); - HANDLE_CODE(bref.pack(value_ss_rsrp_cell_present, 1)); - HANDLE_CODE(bref.pack(ss_rsrp_per_ssb.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, nr_pci, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(pack_integer(bref, nr_arfcn, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.pack(bref)); - } - if (value_ss_rsrp_cell_present) { - HANDLE_CODE(pack_integer(bref, value_ss_rsrp_cell, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (ss_rsrp_per_ssb.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ss_rsrp_per_ssb, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_ss_rsrp_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_nr_present, 1)); - HANDLE_CODE(bref.unpack(value_ss_rsrp_cell_present, 1)); - bool ss_rsrp_per_ssb_present; - HANDLE_CODE(bref.unpack(ss_rsrp_per_ssb_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(nr_pci, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(unpack_integer(nr_arfcn, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.unpack(bref)); - } - if (value_ss_rsrp_cell_present) { - HANDLE_CODE(unpack_integer(value_ss_rsrp_cell, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (ss_rsrp_per_ssb_present) { - HANDLE_CODE(unpack_dyn_seq_of(ss_rsrp_per_ssb, bref, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_ss_rsrp_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("nR-PCI", nr_pci); - j.write_int("nR-ARFCN", nr_arfcn); - if (cgi_nr_present) { - j.write_fieldname("cGI-NR"); - cgi_nr.to_json(j); - } - if (value_ss_rsrp_cell_present) { - j.write_int("valueSS-RSRP-Cell", value_ss_rsrp_cell); - } - if (ss_rsrp_per_ssb.size() > 0) { - j.start_array("sS-RSRP-PerSSB"); - for (const auto& e1 : ss_rsrp_per_ssb) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultSS-RSRQ-Item ::= SEQUENCE -SRSASN_CODE result_ss_rsrq_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_nr_present, 1)); - HANDLE_CODE(bref.pack(value_ss_rsrq_cell_present, 1)); - HANDLE_CODE(bref.pack(ss_rsrq_per_ssb.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, nr_pci, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(pack_integer(bref, nr_arfcn, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.pack(bref)); - } - if (value_ss_rsrq_cell_present) { - HANDLE_CODE(pack_integer(bref, value_ss_rsrq_cell, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (ss_rsrq_per_ssb.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ss_rsrq_per_ssb, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_ss_rsrq_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_nr_present, 1)); - HANDLE_CODE(bref.unpack(value_ss_rsrq_cell_present, 1)); - bool ss_rsrq_per_ssb_present; - HANDLE_CODE(bref.unpack(ss_rsrq_per_ssb_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(nr_pci, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(unpack_integer(nr_arfcn, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.unpack(bref)); - } - if (value_ss_rsrq_cell_present) { - HANDLE_CODE(unpack_integer(value_ss_rsrq_cell, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (ss_rsrq_per_ssb_present) { - HANDLE_CODE(unpack_dyn_seq_of(ss_rsrq_per_ssb, bref, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_ss_rsrq_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("nR-PCI", nr_pci); - j.write_int("nR-ARFCN", nr_arfcn); - if (cgi_nr_present) { - j.write_fieldname("cGI-NR"); - cgi_nr.to_json(j); - } - if (value_ss_rsrq_cell_present) { - j.write_int("valueSS-RSRQ-Cell", value_ss_rsrq_cell); - } - if (ss_rsrq_per_ssb.size() > 0) { - j.start_array("sS-RSRQ-PerSSB"); - for (const auto& e1 : ss_rsrq_per_ssb) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSResource ::= SEQUENCE -SRSASN_CODE srs_res_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(nrof_srs_ports.pack(bref)); - HANDLE_CODE(tx_comb.pack(bref)); - HANDLE_CODE(pack_integer(bref, start_position, (uint8_t)0u, (uint8_t)13u, false, true)); - HANDLE_CODE(nrof_symbols.pack(bref)); - HANDLE_CODE(repeat_factor.pack(bref)); - HANDLE_CODE(pack_integer(bref, freq_domain_position, (uint8_t)0u, (uint8_t)67u, false, true)); - HANDLE_CODE(pack_integer(bref, freq_domain_shift, (uint16_t)0u, (uint16_t)268u, false, true)); - HANDLE_CODE(pack_integer(bref, c_srs, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(pack_integer(bref, b_srs, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(pack_integer(bref, b_hop, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(group_or_seq_hop.pack(bref)); - HANDLE_CODE(res_type.pack(bref)); - HANDLE_CODE(pack_integer(bref, seq_id, (uint16_t)0u, (uint16_t)1023u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(nrof_srs_ports.unpack(bref)); - HANDLE_CODE(tx_comb.unpack(bref)); - HANDLE_CODE(unpack_integer(start_position, bref, (uint8_t)0u, (uint8_t)13u, false, true)); - HANDLE_CODE(nrof_symbols.unpack(bref)); - HANDLE_CODE(repeat_factor.unpack(bref)); - HANDLE_CODE(unpack_integer(freq_domain_position, bref, (uint8_t)0u, (uint8_t)67u, false, true)); - HANDLE_CODE(unpack_integer(freq_domain_shift, bref, (uint16_t)0u, (uint16_t)268u, false, true)); - HANDLE_CODE(unpack_integer(c_srs, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - HANDLE_CODE(unpack_integer(b_srs, bref, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(unpack_integer(b_hop, bref, (uint8_t)0u, (uint8_t)3u, false, true)); - HANDLE_CODE(group_or_seq_hop.unpack(bref)); - HANDLE_CODE(res_type.unpack(bref)); - HANDLE_CODE(unpack_integer(seq_id, bref, (uint16_t)0u, (uint16_t)1023u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srs_res_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResourceID", srs_res_id); - j.write_str("nrofSRS-Ports", nrof_srs_ports.to_string()); - j.write_fieldname("transmissionComb"); - tx_comb.to_json(j); - j.write_int("startPosition", start_position); - j.write_str("nrofSymbols", nrof_symbols.to_string()); - j.write_str("repetitionFactor", repeat_factor.to_string()); - j.write_int("freqDomainPosition", freq_domain_position); - j.write_int("freqDomainShift", freq_domain_shift); - j.write_int("c-SRS", c_srs); - j.write_int("b-SRS", b_srs); - j.write_int("b-hop", b_hop); - j.write_str("groupOrSequenceHopping", group_or_seq_hop.to_string()); - j.write_fieldname("resourceType"); - res_type.to_json(j); - j.write_int("sequenceId", seq_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* srs_res_s::nrof_srs_ports_opts::to_string() const -{ - static const char* names[] = {"port1", "ports2", "ports4"}; - return convert_enum_idx(names, 3, value, "srs_res_s::nrof_srs_ports_e_"); -} -uint8_t srs_res_s::nrof_srs_ports_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4}; - return map_enum_number(numbers, 3, value, "srs_res_s::nrof_srs_ports_e_"); -} - -const char* srs_res_s::nrof_symbols_opts::to_string() const -{ - static const char* names[] = {"n1", "n2", "n4"}; - return convert_enum_idx(names, 3, value, "srs_res_s::nrof_symbols_e_"); -} -uint8_t srs_res_s::nrof_symbols_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4}; - return map_enum_number(numbers, 3, value, "srs_res_s::nrof_symbols_e_"); -} - -const char* srs_res_s::repeat_factor_opts::to_string() const -{ - static const char* names[] = {"n1", "n2", "n4"}; - return convert_enum_idx(names, 3, value, "srs_res_s::repeat_factor_e_"); -} -uint8_t srs_res_s::repeat_factor_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4}; - return map_enum_number(numbers, 3, value, "srs_res_s::repeat_factor_e_"); -} - -const char* srs_res_s::group_or_seq_hop_opts::to_string() const -{ - static const char* names[] = {"neither", "groupHopping", "sequenceHopping"}; - return convert_enum_idx(names, 3, value, "srs_res_s::group_or_seq_hop_e_"); -} - -// SRSResourceSet ::= SEQUENCE -SRSASN_CODE srs_res_set_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_res_set_id, (uint8_t)0u, (uint8_t)15u, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, srs_res_id_list, 1, 16, integer_packer(0, 63, false, true))); - HANDLE_CODE(res_set_type.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_set_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_res_set_id, bref, (uint8_t)0u, (uint8_t)15u, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(srs_res_id_list, bref, 1, 16, integer_packer(0, 63, false, true))); - HANDLE_CODE(res_set_type.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srs_res_set_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResourceSetID", srs_res_set_id); - j.start_array("sRSResourceID-List"); - for (const auto& e1 : srs_res_id_list) { - j.write_int(e1); - } - j.end_array(); - j.write_fieldname("resourceSetType"); - res_set_type.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SSBInfoItem ::= SEQUENCE -SRSASN_CODE ssb_info_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(ssb_cfg.pack(bref)); - HANDLE_CODE(pack_integer(bref, pci_nr, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ssb_info_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(ssb_cfg.unpack(bref)); - HANDLE_CODE(unpack_integer(pci_nr, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ssb_info_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("sSB-Configuration"); - ssb_cfg.to_json(j); - j.write_int("pCI-NR", pci_nr); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TDD-Config-EUTRA-Item ::= SEQUENCE -SRSASN_CODE tdd_cfg_eutra_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(sf_assign.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE tdd_cfg_eutra_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(sf_assign.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void tdd_cfg_eutra_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("subframeAssignment", sf_assign.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* tdd_cfg_eutra_item_s::sf_assign_opts::to_string() const -{ - static const char* names[] = {"sa0", "sa1", "sa2", "sa3", "sa4", "sa5", "sa6"}; - return convert_enum_idx(names, 7, value, "tdd_cfg_eutra_item_s::sf_assign_e_"); -} -uint8_t tdd_cfg_eutra_item_s::sf_assign_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 1, 2, 3, 4, 5, 6}; - return map_enum_number(numbers, 7, value, "tdd_cfg_eutra_item_s::sf_assign_e_"); -} - -// TRPInformationTypeResponseItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t trp_info_type_resp_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {62, 68, 84, 93}; - return map_enum_number(names, 4, idx, "id"); -} -bool trp_info_type_resp_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {62, 68, 84, 93}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_info_type_resp_item_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 62: - return crit_e::reject; - case 68: - return crit_e::reject; - case 84: - return crit_e::reject; - case 93: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_info_type_resp_item_ext_ies_o::value_c trp_info_type_resp_item_ext_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 62: - ret.set(value_c::types::trp_type); - break; - case 68: - ret.set(value_c::types::on_demand_prs); - break; - case 84: - ret.set(value_c::types::trp_tx_teg_assoc); - break; - case 93: - ret.set(value_c::types::trp_beam_ant_info); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_info_type_resp_item_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 62: - return presence_e::mandatory; - case 68: - return presence_e::mandatory; - case 84: - return presence_e::mandatory; - case 93: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void trp_info_type_resp_item_ext_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::trp_type: - c = trp_type_e{}; - break; - case types::on_demand_prs: - c = on_demand_prs_info_s{}; - break; - case types::trp_tx_teg_assoc: - c = trp_tx_teg_assoc_l{}; - break; - case types::trp_beam_ant_info: - c = trp_beam_ant_info_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_ext_ies_o::value_c"); - } -} -trp_type_e& trp_info_type_resp_item_ext_ies_o::value_c::trp_type() -{ - assert_choice_type(types::trp_type, type_, "Value"); - return c.get(); -} -on_demand_prs_info_s& trp_info_type_resp_item_ext_ies_o::value_c::on_demand_prs() -{ - assert_choice_type(types::on_demand_prs, type_, "Value"); - return c.get(); -} -trp_tx_teg_assoc_l& trp_info_type_resp_item_ext_ies_o::value_c::trp_tx_teg_assoc() -{ - assert_choice_type(types::trp_tx_teg_assoc, type_, "Value"); - return c.get(); -} -trp_beam_ant_info_s& trp_info_type_resp_item_ext_ies_o::value_c::trp_beam_ant_info() -{ - assert_choice_type(types::trp_beam_ant_info, type_, "Value"); - return c.get(); -} -const trp_type_e& trp_info_type_resp_item_ext_ies_o::value_c::trp_type() const -{ - assert_choice_type(types::trp_type, type_, "Value"); - return c.get(); -} -const on_demand_prs_info_s& trp_info_type_resp_item_ext_ies_o::value_c::on_demand_prs() const -{ - assert_choice_type(types::on_demand_prs, type_, "Value"); - return c.get(); -} -const trp_tx_teg_assoc_l& trp_info_type_resp_item_ext_ies_o::value_c::trp_tx_teg_assoc() const -{ - assert_choice_type(types::trp_tx_teg_assoc, type_, "Value"); - return c.get(); -} -const trp_beam_ant_info_s& trp_info_type_resp_item_ext_ies_o::value_c::trp_beam_ant_info() const -{ - assert_choice_type(types::trp_beam_ant_info, type_, "Value"); - return c.get(); -} -void trp_info_type_resp_item_ext_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::trp_type: - j.write_str("TRPType", c.get().to_string()); - break; - case types::on_demand_prs: - j.write_fieldname("OnDemandPRS-Info"); - c.get().to_json(j); - break; - case types::trp_tx_teg_assoc: - j.start_array("TRPTxTEGAssociation"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::trp_beam_ant_info: - j.write_fieldname("TRPBeamAntennaInformation"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_ext_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_info_type_resp_item_ext_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::trp_type: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::on_demand_prs: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_tx_teg_assoc: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::trp_beam_ant_info: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_ext_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_type_resp_item_ext_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::trp_type: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::on_demand_prs: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_tx_teg_assoc: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::trp_beam_ant_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_ext_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_info_type_resp_item_ext_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"TRPType", "OnDemandPRS-Info", "TRPTxTEGAssociation", "TRPBeamAntennaInformation"}; - return convert_enum_idx(names, 4, value, "trp_info_type_resp_item_ext_ies_o::value_c::types"); -} - -// TrpMeasurementResultItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t trp_meas_result_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {76, 79, 80}; - return map_enum_number(names, 3, idx, "id"); -} -bool trp_meas_result_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {76, 79, 80}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_meas_result_item_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 76: - return crit_e::ignore; - case 79: - return crit_e::ignore; - case 80: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_meas_result_item_ext_ies_o::ext_c trp_meas_result_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 76: - ret.set(ext_c::types::srs_restype); - break; - case 79: - ret.set(ext_c::types::arp_id); - break; - case 80: - ret.set(ext_c::types::lo_s_n_lo_si_nformation); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_meas_result_item_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 76: - return presence_e::optional; - case 79: - return presence_e::optional; - case 80: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void trp_meas_result_item_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::srs_restype: - c = srs_restype_s{}; - break; - case types::arp_id: - c = uint8_t{}; - break; - case types::lo_s_n_lo_si_nformation: - c = lo_s_n_lo_si_nformation_c{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_meas_result_item_ext_ies_o::ext_c"); - } -} -srs_restype_s& trp_meas_result_item_ext_ies_o::ext_c::srs_restype() -{ - assert_choice_type(types::srs_restype, type_, "Extension"); - return c.get(); -} -uint8_t& trp_meas_result_item_ext_ies_o::ext_c::arp_id() -{ - assert_choice_type(types::arp_id, type_, "Extension"); - return c.get(); -} -lo_s_n_lo_si_nformation_c& trp_meas_result_item_ext_ies_o::ext_c::lo_s_n_lo_si_nformation() -{ - assert_choice_type(types::lo_s_n_lo_si_nformation, type_, "Extension"); - return c.get(); -} -const srs_restype_s& trp_meas_result_item_ext_ies_o::ext_c::srs_restype() const -{ - assert_choice_type(types::srs_restype, type_, "Extension"); - return c.get(); -} -const uint8_t& trp_meas_result_item_ext_ies_o::ext_c::arp_id() const -{ - assert_choice_type(types::arp_id, type_, "Extension"); - return c.get(); -} -const lo_s_n_lo_si_nformation_c& trp_meas_result_item_ext_ies_o::ext_c::lo_s_n_lo_si_nformation() const -{ - assert_choice_type(types::lo_s_n_lo_si_nformation, type_, "Extension"); - return c.get(); -} -void trp_meas_result_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::srs_restype: - j.write_fieldname("SRSResourcetype"); - c.get().to_json(j); - break; - case types::arp_id: - j.write_int("INTEGER (1..16,...)", c.get()); - break; - case types::lo_s_n_lo_si_nformation: - j.write_fieldname("LoS-NLoSInformation"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_meas_result_item_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_meas_result_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::srs_restype: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::arp_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)16u, true, true)); - break; - case types::lo_s_n_lo_si_nformation: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_result_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_result_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::srs_restype: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::arp_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)16u, true, true)); - break; - case types::lo_s_n_lo_si_nformation: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_result_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_meas_result_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"SRSResourcetype", "INTEGER (1..16,...)", "LoS-NLoSInformation"}; - return convert_enum_idx(names, 3, value, "trp_meas_result_item_ext_ies_o::ext_c::types"); -} -uint8_t trp_meas_result_item_ext_ies_o::ext_c::types_opts::to_number() const -{ - if (value == arp_id) { - return 1; - } - invalid_enum_number(value, "trp_meas_result_item_ext_ies_o::ext_c::types"); - return 0; -} - -// TrpMeasuredResultsValue-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t trp_measured_results_value_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {71, 74, 75}; - return map_enum_number(names, 3, idx, "id"); -} -bool trp_measured_results_value_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {71, 74, 75}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_measured_results_value_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 71: - return crit_e::reject; - case 74: - return crit_e::reject; - case 75: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_measured_results_value_ext_ies_o::value_c trp_measured_results_value_ext_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 71: - ret.set(value_c::types::zo_a); - break; - case 74: - ret.set(value_c::types::multiple_ul_ao_a); - break; - case 75: - ret.set(value_c::types::ul_srs_rsrp_p); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_measured_results_value_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 71: - return presence_e::mandatory; - case 74: - return presence_e::mandatory; - case 75: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void trp_measured_results_value_ext_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::zo_a: - c = zo_a_s{}; - break; - case types::multiple_ul_ao_a: - c = multiple_ul_ao_a_s{}; - break; - case types::ul_srs_rsrp_p: - c = ul_srs_rsrp_p_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_ext_ies_o::value_c"); - } -} -zo_a_s& trp_measured_results_value_ext_ies_o::value_c::zo_a() -{ - assert_choice_type(types::zo_a, type_, "Value"); - return c.get(); -} -multiple_ul_ao_a_s& trp_measured_results_value_ext_ies_o::value_c::multiple_ul_ao_a() -{ - assert_choice_type(types::multiple_ul_ao_a, type_, "Value"); - return c.get(); -} -ul_srs_rsrp_p_s& trp_measured_results_value_ext_ies_o::value_c::ul_srs_rsrp_p() -{ - assert_choice_type(types::ul_srs_rsrp_p, type_, "Value"); - return c.get(); -} -const zo_a_s& trp_measured_results_value_ext_ies_o::value_c::zo_a() const -{ - assert_choice_type(types::zo_a, type_, "Value"); - return c.get(); -} -const multiple_ul_ao_a_s& trp_measured_results_value_ext_ies_o::value_c::multiple_ul_ao_a() const -{ - assert_choice_type(types::multiple_ul_ao_a, type_, "Value"); - return c.get(); -} -const ul_srs_rsrp_p_s& trp_measured_results_value_ext_ies_o::value_c::ul_srs_rsrp_p() const -{ - assert_choice_type(types::ul_srs_rsrp_p, type_, "Value"); - return c.get(); -} -void trp_measured_results_value_ext_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::zo_a: - j.write_fieldname("ZoA"); - c.get().to_json(j); - break; - case types::multiple_ul_ao_a: - j.write_fieldname("MultipleULAoA"); - c.get().to_json(j); - break; - case types::ul_srs_rsrp_p: - j.write_fieldname("UL-SRS-RSRPP"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_ext_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_measured_results_value_ext_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::zo_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::multiple_ul_ao_a: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ul_srs_rsrp_p: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_ext_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_measured_results_value_ext_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::zo_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::multiple_ul_ao_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ul_srs_rsrp_p: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_ext_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_measured_results_value_ext_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"ZoA", "MultipleULAoA", "UL-SRS-RSRPP"}; - return convert_enum_idx(names, 3, value, "trp_measured_results_value_ext_ies_o::value_c::types"); -} - -// TRPPositionDefinitionType ::= CHOICE -void trp_position_definition_type_c::destroy_() -{ - switch (type_) { - case types::direct: - c.destroy(); - break; - case types::refd: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trp_position_definition_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::direct: - c.init(); - break; - case types::refd: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_position_definition_type_c"); - } -} -trp_position_definition_type_c::trp_position_definition_type_c(const trp_position_definition_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::direct: - c.init(other.c.get()); - break; - case types::refd: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_position_definition_type_c"); - } -} -trp_position_definition_type_c& trp_position_definition_type_c::operator=(const trp_position_definition_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::direct: - c.set(other.c.get()); - break; - case types::refd: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_position_definition_type_c"); - } - - return *this; -} -trp_position_direct_s& trp_position_definition_type_c::set_direct() -{ - set(types::direct); - return c.get(); -} -trp_position_refd_s& trp_position_definition_type_c::set_refd() -{ - set(types::refd); - return c.get(); -} -protocol_ie_single_container_s& trp_position_definition_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trp_position_definition_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::direct: - j.write_fieldname("direct"); - c.get().to_json(j); - break; - case types::refd: - j.write_fieldname("referenced"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_position_definition_type_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_position_definition_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::direct: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::refd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_position_definition_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_position_definition_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::direct: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::refd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_position_definition_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_position_definition_type_c::types_opts::to_string() const -{ - static const char* names[] = {"direct", "referenced", "choice-extension"}; - return convert_enum_idx(names, 3, value, "trp_position_definition_type_c::types"); -} - -// ULRTOAMeas ::= CHOICE -void ul_rtoa_meas_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void ul_rtoa_meas_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::k0: - break; - case types::k1: - break; - case types::k2: - break; - case types::k3: - break; - case types::k4: - break; - case types::k5: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ul_rtoa_meas_c"); - } -} -ul_rtoa_meas_c::ul_rtoa_meas_c(const ul_rtoa_meas_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::k0: - c.init(other.c.get()); - break; - case types::k1: - c.init(other.c.get()); - break; - case types::k2: - c.init(other.c.get()); - break; - case types::k3: - c.init(other.c.get()); - break; - case types::k4: - c.init(other.c.get()); - break; - case types::k5: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ul_rtoa_meas_c"); - } -} -ul_rtoa_meas_c& ul_rtoa_meas_c::operator=(const ul_rtoa_meas_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::k0: - c.set(other.c.get()); - break; - case types::k1: - c.set(other.c.get()); - break; - case types::k2: - c.set(other.c.get()); - break; - case types::k3: - c.set(other.c.get()); - break; - case types::k4: - c.set(other.c.get()); - break; - case types::k5: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ul_rtoa_meas_c"); - } - - return *this; -} -uint32_t& ul_rtoa_meas_c::set_k0() -{ - set(types::k0); - return c.get(); -} -uint32_t& ul_rtoa_meas_c::set_k1() -{ - set(types::k1); - return c.get(); -} -uint32_t& ul_rtoa_meas_c::set_k2() -{ - set(types::k2); - return c.get(); -} -uint32_t& ul_rtoa_meas_c::set_k3() -{ - set(types::k3); - return c.get(); -} -uint32_t& ul_rtoa_meas_c::set_k4() -{ - set(types::k4); - return c.get(); -} -uint16_t& ul_rtoa_meas_c::set_k5() -{ - set(types::k5); - return c.get(); -} -protocol_ie_single_container_s& ul_rtoa_meas_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void ul_rtoa_meas_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::k0: - j.write_int("k0", c.get()); - break; - case types::k1: - j.write_int("k1", c.get()); - break; - case types::k2: - j.write_int("k2", c.get()); - break; - case types::k3: - j.write_int("k3", c.get()); - break; - case types::k4: - j.write_int("k4", c.get()); - break; - case types::k5: - j.write_int("k5", c.get()); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "ul_rtoa_meas_c"); - } - j.end_obj(); -} -SRSASN_CODE ul_rtoa_meas_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::k0: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)1970049u, false, true)); - break; - case types::k1: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)985025u, false, true)); - break; - case types::k2: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)492513u, false, true)); - break; - case types::k3: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)246257u, false, true)); - break; - case types::k4: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)123129u, false, true)); - break; - case types::k5: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)61565u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "ul_rtoa_meas_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE ul_rtoa_meas_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::k0: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)1970049u, false, true)); - break; - case types::k1: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)985025u, false, true)); - break; - case types::k2: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)492513u, false, true)); - break; - case types::k3: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)246257u, false, true)); - break; - case types::k4: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)123129u, false, true)); - break; - case types::k5: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)61565u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "ul_rtoa_meas_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* ul_rtoa_meas_c::types_opts::to_string() const -{ - static const char* names[] = {"k0", "k1", "k2", "k3", "k4", "k5", "choice-extension"}; - return convert_enum_idx(names, 7, value, "ul_rtoa_meas_c::types"); -} -uint8_t ul_rtoa_meas_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 1, 2, 3, 4, 5}; - return map_enum_number(numbers, 6, value, "ul_rtoa_meas_c::types"); -} - -SRSASN_CODE ul_rtoameas_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += extended_add_path_list_present ? 1 : 0; - nof_ies += trp_rx_teg_info_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (extended_add_path_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)77, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, extended_add_path_list, 1, 8, true)); - } - if (trp_rx_teg_info_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)86, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(trp_rx_teg_info.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ul_rtoameas_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 77: { - extended_add_path_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(extended_add_path_list, bref, 1, 8, true)); - break; - } - case 86: { - trp_rx_teg_info_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(trp_rx_teg_info.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void ul_rtoameas_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (extended_add_path_list_present) { - j.write_int("id", 77); - j.write_str("criticality", "ignore"); - j.start_array("Extension"); - for (const auto& e1 : extended_add_path_list) { - e1.to_json(j); - } - j.end_array(); - } - if (trp_rx_teg_info_present) { - j.write_int("id", 86); - j.write_str("criticality", "ignore"); - trp_rx_teg_info.to_json(j); - } - j.end_obj(); -} - -// AoA-AssistanceInfo ::= SEQUENCE -SRSASN_CODE ao_a_assist_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(angle_meas.pack(bref)); - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ao_a_assist_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(lcs_to_gcs_translation_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(angle_meas.unpack(bref)); - if (lcs_to_gcs_translation_present) { - HANDLE_CODE(lcs_to_gcs_translation.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ao_a_assist_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("angleMeasurement"); - angle_meas.to_json(j); - if (lcs_to_gcs_translation_present) { - j.write_fieldname("lCS-to-GCS-Translation"); - lcs_to_gcs_translation.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// AssistanceInformationMetaData ::= SEQUENCE -SRSASN_CODE assist_info_meta_data_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(encrypted_present, 1)); - HANDLE_CODE(bref.pack(gns_si_d_present, 1)); - HANDLE_CODE(bref.pack(sba_si_d_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (encrypted_present) { - HANDLE_CODE(encrypted.pack(bref)); - } - if (gns_si_d_present) { - HANDLE_CODE(gns_si_d.pack(bref)); - } - if (sba_si_d_present) { - HANDLE_CODE(sba_si_d.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_meta_data_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(encrypted_present, 1)); - HANDLE_CODE(bref.unpack(gns_si_d_present, 1)); - HANDLE_CODE(bref.unpack(sba_si_d_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (encrypted_present) { - HANDLE_CODE(encrypted.unpack(bref)); - } - if (gns_si_d_present) { - HANDLE_CODE(gns_si_d.unpack(bref)); - } - if (sba_si_d_present) { - HANDLE_CODE(sba_si_d.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void assist_info_meta_data_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (encrypted_present) { - j.write_str("encrypted", "true"); - } - if (gns_si_d_present) { - j.write_str("gNSSID", gns_si_d.to_string()); - } - if (sba_si_d_present) { - j.write_str("sBASID", sba_si_d.to_string()); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* assist_info_meta_data_s::encrypted_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "assist_info_meta_data_s::encrypted_e_"); -} - -const char* assist_info_meta_data_s::gns_si_d_opts::to_string() const -{ - static const char* names[] = {"gps", "sbas", "qzss", "galileo", "glonass", "bds", "navic"}; - return convert_enum_idx(names, 7, value, "assist_info_meta_data_s::gns_si_d_e_"); -} - -const char* assist_info_meta_data_s::sba_si_d_opts::to_string() const -{ - static const char* names[] = {"waas", "egnos", "msas", "gagan"}; - return convert_enum_idx(names, 4, value, "assist_info_meta_data_s::sba_si_d_e_"); -} - -// GeographicalCoordinates ::= SEQUENCE -SRSASN_CODE geographical_coordinates_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(dl_prs_res_coordinates_present, 1)); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - HANDLE_CODE(trp_position_definition_type.pack(bref)); - if (dl_prs_res_coordinates_present) { - HANDLE_CODE(dl_prs_res_coordinates.pack(bref)); - } - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE geographical_coordinates_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(dl_prs_res_coordinates_present, 1)); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(trp_position_definition_type.unpack(bref)); - if (dl_prs_res_coordinates_present) { - HANDLE_CODE(dl_prs_res_coordinates.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void geographical_coordinates_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("tRPPositionDefinitionType"); - trp_position_definition_type.to_json(j); - if (dl_prs_res_coordinates_present) { - j.write_fieldname("dLPRSResourceCoordinates"); - dl_prs_res_coordinates.to_json(j); - } - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -// GNB-RxTxTimeDiff ::= SEQUENCE -SRSASN_CODE gnb_rx_tx_time_diff_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(add_path_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(rx_tx_time_diff.pack(bref)); - if (add_path_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, add_path_list, 1, 2, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE gnb_rx_tx_time_diff_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool add_path_list_present; - HANDLE_CODE(bref.unpack(add_path_list_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(rx_tx_time_diff.unpack(bref)); - if (add_path_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(add_path_list, bref, 1, 2, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void gnb_rx_tx_time_diff_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("rxTxTimeDiff"); - rx_tx_time_diff.to_json(j); - if (add_path_list.size() > 0) { - j.start_array("additionalPathList"); - for (const auto& e1 : add_path_list) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// NumberOfFrequencyHoppingBands ::= ENUMERATED -const char* nof_freq_hop_bands_opts::to_string() const -{ - static const char* names[] = {"twobands", "fourbands"}; - return convert_enum_idx(names, 2, value, "nof_freq_hop_bands_e"); -} -uint8_t nof_freq_hop_bands_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4}; - return map_enum_number(numbers, 2, value, "nof_freq_hop_bands_e"); -} - -// NumberOfTRPRxTEG ::= ENUMERATED -const char* nof_trp_rx_teg_opts::to_string() const -{ - static const char* names[] = {"two", "three", "four", "six", "eight"}; - return convert_enum_idx(names, 5, value, "nof_trp_rx_teg_e"); -} -uint8_t nof_trp_rx_teg_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 3, 4, 6, 8}; - return map_enum_number(numbers, 5, value, "nof_trp_rx_teg_e"); -} - -// NumberOfTRPRxTxTEG ::= ENUMERATED -const char* nof_trp_rx_tx_teg_opts::to_string() const -{ - static const char* names[] = {"two", "three", "four", "six", "eight"}; - return convert_enum_idx(names, 5, value, "nof_trp_rx_tx_teg_e"); -} -uint8_t nof_trp_rx_tx_teg_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 3, 4, 6, 8}; - return map_enum_number(numbers, 5, value, "nof_trp_rx_tx_teg_e"); -} - -// OTDOACell-Information-Item-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t otdoa_cell_info_item_ext_ie_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {22, 58, 59}; - return map_enum_number(names, 3, idx, "id"); -} -bool otdoa_cell_info_item_ext_ie_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {22, 58, 59}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e otdoa_cell_info_item_ext_ie_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 22: - return crit_e::ignore; - case 58: - return crit_e::ignore; - case 59: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -otdoa_cell_info_item_ext_ie_o::value_c otdoa_cell_info_item_ext_ie_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 22: - ret.set(value_c::types::tdd_cfg_eutra_item); - break; - case 58: - ret.set(value_c::types::cgi_nr); - break; - case 59: - ret.set(value_c::types::sfn_initisation_time_nr); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e otdoa_cell_info_item_ext_ie_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 22: - return presence_e::mandatory; - case 58: - return presence_e::mandatory; - case 59: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void otdoa_cell_info_item_ext_ie_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::tdd_cfg_eutra_item: - c = tdd_cfg_eutra_item_s{}; - break; - case types::cgi_nr: - c = cgi_nr_s{}; - break; - case types::sfn_initisation_time_nr: - c = fixed_bitstring<64, false, true>{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_ext_ie_o::value_c"); - } -} -tdd_cfg_eutra_item_s& otdoa_cell_info_item_ext_ie_o::value_c::tdd_cfg_eutra_item() -{ - assert_choice_type(types::tdd_cfg_eutra_item, type_, "Value"); - return c.get(); -} -cgi_nr_s& otdoa_cell_info_item_ext_ie_o::value_c::cgi_nr() -{ - assert_choice_type(types::cgi_nr, type_, "Value"); - return c.get(); -} -fixed_bitstring<64, false, true>& otdoa_cell_info_item_ext_ie_o::value_c::sfn_initisation_time_nr() -{ - assert_choice_type(types::sfn_initisation_time_nr, type_, "Value"); - return c.get>(); -} -const tdd_cfg_eutra_item_s& otdoa_cell_info_item_ext_ie_o::value_c::tdd_cfg_eutra_item() const -{ - assert_choice_type(types::tdd_cfg_eutra_item, type_, "Value"); - return c.get(); -} -const cgi_nr_s& otdoa_cell_info_item_ext_ie_o::value_c::cgi_nr() const -{ - assert_choice_type(types::cgi_nr, type_, "Value"); - return c.get(); -} -const fixed_bitstring<64, false, true>& otdoa_cell_info_item_ext_ie_o::value_c::sfn_initisation_time_nr() const -{ - assert_choice_type(types::sfn_initisation_time_nr, type_, "Value"); - return c.get>(); -} -void otdoa_cell_info_item_ext_ie_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::tdd_cfg_eutra_item: - j.write_fieldname("TDD-Config-EUTRA-Item"); - c.get().to_json(j); - break; - case types::cgi_nr: - j.write_fieldname("CGI-NR"); - c.get().to_json(j); - break; - case types::sfn_initisation_time_nr: - j.write_str("BIT STRING", c.get>().to_string()); - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_ext_ie_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE otdoa_cell_info_item_ext_ie_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::tdd_cfg_eutra_item: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::cgi_nr: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sfn_initisation_time_nr: - HANDLE_CODE((c.get>().pack(bref))); - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_ext_ie_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_cell_info_item_ext_ie_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::tdd_cfg_eutra_item: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::cgi_nr: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sfn_initisation_time_nr: - HANDLE_CODE((c.get>().unpack(bref))); - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_ext_ie_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* otdoa_cell_info_item_ext_ie_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"TDD-Config-EUTRA-Item", "CGI-NR", "BIT STRING"}; - return convert_enum_idx(names, 3, value, "otdoa_cell_info_item_ext_ie_o::value_c::types"); -} - -// PosSIB-Type ::= ENUMERATED -const char* pos_sib_type_opts::to_string() const -{ - static const char* names[] = { - "posSibType1-1", "posSibType1-2", "posSibType1-3", "posSibType1-4", "posSibType1-5", "posSibType1-6", - "posSibType1-7", "posSibType1-8", "posSibType2-1", "posSibType2-2", "posSibType2-3", "posSibType2-4", - "posSibType2-5", "posSibType2-6", "posSibType2-7", "posSibType2-8", "posSibType2-9", "posSibType2-10", - "posSibType2-11", "posSibType2-12", "posSibType2-13", "posSibType2-14", "posSibType2-15", "posSibType2-16", - "posSibType2-17", "posSibType2-18", "posSibType2-19", "posSibType2-20", "posSibType2-21", "posSibType2-22", - "posSibType2-23", "posSibType2-24", "posSibType2-25", "posSibType3-1", "posSibType4-1", "posSibType5-1", - "posSibType6-1", "posSibType6-2", "posSibType6-3", "posSibType1-9", "posSibType1-10", "posSibType6-4", - "posSibType6-5", "posSibType6-6"}; - return convert_enum_idx(names, 44, value, "pos_sib_type_e"); -} - -template struct asn1::protocol_ext_field_s; - -template struct asn1::protocol_ie_single_container_s; - -template struct asn1::protocol_ie_single_container_s; - -// PRSConfiguration ::= SEQUENCE -SRSASN_CODE prs_cfg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, prs_res_set_list, 1, 8, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(prs_res_set_list, bref, 1, 8, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_cfg_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("pRSResourceSet-List"); - for (const auto& e1 : prs_res_set_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSTransmissionOffPerResource-Item ::= SEQUENCE -SRSASN_CODE prs_tx_off_per_res_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, prs_tx_off_ind_per_res_list, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_tx_off_per_res_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(prs_tx_off_ind_per_res_list, bref, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_tx_off_per_res_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRSResourceSetID", prs_res_set_id); - j.start_array("pRSTransmissionOffIndicationPerResourceList"); - for (const auto& e1 : prs_tx_off_ind_per_res_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSTransmissionOffPerResourceSet-Item ::= SEQUENCE -SRSASN_CODE prs_tx_off_per_res_set_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_tx_off_per_res_set_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_tx_off_per_res_set_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pRSResourceSetID", prs_res_set_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultEUTRA-Item ::= SEQUENCE -SRSASN_CODE result_eutra_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(value_rsrp_eutra_present, 1)); - HANDLE_CODE(bref.pack(value_rsrq_eutra_present, 1)); - HANDLE_CODE(bref.pack(cgi_eutra_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, pci_eutra, (uint16_t)0u, (uint16_t)503u, true, true)); - HANDLE_CODE(pack_integer(bref, earfcn, (uint32_t)0u, (uint32_t)262143u, true, true)); - if (value_rsrp_eutra_present) { - HANDLE_CODE(pack_integer(bref, value_rsrp_eutra, (uint8_t)0u, (uint8_t)97u, true, true)); - } - if (value_rsrq_eutra_present) { - HANDLE_CODE(pack_integer(bref, value_rsrq_eutra, (uint8_t)0u, (uint8_t)34u, true, true)); - } - if (cgi_eutra_present) { - HANDLE_CODE(cgi_eutra.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_eutra_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(value_rsrp_eutra_present, 1)); - HANDLE_CODE(bref.unpack(value_rsrq_eutra_present, 1)); - HANDLE_CODE(bref.unpack(cgi_eutra_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(pci_eutra, bref, (uint16_t)0u, (uint16_t)503u, true, true)); - HANDLE_CODE(unpack_integer(earfcn, bref, (uint32_t)0u, (uint32_t)262143u, true, true)); - if (value_rsrp_eutra_present) { - HANDLE_CODE(unpack_integer(value_rsrp_eutra, bref, (uint8_t)0u, (uint8_t)97u, true, true)); - } - if (value_rsrq_eutra_present) { - HANDLE_CODE(unpack_integer(value_rsrq_eutra, bref, (uint8_t)0u, (uint8_t)34u, true, true)); - } - if (cgi_eutra_present) { - HANDLE_CODE(cgi_eutra.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_eutra_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pCI-EUTRA", pci_eutra); - j.write_int("eARFCN", earfcn); - if (value_rsrp_eutra_present) { - j.write_int("valueRSRP-EUTRA", value_rsrp_eutra); - } - if (value_rsrq_eutra_present) { - j.write_int("valueRSRQ-EUTRA", value_rsrq_eutra); - } - if (cgi_eutra_present) { - j.write_fieldname("cGI-EUTRA"); - cgi_eutra.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultNR-Item ::= SEQUENCE -SRSASN_CODE result_nr_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(value_ss_rsrp_cell_present, 1)); - HANDLE_CODE(bref.pack(value_ss_rsrq_cell_present, 1)); - HANDLE_CODE(bref.pack(ss_rsrp_per_ssb.size() > 0, 1)); - HANDLE_CODE(bref.pack(ss_rsrq_per_ssb.size() > 0, 1)); - HANDLE_CODE(bref.pack(cgi_nr_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, nr_pci, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(pack_integer(bref, nr_arfcn, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (value_ss_rsrp_cell_present) { - HANDLE_CODE(pack_integer(bref, value_ss_rsrp_cell, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (value_ss_rsrq_cell_present) { - HANDLE_CODE(pack_integer(bref, value_ss_rsrq_cell, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (ss_rsrp_per_ssb.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ss_rsrp_per_ssb, 1, 64, true)); - } - if (ss_rsrq_per_ssb.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ss_rsrq_per_ssb, 1, 64, true)); - } - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_nr_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(value_ss_rsrp_cell_present, 1)); - HANDLE_CODE(bref.unpack(value_ss_rsrq_cell_present, 1)); - bool ss_rsrp_per_ssb_present; - HANDLE_CODE(bref.unpack(ss_rsrp_per_ssb_present, 1)); - bool ss_rsrq_per_ssb_present; - HANDLE_CODE(bref.unpack(ss_rsrq_per_ssb_present, 1)); - HANDLE_CODE(bref.unpack(cgi_nr_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(nr_pci, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - HANDLE_CODE(unpack_integer(nr_arfcn, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - if (value_ss_rsrp_cell_present) { - HANDLE_CODE(unpack_integer(value_ss_rsrp_cell, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (value_ss_rsrq_cell_present) { - HANDLE_CODE(unpack_integer(value_ss_rsrq_cell, bref, (uint8_t)0u, (uint8_t)127u, false, true)); - } - if (ss_rsrp_per_ssb_present) { - HANDLE_CODE(unpack_dyn_seq_of(ss_rsrp_per_ssb, bref, 1, 64, true)); - } - if (ss_rsrq_per_ssb_present) { - HANDLE_CODE(unpack_dyn_seq_of(ss_rsrq_per_ssb, bref, 1, 64, true)); - } - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_nr_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("nR-PCI", nr_pci); - j.write_int("nR-ARFCN", nr_arfcn); - if (value_ss_rsrp_cell_present) { - j.write_int("valueSS-RSRP-Cell", value_ss_rsrp_cell); - } - if (value_ss_rsrq_cell_present) { - j.write_int("valueSS-RSRQ-Cell", value_ss_rsrq_cell); - } - if (ss_rsrp_per_ssb.size() > 0) { - j.start_array("sS-RSRP-PerSSB"); - for (const auto& e1 : ss_rsrp_per_ssb) { - e1.to_json(j); - } - j.end_array(); - } - if (ss_rsrq_per_ssb.size() > 0) { - j.start_array("sS-RSRQ-PerSSB"); - for (const auto& e1 : ss_rsrq_per_ssb) { - e1.to_json(j); - } - j.end_array(); - } - if (cgi_nr_present) { - j.write_fieldname("cGI-NR"); - cgi_nr.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SpatialDirectionInformation ::= SEQUENCE -SRSASN_CODE spatial_direction_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(nr_prs_beam_info.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE spatial_direction_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(nr_prs_beam_info.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void spatial_direction_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("nR-PRS-Beam-Information"); - nr_prs_beam_info.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SpatialRelationInfo ::= SEQUENCE -SRSASN_CODE spatial_relation_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, spatial_relationfor_res_id, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE spatial_relation_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(spatial_relationfor_res_id, bref, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void spatial_relation_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("spatialRelationforResourceID"); - for (const auto& e1 : spatial_relationfor_res_id) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SpatialRelationPerSRSResource ::= SEQUENCE -SRSASN_CODE spatial_relation_per_srs_res_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, spatial_relation_per_srs_res_list, 1, 16, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE spatial_relation_per_srs_res_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(spatial_relation_per_srs_res_list, bref, 1, 16, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void spatial_relation_per_srs_res_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("spatialRelationPerSRSResource-List"); - for (const auto& e1 : spatial_relation_per_srs_res_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SSBInfo ::= SEQUENCE -SRSASN_CODE ssb_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, list_of_ssb_info, 1, 255, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ssb_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(list_of_ssb_info, bref, 1, 255, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ssb_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("listOfSSBInfo"); - for (const auto& e1 : list_of_ssb_info) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// StartTimeAndDuration ::= SEQUENCE -SRSASN_CODE start_time_and_dur_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(start_time_present, 1)); - HANDLE_CODE(bref.pack(dur_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (start_time_present) { - HANDLE_CODE(start_time.pack(bref)); - } - if (dur_present) { - HANDLE_CODE(pack_integer(bref, dur, (uint32_t)0u, (uint32_t)90060u, true, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE start_time_and_dur_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(start_time_present, 1)); - HANDLE_CODE(bref.unpack(dur_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (start_time_present) { - HANDLE_CODE(start_time.unpack(bref)); - } - if (dur_present) { - HANDLE_CODE(unpack_integer(dur, bref, (uint32_t)0u, (uint32_t)90060u, true, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void start_time_and_dur_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (start_time_present) { - j.write_str("startTime", start_time.to_string()); - } - if (dur_present) { - j.write_int("duration", dur); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TimeStampSlotIndex ::= CHOICE -void time_stamp_slot_idx_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void time_stamp_slot_idx_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::scs_15: - break; - case types::scs_30: - break; - case types::scs_60: - break; - case types::scs_120: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "time_stamp_slot_idx_c"); - } -} -time_stamp_slot_idx_c::time_stamp_slot_idx_c(const time_stamp_slot_idx_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::scs_15: - c.init(other.c.get()); - break; - case types::scs_30: - c.init(other.c.get()); - break; - case types::scs_60: - c.init(other.c.get()); - break; - case types::scs_120: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "time_stamp_slot_idx_c"); - } -} -time_stamp_slot_idx_c& time_stamp_slot_idx_c::operator=(const time_stamp_slot_idx_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::scs_15: - c.set(other.c.get()); - break; - case types::scs_30: - c.set(other.c.get()); - break; - case types::scs_60: - c.set(other.c.get()); - break; - case types::scs_120: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "time_stamp_slot_idx_c"); - } - - return *this; -} -uint8_t& time_stamp_slot_idx_c::set_scs_15() -{ - set(types::scs_15); - return c.get(); -} -uint8_t& time_stamp_slot_idx_c::set_scs_30() -{ - set(types::scs_30); - return c.get(); -} -uint8_t& time_stamp_slot_idx_c::set_scs_60() -{ - set(types::scs_60); - return c.get(); -} -uint8_t& time_stamp_slot_idx_c::set_scs_120() -{ - set(types::scs_120); - return c.get(); -} -protocol_ie_single_container_s& time_stamp_slot_idx_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void time_stamp_slot_idx_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::scs_15: - j.write_int("sCS-15", c.get()); - break; - case types::scs_30: - j.write_int("sCS-30", c.get()); - break; - case types::scs_60: - j.write_int("sCS-60", c.get()); - break; - case types::scs_120: - j.write_int("sCS-120", c.get()); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "time_stamp_slot_idx_c"); - } - j.end_obj(); -} -SRSASN_CODE time_stamp_slot_idx_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::scs_15: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)9u, false, true)); - break; - case types::scs_30: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)19u, false, true)); - break; - case types::scs_60: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)39u, false, true)); - break; - case types::scs_120: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)79u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "time_stamp_slot_idx_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE time_stamp_slot_idx_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::scs_15: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)9u, false, true)); - break; - case types::scs_30: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)19u, false, true)); - break; - case types::scs_60: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)39u, false, true)); - break; - case types::scs_120: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)79u, false, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "time_stamp_slot_idx_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* time_stamp_slot_idx_c::types_opts::to_string() const -{ - static const char* names[] = {"sCS-15", "sCS-30", "sCS-60", "sCS-120", "choice-extension"}; - return convert_enum_idx(names, 5, value, "time_stamp_slot_idx_c::types"); -} -int8_t time_stamp_slot_idx_c::types_opts::to_number() const -{ - static const int8_t numbers[] = {-15, -30, -60, -120}; - return map_enum_number(numbers, 4, value, "time_stamp_slot_idx_c::types"); -} - -// UL-RTOAMeasurement ::= SEQUENCE -SRSASN_CODE ul_rtoameas_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(add_path_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(ul_rto_ameas.pack(bref)); - if (add_path_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, add_path_list, 1, 2, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ul_rtoameas_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool add_path_list_present; - HANDLE_CODE(bref.unpack(add_path_list_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(ul_rto_ameas.unpack(bref)); - if (add_path_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(add_path_list, bref, 1, 2, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ul_rtoameas_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("uLRTOAmeas"); - ul_rto_ameas.to_json(j); - if (add_path_list.size() > 0) { - j.start_array("additionalPathList"); - for (const auto& e1 : add_path_list) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// CPLength-EUTRA ::= ENUMERATED -const char* cp_len_eutra_opts::to_string() const -{ - static const char* names[] = {"normal", "extended"}; - return convert_enum_idx(names, 2, value, "cp_len_eutra_e"); -} - -// DL-Bandwidth-EUTRA ::= ENUMERATED -const char* dl_bw_eutra_opts::to_string() const -{ - static const char* names[] = {"bw6", "bw15", "bw25", "bw50", "bw75", "bw100"}; - return convert_enum_idx(names, 6, value, "dl_bw_eutra_e"); -} -uint8_t dl_bw_eutra_opts::to_number() const -{ - static const uint8_t numbers[] = {6, 15, 25, 50, 75, 100}; - return map_enum_number(numbers, 6, value, "dl_bw_eutra_e"); -} - -// MeasurementBeamInfo ::= SEQUENCE -SRSASN_CODE meas_beam_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(prs_res_id_present, 1)); - HANDLE_CODE(bref.pack(prs_res_set_id_present, 1)); - HANDLE_CODE(bref.pack(ssb_idx_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (prs_res_id_present) { - HANDLE_CODE(pack_integer(bref, prs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (prs_res_set_id_present) { - HANDLE_CODE(pack_integer(bref, prs_res_set_id, (uint8_t)0u, (uint8_t)7u, false, true)); - } - if (ssb_idx_present) { - HANDLE_CODE(pack_integer(bref, ssb_idx, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_beam_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(prs_res_id_present, 1)); - HANDLE_CODE(bref.unpack(prs_res_set_id_present, 1)); - HANDLE_CODE(bref.unpack(ssb_idx_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (prs_res_id_present) { - HANDLE_CODE(unpack_integer(prs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (prs_res_set_id_present) { - HANDLE_CODE(unpack_integer(prs_res_set_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - } - if (ssb_idx_present) { - HANDLE_CODE(unpack_integer(ssb_idx, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void meas_beam_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (prs_res_id_present) { - j.write_int("pRS-Resource-ID", prs_res_id); - } - if (prs_res_set_id_present) { - j.write_int("pRS-Resource-Set-ID", prs_res_set_id); - } - if (ssb_idx_present) { - j.write_int("sSB-Index", ssb_idx); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// MeasurementQuantitiesValue ::= ENUMERATED -const char* meas_quantities_value_opts::to_string() const -{ - static const char* names[] = {"cell-ID", - "angleOfArrival", - "timingAdvanceType1", - "timingAdvanceType2", - "rSRP", - "rSRQ", - "sS-RSRP", - "sS-RSRQ", - "cSI-RSRP", - "cSI-RSRQ", - "angleOfArrivalNR", - "timingAdvanceNR"}; - return convert_enum_idx(names, 12, value, "meas_quantities_value_e"); -} -uint8_t meas_quantities_value_opts::to_number() const -{ - switch (value) { - case timing_advance_type1: - return 1; - case timing_advance_type2: - return 2; - default: - invalid_enum_number(value, "meas_quantities_value_e"); - } - return 0; -} - -// MeasuredResultsValue-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t measured_results_value_ext_ie_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {32, 33, 34, 35, 36, 94}; - return map_enum_number(names, 6, idx, "id"); -} -bool measured_results_value_ext_ie_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {32, 33, 34, 35, 36, 94}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e measured_results_value_ext_ie_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 32: - return crit_e::ignore; - case 33: - return crit_e::ignore; - case 34: - return crit_e::ignore; - case 35: - return crit_e::ignore; - case 36: - return crit_e::ignore; - case 94: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -measured_results_value_ext_ie_o::value_c measured_results_value_ext_ie_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 32: - ret.set(value_c::types::result_ss_rsrp); - break; - case 33: - ret.set(value_c::types::result_ss_rsrq); - break; - case 34: - ret.set(value_c::types::result_csi_rsrp); - break; - case 35: - ret.set(value_c::types::result_csi_rsrq); - break; - case 36: - ret.set(value_c::types::angle_of_arrival_nr); - break; - case 94: - ret.set(value_c::types::nr_tadv); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e measured_results_value_ext_ie_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 32: - return presence_e::mandatory; - case 33: - return presence_e::mandatory; - case 34: - return presence_e::mandatory; - case 35: - return presence_e::mandatory; - case 36: - return presence_e::mandatory; - case 94: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void measured_results_value_ext_ie_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::result_ss_rsrp: - c = result_ss_rsrp_l{}; - break; - case types::result_ss_rsrq: - c = result_ss_rsrq_l{}; - break; - case types::result_csi_rsrp: - c = result_csi_rsrp_l{}; - break; - case types::result_csi_rsrq: - c = result_csi_rsrq_l{}; - break; - case types::angle_of_arrival_nr: - c = ul_ao_a_s{}; - break; - case types::nr_tadv: - c = uint16_t{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "measured_results_value_ext_ie_o::value_c"); - } -} -result_ss_rsrp_l& measured_results_value_ext_ie_o::value_c::result_ss_rsrp() -{ - assert_choice_type(types::result_ss_rsrp, type_, "Value"); - return c.get(); -} -result_ss_rsrq_l& measured_results_value_ext_ie_o::value_c::result_ss_rsrq() -{ - assert_choice_type(types::result_ss_rsrq, type_, "Value"); - return c.get(); -} -result_csi_rsrp_l& measured_results_value_ext_ie_o::value_c::result_csi_rsrp() -{ - assert_choice_type(types::result_csi_rsrp, type_, "Value"); - return c.get(); -} -result_csi_rsrq_l& measured_results_value_ext_ie_o::value_c::result_csi_rsrq() -{ - assert_choice_type(types::result_csi_rsrq, type_, "Value"); - return c.get(); -} -ul_ao_a_s& measured_results_value_ext_ie_o::value_c::angle_of_arrival_nr() -{ - assert_choice_type(types::angle_of_arrival_nr, type_, "Value"); - return c.get(); -} -uint16_t& measured_results_value_ext_ie_o::value_c::nr_tadv() -{ - assert_choice_type(types::nr_tadv, type_, "Value"); - return c.get(); -} -const result_ss_rsrp_l& measured_results_value_ext_ie_o::value_c::result_ss_rsrp() const -{ - assert_choice_type(types::result_ss_rsrp, type_, "Value"); - return c.get(); -} -const result_ss_rsrq_l& measured_results_value_ext_ie_o::value_c::result_ss_rsrq() const -{ - assert_choice_type(types::result_ss_rsrq, type_, "Value"); - return c.get(); -} -const result_csi_rsrp_l& measured_results_value_ext_ie_o::value_c::result_csi_rsrp() const -{ - assert_choice_type(types::result_csi_rsrp, type_, "Value"); - return c.get(); -} -const result_csi_rsrq_l& measured_results_value_ext_ie_o::value_c::result_csi_rsrq() const -{ - assert_choice_type(types::result_csi_rsrq, type_, "Value"); - return c.get(); -} -const ul_ao_a_s& measured_results_value_ext_ie_o::value_c::angle_of_arrival_nr() const -{ - assert_choice_type(types::angle_of_arrival_nr, type_, "Value"); - return c.get(); -} -const uint16_t& measured_results_value_ext_ie_o::value_c::nr_tadv() const -{ - assert_choice_type(types::nr_tadv, type_, "Value"); - return c.get(); -} -void measured_results_value_ext_ie_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::result_ss_rsrp: - j.start_array("ResultSS-RSRP"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::result_ss_rsrq: - j.start_array("ResultSS-RSRQ"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::result_csi_rsrp: - j.start_array("ResultCSI-RSRP"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::result_csi_rsrq: - j.start_array("ResultCSI-RSRQ"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::angle_of_arrival_nr: - j.write_fieldname("UL-AoA"); - c.get().to_json(j); - break; - case types::nr_tadv: - j.write_int("INTEGER (0..7690)", c.get()); - break; - default: - log_invalid_choice_id(type_, "measured_results_value_ext_ie_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE measured_results_value_ext_ie_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::result_ss_rsrp: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 9, true)); - break; - case types::result_ss_rsrq: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 9, true)); - break; - case types::result_csi_rsrp: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 9, true)); - break; - case types::result_csi_rsrq: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 9, true)); - break; - case types::angle_of_arrival_nr: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nr_tadv: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)7690u, false, true)); - break; - default: - log_invalid_choice_id(type_, "measured_results_value_ext_ie_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE measured_results_value_ext_ie_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::result_ss_rsrp: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 9, true)); - break; - case types::result_ss_rsrq: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 9, true)); - break; - case types::result_csi_rsrp: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 9, true)); - break; - case types::result_csi_rsrq: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 9, true)); - break; - case types::angle_of_arrival_nr: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nr_tadv: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)7690u, false, true)); - break; - default: - log_invalid_choice_id(type_, "measured_results_value_ext_ie_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* measured_results_value_ext_ie_o::value_c::types_opts::to_string() const -{ - static const char* names[] = { - "ResultSS-RSRP", "ResultSS-RSRQ", "ResultCSI-RSRP", "ResultCSI-RSRQ", "UL-AoA", "INTEGER (0..7690)"}; - return convert_enum_idx(names, 6, value, "measured_results_value_ext_ie_o::value_c::types"); -} -uint8_t measured_results_value_ext_ie_o::value_c::types_opts::to_number() const -{ - if (value == nr_tadv) { - return 0; - } - invalid_enum_number(value, "measured_results_value_ext_ie_o::value_c::types"); - return 0; -} - -// NumberOfAntennaPorts-EUTRA ::= ENUMERATED -const char* nof_ant_ports_eutra_opts::to_string() const -{ - static const char* names[] = {"n1-or-n2", "n4"}; - return convert_enum_idx(names, 2, value, "nof_ant_ports_eutra_e"); -} -uint8_t nof_ant_ports_eutra_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 4}; - return map_enum_number(numbers, 2, value, "nof_ant_ports_eutra_e"); -} - -// NumberOfDlFrames-EUTRA ::= ENUMERATED -const char* nof_dl_frames_eutra_opts::to_string() const -{ - static const char* names[] = {"sf1", "sf2", "sf4", "sf6"}; - return convert_enum_idx(names, 4, value, "nof_dl_frames_eutra_e"); -} -uint8_t nof_dl_frames_eutra_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4, 6}; - return map_enum_number(numbers, 4, value, "nof_dl_frames_eutra_e"); -} - -// OtherRATMeasurementQuantitiesValue ::= ENUMERATED -const char* other_rat_meas_quantities_value_opts::to_string() const -{ - static const char* names[] = {"geran", "utran", "nR", "eUTRA"}; - return convert_enum_idx(names, 4, value, "other_rat_meas_quantities_value_e"); -} - -SRSASN_CODE pos_sibs_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(assist_info_meta_data_present, 1)); - HANDLE_CODE(bref.pack(broadcast_prio_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pos_sib_type.pack(bref)); - HANDLE_CODE(pack_dyn_seq_of(bref, pos_sib_segments, 1, 64, true)); - if (assist_info_meta_data_present) { - HANDLE_CODE(assist_info_meta_data.pack(bref)); - } - if (broadcast_prio_present) { - HANDLE_CODE(pack_integer(bref, broadcast_prio, (uint8_t)1u, (uint8_t)16u, true, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pos_sibs_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(assist_info_meta_data_present, 1)); - HANDLE_CODE(bref.unpack(broadcast_prio_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(pos_sib_type.unpack(bref)); - HANDLE_CODE(unpack_dyn_seq_of(pos_sib_segments, bref, 1, 64, true)); - if (assist_info_meta_data_present) { - HANDLE_CODE(assist_info_meta_data.unpack(bref)); - } - if (broadcast_prio_present) { - HANDLE_CODE(unpack_integer(broadcast_prio, bref, (uint8_t)1u, (uint8_t)16u, true, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pos_sibs_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("posSIB-Type", pos_sib_type.to_string()); - j.start_array("posSIB-Segments"); - for (const auto& e1 : pos_sib_segments) { - e1.to_json(j); - } - j.end_array(); - if (assist_info_meta_data_present) { - j.write_fieldname("assistanceInformationMetaData"); - assist_info_meta_data.to_json(j); - } - if (broadcast_prio_present) { - j.write_int("broadcastPriority", broadcast_prio); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -template struct asn1::protocol_ie_single_container_s; - -// PRS-Bandwidth-EUTRA ::= ENUMERATED -const char* prs_bw_eutra_opts::to_string() const -{ - static const char* names[] = {"bw6", "bw15", "bw25", "bw50", "bw75", "bw100"}; - return convert_enum_idx(names, 6, value, "prs_bw_eutra_e"); -} -uint8_t prs_bw_eutra_opts::to_number() const -{ - static const uint8_t numbers[] = {6, 15, 25, 50, 75, 100}; - return map_enum_number(numbers, 6, value, "prs_bw_eutra_e"); -} - -// PRSFrequencyHoppingConfiguration-EUTRA ::= SEQUENCE -SRSASN_CODE prs_freq_hop_cfg_eutra_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(no_of_freq_hop_bands.pack(bref)); - HANDLE_CODE(pack_dyn_seq_of(bref, band_positions, 1, 7, integer_packer(0, 15, true, true))); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_freq_hop_cfg_eutra_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(no_of_freq_hop_bands.unpack(bref)); - HANDLE_CODE(unpack_dyn_seq_of(band_positions, bref, 1, 7, integer_packer(0, 15, true, true))); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_freq_hop_cfg_eutra_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("noOfFreqHoppingBands", no_of_freq_hop_bands.to_string()); - j.start_array("bandPositions"); - for (const auto& e1 : band_positions) { - j.write_int(e1); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSMutingConfiguration-EUTRA ::= CHOICE -void prs_muting_cfg_eutra_c::destroy_() -{ - switch (type_) { - case types::two: - c.destroy>(); - break; - case types::four: - c.destroy>(); - break; - case types::eight: - c.destroy>(); - break; - case types::sixteen: - c.destroy>(); - break; - case types::thirty_two: - c.destroy>(); - break; - case types::sixty_four: - c.destroy>(); - break; - case types::one_hundred_and_twenty_eight: - c.destroy>(); - break; - case types::two_hundred_and_fifty_six: - c.destroy>(); - break; - case types::five_hundred_and_twelve: - c.destroy>(); - break; - case types::one_thousand_and_twenty_four: - c.destroy>(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void prs_muting_cfg_eutra_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::two: - c.init>(); - break; - case types::four: - c.init>(); - break; - case types::eight: - c.init>(); - break; - case types::sixteen: - c.init>(); - break; - case types::thirty_two: - c.init>(); - break; - case types::sixty_four: - c.init>(); - break; - case types::one_hundred_and_twenty_eight: - c.init>(); - break; - case types::two_hundred_and_fifty_six: - c.init>(); - break; - case types::five_hundred_and_twelve: - c.init>(); - break; - case types::one_thousand_and_twenty_four: - c.init>(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_muting_cfg_eutra_c"); - } -} -prs_muting_cfg_eutra_c::prs_muting_cfg_eutra_c(const prs_muting_cfg_eutra_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::two: - c.init(other.c.get>()); - break; - case types::four: - c.init(other.c.get>()); - break; - case types::eight: - c.init(other.c.get>()); - break; - case types::sixteen: - c.init(other.c.get>()); - break; - case types::thirty_two: - c.init(other.c.get>()); - break; - case types::sixty_four: - c.init(other.c.get>()); - break; - case types::one_hundred_and_twenty_eight: - c.init(other.c.get>()); - break; - case types::two_hundred_and_fifty_six: - c.init(other.c.get>()); - break; - case types::five_hundred_and_twelve: - c.init(other.c.get>()); - break; - case types::one_thousand_and_twenty_four: - c.init(other.c.get>()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_muting_cfg_eutra_c"); - } -} -prs_muting_cfg_eutra_c& prs_muting_cfg_eutra_c::operator=(const prs_muting_cfg_eutra_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::two: - c.set(other.c.get>()); - break; - case types::four: - c.set(other.c.get>()); - break; - case types::eight: - c.set(other.c.get>()); - break; - case types::sixteen: - c.set(other.c.get>()); - break; - case types::thirty_two: - c.set(other.c.get>()); - break; - case types::sixty_four: - c.set(other.c.get>()); - break; - case types::one_hundred_and_twenty_eight: - c.set(other.c.get>()); - break; - case types::two_hundred_and_fifty_six: - c.set(other.c.get>()); - break; - case types::five_hundred_and_twelve: - c.set(other.c.get>()); - break; - case types::one_thousand_and_twenty_four: - c.set(other.c.get>()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_muting_cfg_eutra_c"); - } - - return *this; -} -fixed_bitstring<2, false, true>& prs_muting_cfg_eutra_c::set_two() -{ - set(types::two); - return c.get>(); -} -fixed_bitstring<4, false, true>& prs_muting_cfg_eutra_c::set_four() -{ - set(types::four); - return c.get>(); -} -fixed_bitstring<8, false, true>& prs_muting_cfg_eutra_c::set_eight() -{ - set(types::eight); - return c.get>(); -} -fixed_bitstring<16, false, true>& prs_muting_cfg_eutra_c::set_sixteen() -{ - set(types::sixteen); - return c.get>(); -} -fixed_bitstring<32, false, true>& prs_muting_cfg_eutra_c::set_thirty_two() -{ - set(types::thirty_two); - return c.get>(); -} -fixed_bitstring<64, false, true>& prs_muting_cfg_eutra_c::set_sixty_four() -{ - set(types::sixty_four); - return c.get>(); -} -fixed_bitstring<128, false, true>& prs_muting_cfg_eutra_c::set_one_hundred_and_twenty_eight() -{ - set(types::one_hundred_and_twenty_eight); - return c.get>(); -} -fixed_bitstring<256, false, true>& prs_muting_cfg_eutra_c::set_two_hundred_and_fifty_six() -{ - set(types::two_hundred_and_fifty_six); - return c.get>(); -} -fixed_bitstring<512, false, true>& prs_muting_cfg_eutra_c::set_five_hundred_and_twelve() -{ - set(types::five_hundred_and_twelve); - return c.get>(); -} -fixed_bitstring<1024, false, true>& prs_muting_cfg_eutra_c::set_one_thousand_and_twenty_four() -{ - set(types::one_thousand_and_twenty_four); - return c.get>(); -} -protocol_ie_single_container_s& prs_muting_cfg_eutra_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void prs_muting_cfg_eutra_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::two: - j.write_str("two", c.get>().to_string()); - break; - case types::four: - j.write_str("four", c.get>().to_string()); - break; - case types::eight: - j.write_str("eight", c.get>().to_string()); - break; - case types::sixteen: - j.write_str("sixteen", c.get>().to_string()); - break; - case types::thirty_two: - j.write_str("thirty-two", c.get>().to_string()); - break; - case types::sixty_four: - j.write_str("sixty-four", c.get>().to_string()); - break; - case types::one_hundred_and_twenty_eight: - j.write_str("one-hundred-and-twenty-eight", c.get>().to_string()); - break; - case types::two_hundred_and_fifty_six: - j.write_str("two-hundred-and-fifty-six", c.get>().to_string()); - break; - case types::five_hundred_and_twelve: - j.write_str("five-hundred-and-twelve", c.get>().to_string()); - break; - case types::one_thousand_and_twenty_four: - j.write_str("one-thousand-and-twenty-four", c.get>().to_string()); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "prs_muting_cfg_eutra_c"); - } - j.end_obj(); -} -SRSASN_CODE prs_muting_cfg_eutra_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::two: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::four: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::eight: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::sixteen: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::thirty_two: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::sixty_four: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::one_hundred_and_twenty_eight: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::two_hundred_and_fifty_six: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::five_hundred_and_twelve: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::one_thousand_and_twenty_four: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_muting_cfg_eutra_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_muting_cfg_eutra_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::two: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::four: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::eight: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::sixteen: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::thirty_two: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::sixty_four: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::one_hundred_and_twenty_eight: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::two_hundred_and_fifty_six: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::five_hundred_and_twelve: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::one_thousand_and_twenty_four: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_muting_cfg_eutra_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* prs_muting_cfg_eutra_c::types_opts::to_string() const -{ - static const char* names[] = {"two", - "four", - "eight", - "sixteen", - "thirty-two", - "sixty-four", - "one-hundred-and-twenty-eight", - "two-hundred-and-fifty-six", - "five-hundred-and-twelve", - "one-thousand-and-twenty-four", - "choice-Extension"}; - return convert_enum_idx(names, 11, value, "prs_muting_cfg_eutra_c::types"); -} - -// PRSOccasionGroup-EUTRA ::= ENUMERATED -const char* prs_occasion_group_eutra_opts::to_string() const -{ - static const char* names[] = {"og2", "og4", "og8", "og16", "og32", "og64", "og128"}; - return convert_enum_idx(names, 7, value, "prs_occasion_group_eutra_e"); -} -uint8_t prs_occasion_group_eutra_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4, 8, 16, 32, 64, 128}; - return map_enum_number(numbers, 7, value, "prs_occasion_group_eutra_e"); -} - -// RequestedDLPRSResourceSet-Item ::= SEQUENCE -SRSASN_CODE requested_dl_prs_res_set_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(pr_sbw_present, 1)); - HANDLE_CODE(bref.pack(comb_size_present, 1)); - HANDLE_CODE(bref.pack(res_set_periodicity_present, 1)); - HANDLE_CODE(bref.pack(res_repeat_factor_present, 1)); - HANDLE_CODE(bref.pack(res_numof_symbols_present, 1)); - HANDLE_CODE(bref.pack(requested_dl_prs_res_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(res_set_start_time_and_dur_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (pr_sbw_present) { - HANDLE_CODE(pack_integer(bref, pr_sbw, (uint8_t)1u, (uint8_t)63u, false, true)); - } - if (comb_size_present) { - HANDLE_CODE(comb_size.pack(bref)); - } - if (res_set_periodicity_present) { - HANDLE_CODE(res_set_periodicity.pack(bref)); - } - if (res_repeat_factor_present) { - HANDLE_CODE(res_repeat_factor.pack(bref)); - } - if (res_numof_symbols_present) { - HANDLE_CODE(res_numof_symbols.pack(bref)); - } - if (requested_dl_prs_res_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, requested_dl_prs_res_list, 1, 64, true)); - } - if (res_set_start_time_and_dur_present) { - HANDLE_CODE(res_set_start_time_and_dur.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE requested_dl_prs_res_set_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(pr_sbw_present, 1)); - HANDLE_CODE(bref.unpack(comb_size_present, 1)); - HANDLE_CODE(bref.unpack(res_set_periodicity_present, 1)); - HANDLE_CODE(bref.unpack(res_repeat_factor_present, 1)); - HANDLE_CODE(bref.unpack(res_numof_symbols_present, 1)); - bool requested_dl_prs_res_list_present; - HANDLE_CODE(bref.unpack(requested_dl_prs_res_list_present, 1)); - HANDLE_CODE(bref.unpack(res_set_start_time_and_dur_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (pr_sbw_present) { - HANDLE_CODE(unpack_integer(pr_sbw, bref, (uint8_t)1u, (uint8_t)63u, false, true)); - } - if (comb_size_present) { - HANDLE_CODE(comb_size.unpack(bref)); - } - if (res_set_periodicity_present) { - HANDLE_CODE(res_set_periodicity.unpack(bref)); - } - if (res_repeat_factor_present) { - HANDLE_CODE(res_repeat_factor.unpack(bref)); - } - if (res_numof_symbols_present) { - HANDLE_CODE(res_numof_symbols.unpack(bref)); - } - if (requested_dl_prs_res_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(requested_dl_prs_res_list, bref, 1, 64, true)); - } - if (res_set_start_time_and_dur_present) { - HANDLE_CODE(res_set_start_time_and_dur.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void requested_dl_prs_res_set_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (pr_sbw_present) { - j.write_int("pRSbandwidth", pr_sbw); - } - if (comb_size_present) { - j.write_str("combSize", comb_size.to_string()); - } - if (res_set_periodicity_present) { - j.write_str("resourceSetPeriodicity", res_set_periodicity.to_string()); - } - if (res_repeat_factor_present) { - j.write_str("resourceRepetitionFactor", res_repeat_factor.to_string()); - } - if (res_numof_symbols_present) { - j.write_str("resourceNumberofSymbols", res_numof_symbols.to_string()); - } - if (requested_dl_prs_res_list.size() > 0) { - j.start_array("requestedDLPRSResource-List"); - for (const auto& e1 : requested_dl_prs_res_list) { - e1.to_json(j); - } - j.end_array(); - } - if (res_set_start_time_and_dur_present) { - j.write_fieldname("resourceSetStartTimeAndDuration"); - res_set_start_time_and_dur.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* requested_dl_prs_res_set_item_s::comb_size_opts::to_string() const -{ - static const char* names[] = {"n2", "n4", "n6", "n12"}; - return convert_enum_idx(names, 4, value, "requested_dl_prs_res_set_item_s::comb_size_e_"); -} -uint8_t requested_dl_prs_res_set_item_s::comb_size_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4, 6, 12}; - return map_enum_number(numbers, 4, value, "requested_dl_prs_res_set_item_s::comb_size_e_"); -} - -const char* requested_dl_prs_res_set_item_s::res_set_periodicity_opts::to_string() const -{ - static const char* names[] = {"n4", "n5", "n8", "n10", "n16", "n20", "n32", - "n40", "n64", "n80", "n160", "n320", "n640", "n1280", - "n2560", "n5120", "n10240", "n20480", "n40960", "n81920"}; - return convert_enum_idx(names, 20, value, "requested_dl_prs_res_set_item_s::res_set_periodicity_e_"); -} -uint32_t requested_dl_prs_res_set_item_s::res_set_periodicity_opts::to_number() const -{ - static const uint32_t numbers[] = {4, 5, 8, 10, 16, 20, 32, 40, 64, 80, - 160, 320, 640, 1280, 2560, 5120, 10240, 20480, 40960, 81920}; - return map_enum_number(numbers, 20, value, "requested_dl_prs_res_set_item_s::res_set_periodicity_e_"); -} - -const char* requested_dl_prs_res_set_item_s::res_repeat_factor_opts::to_string() const -{ - static const char* names[] = {"rf1", "rf2", "rf4", "rf6", "rf8", "rf16", "rf32"}; - return convert_enum_idx(names, 7, value, "requested_dl_prs_res_set_item_s::res_repeat_factor_e_"); -} -uint8_t requested_dl_prs_res_set_item_s::res_repeat_factor_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2, 4, 6, 8, 16, 32}; - return map_enum_number(numbers, 7, value, "requested_dl_prs_res_set_item_s::res_repeat_factor_e_"); -} - -const char* requested_dl_prs_res_set_item_s::res_numof_symbols_opts::to_string() const -{ - static const char* names[] = {"n2", "n4", "n6", "n12"}; - return convert_enum_idx(names, 4, value, "requested_dl_prs_res_set_item_s::res_numof_symbols_e_"); -} -uint8_t requested_dl_prs_res_set_item_s::res_numof_symbols_opts::to_number() const -{ - static const uint8_t numbers[] = {2, 4, 6, 12}; - return map_enum_number(numbers, 4, value, "requested_dl_prs_res_set_item_s::res_numof_symbols_e_"); -} - -// ResultRSRP-EUTRA-Item ::= SEQUENCE -SRSASN_CODE result_rsrp_eutra_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_eutra_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, pci_eutra, (uint16_t)0u, (uint16_t)503u, true, true)); - HANDLE_CODE(pack_integer(bref, earfcn, (uint32_t)0u, (uint32_t)262143u, true, true)); - if (cgi_eutra_present) { - HANDLE_CODE(cgi_eutra.pack(bref)); - } - HANDLE_CODE(pack_integer(bref, value_rsrp_eutra, (uint8_t)0u, (uint8_t)97u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_rsrp_eutra_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_eutra_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(pci_eutra, bref, (uint16_t)0u, (uint16_t)503u, true, true)); - HANDLE_CODE(unpack_integer(earfcn, bref, (uint32_t)0u, (uint32_t)262143u, true, true)); - if (cgi_eutra_present) { - HANDLE_CODE(cgi_eutra.unpack(bref)); - } - HANDLE_CODE(unpack_integer(value_rsrp_eutra, bref, (uint8_t)0u, (uint8_t)97u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_rsrp_eutra_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pCI-EUTRA", pci_eutra); - j.write_int("eARFCN", earfcn); - if (cgi_eutra_present) { - j.write_fieldname("cGI-EUTRA"); - cgi_eutra.to_json(j); - } - j.write_int("valueRSRP-EUTRA", value_rsrp_eutra); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultRSRQ-EUTRA-Item ::= SEQUENCE -SRSASN_CODE result_rsrq_eutra_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_utra_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, pci_eutra, (uint16_t)0u, (uint16_t)503u, true, true)); - HANDLE_CODE(pack_integer(bref, earfcn, (uint32_t)0u, (uint32_t)262143u, true, true)); - if (cgi_utra_present) { - HANDLE_CODE(cgi_utra.pack(bref)); - } - HANDLE_CODE(pack_integer(bref, value_rsrq_eutra, (uint8_t)0u, (uint8_t)34u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_rsrq_eutra_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_utra_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(pci_eutra, bref, (uint16_t)0u, (uint16_t)503u, true, true)); - HANDLE_CODE(unpack_integer(earfcn, bref, (uint32_t)0u, (uint32_t)262143u, true, true)); - if (cgi_utra_present) { - HANDLE_CODE(cgi_utra.unpack(bref)); - } - HANDLE_CODE(unpack_integer(value_rsrq_eutra, bref, (uint8_t)0u, (uint8_t)34u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_rsrq_eutra_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pCI-EUTRA", pci_eutra); - j.write_int("eARFCN", earfcn); - if (cgi_utra_present) { - j.write_fieldname("cGI-UTRA"); - cgi_utra.to_json(j); - } - j.write_int("valueRSRQ-EUTRA", value_rsrq_eutra); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SCS-SpecificCarrier ::= SEQUENCE -SRSASN_CODE scs_specific_carrier_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, offset_to_carrier, (uint16_t)0u, (uint16_t)2199u, true, true)); - HANDLE_CODE(subcarrier_spacing.pack(bref)); - HANDLE_CODE(pack_integer(bref, carrier_bw, (uint16_t)1u, (uint16_t)275u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE scs_specific_carrier_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(offset_to_carrier, bref, (uint16_t)0u, (uint16_t)2199u, true, true)); - HANDLE_CODE(subcarrier_spacing.unpack(bref)); - HANDLE_CODE(unpack_integer(carrier_bw, bref, (uint16_t)1u, (uint16_t)275u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void scs_specific_carrier_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("offsetToCarrier", offset_to_carrier); - j.write_str("subcarrierSpacing", subcarrier_spacing.to_string()); - j.write_int("carrierBandwidth", carrier_bw); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* scs_specific_carrier_s::subcarrier_spacing_opts::to_string() const -{ - static const char* names[] = {"kHz15", "kHz30", "kHz60", "kHz120"}; - return convert_enum_idx(names, 4, value, "scs_specific_carrier_s::subcarrier_spacing_e_"); -} -uint8_t scs_specific_carrier_s::subcarrier_spacing_opts::to_number() const -{ - static const uint8_t numbers[] = {15, 30, 60, 120}; - return map_enum_number(numbers, 4, value, "scs_specific_carrier_s::subcarrier_spacing_e_"); -} - -// SemipersistentSRS-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t semipersistent_srs_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {48, 63}; - return map_enum_number(names, 2, idx, "id"); -} -bool semipersistent_srs_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {48, 63}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e semipersistent_srs_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 48: - return crit_e::ignore; - case 63: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -semipersistent_srs_ext_ies_o::ext_c semipersistent_srs_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 48: - ret.set(ext_c::types::srs_spatial_relation); - break; - case 63: - ret.set(ext_c::types::srs_spatial_relation_per_srs_res); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e semipersistent_srs_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 48: - return presence_e::optional; - case 63: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void semipersistent_srs_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::srs_spatial_relation: - c = spatial_relation_info_s{}; - break; - case types::srs_spatial_relation_per_srs_res: - c = spatial_relation_per_srs_res_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "semipersistent_srs_ext_ies_o::ext_c"); - } -} -spatial_relation_info_s& semipersistent_srs_ext_ies_o::ext_c::srs_spatial_relation() -{ - assert_choice_type(types::srs_spatial_relation, type_, "Extension"); - return c.get(); -} -spatial_relation_per_srs_res_s& semipersistent_srs_ext_ies_o::ext_c::srs_spatial_relation_per_srs_res() -{ - assert_choice_type(types::srs_spatial_relation_per_srs_res, type_, "Extension"); - return c.get(); -} -const spatial_relation_info_s& semipersistent_srs_ext_ies_o::ext_c::srs_spatial_relation() const -{ - assert_choice_type(types::srs_spatial_relation, type_, "Extension"); - return c.get(); -} -const spatial_relation_per_srs_res_s& semipersistent_srs_ext_ies_o::ext_c::srs_spatial_relation_per_srs_res() const -{ - assert_choice_type(types::srs_spatial_relation_per_srs_res, type_, "Extension"); - return c.get(); -} -void semipersistent_srs_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::srs_spatial_relation: - j.write_fieldname("SpatialRelationInfo"); - c.get().to_json(j); - break; - case types::srs_spatial_relation_per_srs_res: - j.write_fieldname("SpatialRelationPerSRSResource"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "semipersistent_srs_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE semipersistent_srs_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::srs_spatial_relation: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::srs_spatial_relation_per_srs_res: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "semipersistent_srs_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE semipersistent_srs_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::srs_spatial_relation: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::srs_spatial_relation_per_srs_res: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "semipersistent_srs_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* semipersistent_srs_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"SpatialRelationInfo", "SpatialRelationPerSRSResource"}; - return convert_enum_idx(names, 2, value, "semipersistent_srs_ext_ies_o::ext_c::types"); -} - -// SRSConfig ::= SEQUENCE -SRSASN_CODE srs_cfg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(srs_res_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(pos_srs_res_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(srs_res_set_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(pos_srs_res_set_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (srs_res_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, srs_res_list, 1, 64, true)); - } - if (pos_srs_res_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, pos_srs_res_list, 1, 64, true)); - } - if (srs_res_set_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, srs_res_set_list, 1, 16, true)); - } - if (pos_srs_res_set_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, pos_srs_res_set_list, 1, 16, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_cfg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool srs_res_list_present; - HANDLE_CODE(bref.unpack(srs_res_list_present, 1)); - bool pos_srs_res_list_present; - HANDLE_CODE(bref.unpack(pos_srs_res_list_present, 1)); - bool srs_res_set_list_present; - HANDLE_CODE(bref.unpack(srs_res_set_list_present, 1)); - bool pos_srs_res_set_list_present; - HANDLE_CODE(bref.unpack(pos_srs_res_set_list_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (srs_res_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(srs_res_list, bref, 1, 64, true)); - } - if (pos_srs_res_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(pos_srs_res_list, bref, 1, 64, true)); - } - if (srs_res_set_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(srs_res_set_list, bref, 1, 16, true)); - } - if (pos_srs_res_set_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(pos_srs_res_set_list, bref, 1, 16, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srs_cfg_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (srs_res_list.size() > 0) { - j.start_array("sRSResource-List"); - for (const auto& e1 : srs_res_list) { - e1.to_json(j); - } - j.end_array(); - } - if (pos_srs_res_list.size() > 0) { - j.start_array("posSRSResource-List"); - for (const auto& e1 : pos_srs_res_list) { - e1.to_json(j); - } - j.end_array(); - } - if (srs_res_set_list.size() > 0) { - j.start_array("sRSResourceSet-List"); - for (const auto& e1 : srs_res_set_list) { - e1.to_json(j); - } - j.end_array(); - } - if (pos_srs_res_set_list.size() > 0) { - j.start_array("posSRSResourceSet-List"); - for (const auto& e1 : pos_srs_res_set_list) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TimeStamp ::= SEQUENCE -SRSASN_CODE time_stamp_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(meas_time_present, 1)); - HANDLE_CODE(bref.pack(ie_ext_present, 1)); - - HANDLE_CODE(pack_integer(bref, sys_frame_num, (uint16_t)0u, (uint16_t)1023u, false, true)); - HANDLE_CODE(slot_idx.pack(bref)); - if (meas_time_present) { - HANDLE_CODE(meas_time.pack(bref)); - } - if (ie_ext_present) { - HANDLE_CODE(ie_ext.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE time_stamp_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(meas_time_present, 1)); - HANDLE_CODE(bref.unpack(ie_ext_present, 1)); - - HANDLE_CODE(unpack_integer(sys_frame_num, bref, (uint16_t)0u, (uint16_t)1023u, false, true)); - HANDLE_CODE(slot_idx.unpack(bref)); - if (meas_time_present) { - HANDLE_CODE(meas_time.unpack(bref)); - } - if (ie_ext_present) { - HANDLE_CODE(ie_ext.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void time_stamp_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("systemFrameNumber", sys_frame_num); - j.write_fieldname("slotIndex"); - slot_idx.to_json(j); - if (meas_time_present) { - j.write_str("measurementTime", meas_time.to_string()); - } - if (ie_ext_present) { - j.write_fieldname("iE-Extension"); - ie_ext.to_json(j); - } - j.end_obj(); -} - -// TP-Type-EUTRA ::= ENUMERATED -const char* tp_type_eutra_opts::to_string() const -{ - static const char* names[] = {"prs-only-tp"}; - return convert_enum_idx(names, 1, value, "tp_type_eutra_e"); -} - -// TRPInformationTypeResponseItem ::= CHOICE -void trp_info_type_resp_item_c::destroy_() -{ - switch (type_) { - case types::cgi_nr: - c.destroy(); - break; - case types::prs_cfg: - c.destroy(); - break; - case types::ss_binfo: - c.destroy(); - break; - case types::sfn_initisation_time: - c.destroy>(); - break; - case types::spatial_direction_info: - c.destroy(); - break; - case types::geographical_coordinates: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trp_info_type_resp_item_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::pci_nr: - break; - case types::cgi_nr: - c.init(); - break; - case types::arfcn: - break; - case types::prs_cfg: - c.init(); - break; - case types::ss_binfo: - c.init(); - break; - case types::sfn_initisation_time: - c.init>(); - break; - case types::spatial_direction_info: - c.init(); - break; - case types::geographical_coordinates: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_c"); - } -} -trp_info_type_resp_item_c::trp_info_type_resp_item_c(const trp_info_type_resp_item_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::pci_nr: - c.init(other.c.get()); - break; - case types::cgi_nr: - c.init(other.c.get()); - break; - case types::arfcn: - c.init(other.c.get()); - break; - case types::prs_cfg: - c.init(other.c.get()); - break; - case types::ss_binfo: - c.init(other.c.get()); - break; - case types::sfn_initisation_time: - c.init(other.c.get>()); - break; - case types::spatial_direction_info: - c.init(other.c.get()); - break; - case types::geographical_coordinates: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_c"); - } -} -trp_info_type_resp_item_c& trp_info_type_resp_item_c::operator=(const trp_info_type_resp_item_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::pci_nr: - c.set(other.c.get()); - break; - case types::cgi_nr: - c.set(other.c.get()); - break; - case types::arfcn: - c.set(other.c.get()); - break; - case types::prs_cfg: - c.set(other.c.get()); - break; - case types::ss_binfo: - c.set(other.c.get()); - break; - case types::sfn_initisation_time: - c.set(other.c.get>()); - break; - case types::spatial_direction_info: - c.set(other.c.get()); - break; - case types::geographical_coordinates: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_c"); - } - - return *this; -} -uint16_t& trp_info_type_resp_item_c::set_pci_nr() -{ - set(types::pci_nr); - return c.get(); -} -cgi_nr_s& trp_info_type_resp_item_c::set_cgi_nr() -{ - set(types::cgi_nr); - return c.get(); -} -uint32_t& trp_info_type_resp_item_c::set_arfcn() -{ - set(types::arfcn); - return c.get(); -} -prs_cfg_s& trp_info_type_resp_item_c::set_prs_cfg() -{ - set(types::prs_cfg); - return c.get(); -} -ssb_info_s& trp_info_type_resp_item_c::set_ss_binfo() -{ - set(types::ss_binfo); - return c.get(); -} -fixed_bitstring<64, false, true>& trp_info_type_resp_item_c::set_sfn_initisation_time() -{ - set(types::sfn_initisation_time); - return c.get>(); -} -spatial_direction_info_s& trp_info_type_resp_item_c::set_spatial_direction_info() -{ - set(types::spatial_direction_info); - return c.get(); -} -geographical_coordinates_s& trp_info_type_resp_item_c::set_geographical_coordinates() -{ - set(types::geographical_coordinates); - return c.get(); -} -protocol_ie_single_container_s& trp_info_type_resp_item_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trp_info_type_resp_item_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::pci_nr: - j.write_int("pCI-NR", c.get()); - break; - case types::cgi_nr: - j.write_fieldname("cGI-NR"); - c.get().to_json(j); - break; - case types::arfcn: - j.write_int("aRFCN", c.get()); - break; - case types::prs_cfg: - j.write_fieldname("pRSConfiguration"); - c.get().to_json(j); - break; - case types::ss_binfo: - j.write_fieldname("sSBinformation"); - c.get().to_json(j); - break; - case types::sfn_initisation_time: - j.write_str("sFNInitialisationTime", c.get>().to_string()); - break; - case types::spatial_direction_info: - j.write_fieldname("spatialDirectionInformation"); - c.get().to_json(j); - break; - case types::geographical_coordinates: - j.write_fieldname("geographicalCoordinates"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_info_type_resp_item_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::pci_nr: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)1007u, false, true)); - break; - case types::cgi_nr: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::arfcn: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)3279165u, false, true)); - break; - case types::prs_cfg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ss_binfo: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::spatial_direction_info: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::geographical_coordinates: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_type_resp_item_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::pci_nr: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - break; - case types::cgi_nr: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::arfcn: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - break; - case types::prs_cfg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ss_binfo: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::spatial_direction_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::geographical_coordinates: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_type_resp_item_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_info_type_resp_item_c::types_opts::to_string() const -{ - static const char* names[] = {"pCI-NR", - "cGI-NR", - "aRFCN", - "pRSConfiguration", - "sSBinformation", - "sFNInitialisationTime", - "spatialDirectionInformation", - "geographicalCoordinates", - "choice-extension"}; - return convert_enum_idx(names, 9, value, "trp_info_type_resp_item_c::types"); -} - -// TRP-MeasurementRequestItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t trp_meas_request_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {60, 69, 82, 83}; - return map_enum_number(names, 4, idx, "id"); -} -bool trp_meas_request_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {60, 69, 82, 83}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_meas_request_item_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 60: - return crit_e::ignore; - case 69: - return crit_e::ignore; - case 82: - return crit_e::ignore; - case 83: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_meas_request_item_ext_ies_o::ext_c trp_meas_request_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 60: - ret.set(ext_c::types::cell_id); - break; - case 69: - ret.set(ext_c::types::ao_a_search_win); - break; - case 82: - ret.set(ext_c::types::nof_trp_rx_teg); - break; - case 83: - ret.set(ext_c::types::nof_trp_rx_tx_teg); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_meas_request_item_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 60: - return presence_e::optional; - case 69: - return presence_e::optional; - case 82: - return presence_e::optional; - case 83: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void trp_meas_request_item_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cell_id: - c = cgi_nr_s{}; - break; - case types::ao_a_search_win: - c = ao_a_assist_info_s{}; - break; - case types::nof_trp_rx_teg: - c = nof_trp_rx_teg_e{}; - break; - case types::nof_trp_rx_tx_teg: - c = nof_trp_rx_tx_teg_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_meas_request_item_ext_ies_o::ext_c"); - } -} -cgi_nr_s& trp_meas_request_item_ext_ies_o::ext_c::cell_id() -{ - assert_choice_type(types::cell_id, type_, "Extension"); - return c.get(); -} -ao_a_assist_info_s& trp_meas_request_item_ext_ies_o::ext_c::ao_a_search_win() -{ - assert_choice_type(types::ao_a_search_win, type_, "Extension"); - return c.get(); -} -nof_trp_rx_teg_e& trp_meas_request_item_ext_ies_o::ext_c::nof_trp_rx_teg() -{ - assert_choice_type(types::nof_trp_rx_teg, type_, "Extension"); - return c.get(); -} -nof_trp_rx_tx_teg_e& trp_meas_request_item_ext_ies_o::ext_c::nof_trp_rx_tx_teg() -{ - assert_choice_type(types::nof_trp_rx_tx_teg, type_, "Extension"); - return c.get(); -} -const cgi_nr_s& trp_meas_request_item_ext_ies_o::ext_c::cell_id() const -{ - assert_choice_type(types::cell_id, type_, "Extension"); - return c.get(); -} -const ao_a_assist_info_s& trp_meas_request_item_ext_ies_o::ext_c::ao_a_search_win() const -{ - assert_choice_type(types::ao_a_search_win, type_, "Extension"); - return c.get(); -} -const nof_trp_rx_teg_e& trp_meas_request_item_ext_ies_o::ext_c::nof_trp_rx_teg() const -{ - assert_choice_type(types::nof_trp_rx_teg, type_, "Extension"); - return c.get(); -} -const nof_trp_rx_tx_teg_e& trp_meas_request_item_ext_ies_o::ext_c::nof_trp_rx_tx_teg() const -{ - assert_choice_type(types::nof_trp_rx_tx_teg, type_, "Extension"); - return c.get(); -} -void trp_meas_request_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cell_id: - j.write_fieldname("CGI-NR"); - c.get().to_json(j); - break; - case types::ao_a_search_win: - j.write_fieldname("AoA-AssistanceInfo"); - c.get().to_json(j); - break; - case types::nof_trp_rx_teg: - j.write_str("NumberOfTRPRxTEG", c.get().to_string()); - break; - case types::nof_trp_rx_tx_teg: - j.write_str("NumberOfTRPRxTxTEG", c.get().to_string()); - break; - default: - log_invalid_choice_id(type_, "trp_meas_request_item_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_meas_request_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cell_id: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ao_a_search_win: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nof_trp_rx_teg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nof_trp_rx_tx_teg: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_request_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_request_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cell_id: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ao_a_search_win: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nof_trp_rx_teg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nof_trp_rx_tx_teg: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_request_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_meas_request_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"CGI-NR", "AoA-AssistanceInfo", "NumberOfTRPRxTEG", "NumberOfTRPRxTxTEG"}; - return convert_enum_idx(names, 4, value, "trp_meas_request_item_ext_ies_o::ext_c::types"); -} - -SRSASN_CODE trp_meas_result_item_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += srs_restype_present ? 1 : 0; - nof_ies += arp_id_present ? 1 : 0; - nof_ies += lo_s_n_lo_si_nformation_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (srs_restype_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)76, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_restype.pack(bref)); - } - if (arp_id_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)79, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, arp_id, (uint8_t)1u, (uint8_t)16u, true, true)); - } - if (lo_s_n_lo_si_nformation_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)80, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(lo_s_n_lo_si_nformation.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_result_item_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 76: { - srs_restype_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_restype.unpack(bref)); - break; - } - case 79: { - arp_id_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(arp_id, bref, (uint8_t)1u, (uint8_t)16u, true, true)); - break; - } - case 80: { - lo_s_n_lo_si_nformation_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(lo_s_n_lo_si_nformation.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void trp_meas_result_item_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (srs_restype_present) { - j.write_int("id", 76); - j.write_str("criticality", "ignore"); - srs_restype.to_json(j); - } - if (arp_id_present) { - j.write_int("id", 79); - j.write_str("criticality", "ignore"); - j.write_int("Extension", arp_id); - } - if (lo_s_n_lo_si_nformation_present) { - j.write_int("id", 80); - j.write_str("criticality", "ignore"); - lo_s_n_lo_si_nformation.to_json(j); - } - j.end_obj(); -} - -// TRP-MeasurementUpdateItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t trp_meas_upd_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {82, 83}; - return map_enum_number(names, 2, idx, "id"); -} -bool trp_meas_upd_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {82, 83}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_meas_upd_item_ext_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 82: - return crit_e::ignore; - case 83: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_meas_upd_item_ext_ies_o::ext_c trp_meas_upd_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - switch (id) { - case 82: - ret.set(ext_c::types::nof_trp_rx_teg); - break; - case 83: - ret.set(ext_c::types::nof_trp_rx_tx_teg); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_meas_upd_item_ext_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 82: - return presence_e::optional; - case 83: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Extension ::= OPEN TYPE -void trp_meas_upd_item_ext_ies_o::ext_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::nof_trp_rx_teg: - c = nof_trp_rx_teg_e{}; - break; - case types::nof_trp_rx_tx_teg: - c = nof_trp_rx_tx_teg_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_meas_upd_item_ext_ies_o::ext_c"); - } -} -nof_trp_rx_teg_e& trp_meas_upd_item_ext_ies_o::ext_c::nof_trp_rx_teg() -{ - assert_choice_type(types::nof_trp_rx_teg, type_, "Extension"); - return c.get(); -} -nof_trp_rx_tx_teg_e& trp_meas_upd_item_ext_ies_o::ext_c::nof_trp_rx_tx_teg() -{ - assert_choice_type(types::nof_trp_rx_tx_teg, type_, "Extension"); - return c.get(); -} -const nof_trp_rx_teg_e& trp_meas_upd_item_ext_ies_o::ext_c::nof_trp_rx_teg() const -{ - assert_choice_type(types::nof_trp_rx_teg, type_, "Extension"); - return c.get(); -} -const nof_trp_rx_tx_teg_e& trp_meas_upd_item_ext_ies_o::ext_c::nof_trp_rx_tx_teg() const -{ - assert_choice_type(types::nof_trp_rx_tx_teg, type_, "Extension"); - return c.get(); -} -void trp_meas_upd_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::nof_trp_rx_teg: - j.write_str("NumberOfTRPRxTEG", c.get().to_string()); - break; - case types::nof_trp_rx_tx_teg: - j.write_str("NumberOfTRPRxTxTEG", c.get().to_string()); - break; - default: - log_invalid_choice_id(type_, "trp_meas_upd_item_ext_ies_o::ext_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_meas_upd_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::nof_trp_rx_teg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nof_trp_rx_tx_teg: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_upd_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_upd_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::nof_trp_rx_teg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nof_trp_rx_tx_teg: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_meas_upd_item_ext_ies_o::ext_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_meas_upd_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"NumberOfTRPRxTEG", "NumberOfTRPRxTxTEG"}; - return convert_enum_idx(names, 2, value, "trp_meas_upd_item_ext_ies_o::ext_c::types"); -} - -// TrpMeasuredResultsValue ::= CHOICE -void trp_measured_results_value_c::destroy_() -{ - switch (type_) { - case types::ul_angle_of_arrival: - c.destroy(); - break; - case types::ul_rtoa: - c.destroy(); - break; - case types::gnb_rx_tx_time_diff: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void trp_measured_results_value_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::ul_angle_of_arrival: - c.init(); - break; - case types::ul_srs_rsrp: - break; - case types::ul_rtoa: - c.init(); - break; - case types::gnb_rx_tx_time_diff: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_c"); - } -} -trp_measured_results_value_c::trp_measured_results_value_c(const trp_measured_results_value_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::ul_angle_of_arrival: - c.init(other.c.get()); - break; - case types::ul_srs_rsrp: - c.init(other.c.get()); - break; - case types::ul_rtoa: - c.init(other.c.get()); - break; - case types::gnb_rx_tx_time_diff: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_c"); - } -} -trp_measured_results_value_c& trp_measured_results_value_c::operator=(const trp_measured_results_value_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::ul_angle_of_arrival: - c.set(other.c.get()); - break; - case types::ul_srs_rsrp: - c.set(other.c.get()); - break; - case types::ul_rtoa: - c.set(other.c.get()); - break; - case types::gnb_rx_tx_time_diff: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_c"); - } - - return *this; -} -ul_ao_a_s& trp_measured_results_value_c::set_ul_angle_of_arrival() -{ - set(types::ul_angle_of_arrival); - return c.get(); -} -uint8_t& trp_measured_results_value_c::set_ul_srs_rsrp() -{ - set(types::ul_srs_rsrp); - return c.get(); -} -ul_rtoameas_s& trp_measured_results_value_c::set_ul_rtoa() -{ - set(types::ul_rtoa); - return c.get(); -} -gnb_rx_tx_time_diff_s& trp_measured_results_value_c::set_gnb_rx_tx_time_diff() -{ - set(types::gnb_rx_tx_time_diff); - return c.get(); -} -protocol_ie_single_container_s& trp_measured_results_value_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void trp_measured_results_value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::ul_angle_of_arrival: - j.write_fieldname("uL-AngleOfArrival"); - c.get().to_json(j); - break; - case types::ul_srs_rsrp: - j.write_int("uL-SRS-RSRP", c.get()); - break; - case types::ul_rtoa: - j.write_fieldname("uL-RTOA"); - c.get().to_json(j); - break; - case types::gnb_rx_tx_time_diff: - j.write_fieldname("gNB-RxTxTimeDiff"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_measured_results_value_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::ul_angle_of_arrival: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ul_srs_rsrp: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)126u, false, true)); - break; - case types::ul_rtoa: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::gnb_rx_tx_time_diff: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_measured_results_value_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::ul_angle_of_arrival: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ul_srs_rsrp: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)126u, false, true)); - break; - case types::ul_rtoa: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::gnb_rx_tx_time_diff: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_measured_results_value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_measured_results_value_c::types_opts::to_string() const -{ - static const char* names[] = {"uL-AngleOfArrival", "uL-SRS-RSRP", "uL-RTOA", "gNB-RxTxTimeDiff", "choice-extension"}; - return convert_enum_idx(names, 5, value, "trp_measured_results_value_c::types"); -} - -// WLANMeasurementQuantitiesValue ::= ENUMERATED -const char* wlan_meas_quantities_value_opts::to_string() const -{ - static const char* names[] = {"wlan"}; - return convert_enum_idx(names, 1, value, "wlan_meas_quantities_value_e"); -} - -// ActiveULBWP ::= SEQUENCE -SRSASN_CODE active_ul_bwp_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(shift7dot5k_hz_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, location_and_bw, (uint16_t)0u, (uint16_t)37949u, true, true)); - HANDLE_CODE(subcarrier_spacing.pack(bref)); - HANDLE_CODE(cp.pack(bref)); - HANDLE_CODE(pack_integer(bref, tx_direct_current_location, (uint16_t)0u, (uint16_t)3301u, true, true)); - if (shift7dot5k_hz_present) { - HANDLE_CODE(shift7dot5k_hz.pack(bref)); - } - HANDLE_CODE(srs_cfg.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE active_ul_bwp_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(shift7dot5k_hz_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(location_and_bw, bref, (uint16_t)0u, (uint16_t)37949u, true, true)); - HANDLE_CODE(subcarrier_spacing.unpack(bref)); - HANDLE_CODE(cp.unpack(bref)); - HANDLE_CODE(unpack_integer(tx_direct_current_location, bref, (uint16_t)0u, (uint16_t)3301u, true, true)); - if (shift7dot5k_hz_present) { - HANDLE_CODE(shift7dot5k_hz.unpack(bref)); - } - HANDLE_CODE(srs_cfg.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void active_ul_bwp_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("locationAndBandwidth", location_and_bw); - j.write_str("subcarrierSpacing", subcarrier_spacing.to_string()); - j.write_str("cyclicPrefix", cp.to_string()); - j.write_int("txDirectCurrentLocation", tx_direct_current_location); - if (shift7dot5k_hz_present) { - j.write_str("shift7dot5kHz", "true"); - } - j.write_fieldname("sRSConfig"); - srs_cfg.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* active_ul_bwp_s::subcarrier_spacing_opts::to_string() const -{ - static const char* names[] = {"kHz15", "kHz30", "kHz60", "kHz120"}; - return convert_enum_idx(names, 4, value, "active_ul_bwp_s::subcarrier_spacing_e_"); -} -uint8_t active_ul_bwp_s::subcarrier_spacing_opts::to_number() const -{ - static const uint8_t numbers[] = {15, 30, 60, 120}; - return map_enum_number(numbers, 4, value, "active_ul_bwp_s::subcarrier_spacing_e_"); -} - -const char* active_ul_bwp_s::cp_opts::to_string() const -{ - static const char* names[] = {"normal", "extended"}; - return convert_enum_idx(names, 2, value, "active_ul_bwp_s::cp_e_"); -} - -const char* active_ul_bwp_s::shift7dot5k_hz_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "active_ul_bwp_s::shift7dot5k_hz_e_"); -} - -// BroadcastPeriodicity ::= ENUMERATED -const char* broadcast_periodicity_opts::to_string() const -{ - static const char* names[] = {"ms80", "ms160", "ms320", "ms640", "ms1280", "ms2560", "ms5120"}; - return convert_enum_idx(names, 7, value, "broadcast_periodicity_e"); -} -uint16_t broadcast_periodicity_opts::to_number() const -{ - static const uint16_t numbers[] = {80, 160, 320, 640, 1280, 2560, 5120}; - return map_enum_number(numbers, 7, value, "broadcast_periodicity_e"); -} - -// MeasurementQuantities-Item ::= SEQUENCE -SRSASN_CODE meas_quantities_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(meas_quantities_value.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_quantities_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(meas_quantities_value.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void meas_quantities_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("measurementQuantitiesValue", meas_quantities_value.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// OTDOACell-Information-Item ::= CHOICE -void otdoa_cell_info_item_c::destroy_() -{ - switch (type_) { - case types::cgi_eutra: - c.destroy(); - break; - case types::tac: - c.destroy>(); - break; - case types::sfn_initisation_time_eutra: - c.destroy>(); - break; - case types::ng_ran_access_point_position: - c.destroy(); - break; - case types::prs_muting_cfg_eutra: - c.destroy(); - break; - case types::prs_freq_hop_cfg_eutra: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void otdoa_cell_info_item_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::pci_eutra: - break; - case types::cgi_eutra: - c.init(); - break; - case types::tac: - c.init>(); - break; - case types::earfcn: - break; - case types::prs_bw_eutra: - break; - case types::prs_cfg_idx_eutra: - break; - case types::cp_len_eutra: - break; - case types::nof_dl_frames_eutra: - break; - case types::nof_ant_ports_eutra: - break; - case types::sfn_initisation_time_eutra: - c.init>(); - break; - case types::ng_ran_access_point_position: - c.init(); - break; - case types::prs_muting_cfg_eutra: - c.init(); - break; - case types::prsid_eutra: - break; - case types::tpid_eutra: - break; - case types::tp_type_eutra: - break; - case types::nof_dl_frames_extended_eutra: - break; - case types::crs_cp_len_eutra: - break; - case types::dl_bw_eutra: - break; - case types::prs_occasion_group_eutra: - break; - case types::prs_freq_hop_cfg_eutra: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_c"); - } -} -otdoa_cell_info_item_c::otdoa_cell_info_item_c(const otdoa_cell_info_item_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::pci_eutra: - c.init(other.c.get()); - break; - case types::cgi_eutra: - c.init(other.c.get()); - break; - case types::tac: - c.init(other.c.get>()); - break; - case types::earfcn: - c.init(other.c.get()); - break; - case types::prs_bw_eutra: - c.init(other.c.get()); - break; - case types::prs_cfg_idx_eutra: - c.init(other.c.get()); - break; - case types::cp_len_eutra: - c.init(other.c.get()); - break; - case types::nof_dl_frames_eutra: - c.init(other.c.get()); - break; - case types::nof_ant_ports_eutra: - c.init(other.c.get()); - break; - case types::sfn_initisation_time_eutra: - c.init(other.c.get>()); - break; - case types::ng_ran_access_point_position: - c.init(other.c.get()); - break; - case types::prs_muting_cfg_eutra: - c.init(other.c.get()); - break; - case types::prsid_eutra: - c.init(other.c.get()); - break; - case types::tpid_eutra: - c.init(other.c.get()); - break; - case types::tp_type_eutra: - c.init(other.c.get()); - break; - case types::nof_dl_frames_extended_eutra: - c.init(other.c.get()); - break; - case types::crs_cp_len_eutra: - c.init(other.c.get()); - break; - case types::dl_bw_eutra: - c.init(other.c.get()); - break; - case types::prs_occasion_group_eutra: - c.init(other.c.get()); - break; - case types::prs_freq_hop_cfg_eutra: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_c"); - } -} -otdoa_cell_info_item_c& otdoa_cell_info_item_c::operator=(const otdoa_cell_info_item_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::pci_eutra: - c.set(other.c.get()); - break; - case types::cgi_eutra: - c.set(other.c.get()); - break; - case types::tac: - c.set(other.c.get>()); - break; - case types::earfcn: - c.set(other.c.get()); - break; - case types::prs_bw_eutra: - c.set(other.c.get()); - break; - case types::prs_cfg_idx_eutra: - c.set(other.c.get()); - break; - case types::cp_len_eutra: - c.set(other.c.get()); - break; - case types::nof_dl_frames_eutra: - c.set(other.c.get()); - break; - case types::nof_ant_ports_eutra: - c.set(other.c.get()); - break; - case types::sfn_initisation_time_eutra: - c.set(other.c.get>()); - break; - case types::ng_ran_access_point_position: - c.set(other.c.get()); - break; - case types::prs_muting_cfg_eutra: - c.set(other.c.get()); - break; - case types::prsid_eutra: - c.set(other.c.get()); - break; - case types::tpid_eutra: - c.set(other.c.get()); - break; - case types::tp_type_eutra: - c.set(other.c.get()); - break; - case types::nof_dl_frames_extended_eutra: - c.set(other.c.get()); - break; - case types::crs_cp_len_eutra: - c.set(other.c.get()); - break; - case types::dl_bw_eutra: - c.set(other.c.get()); - break; - case types::prs_occasion_group_eutra: - c.set(other.c.get()); - break; - case types::prs_freq_hop_cfg_eutra: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_c"); - } - - return *this; -} -uint16_t& otdoa_cell_info_item_c::set_pci_eutra() -{ - set(types::pci_eutra); - return c.get(); -} -cgi_eutra_s& otdoa_cell_info_item_c::set_cgi_eutra() -{ - set(types::cgi_eutra); - return c.get(); -} -fixed_octstring<3, true>& otdoa_cell_info_item_c::set_tac() -{ - set(types::tac); - return c.get>(); -} -uint32_t& otdoa_cell_info_item_c::set_earfcn() -{ - set(types::earfcn); - return c.get(); -} -prs_bw_eutra_e& otdoa_cell_info_item_c::set_prs_bw_eutra() -{ - set(types::prs_bw_eutra); - return c.get(); -} -uint16_t& otdoa_cell_info_item_c::set_prs_cfg_idx_eutra() -{ - set(types::prs_cfg_idx_eutra); - return c.get(); -} -cp_len_eutra_e& otdoa_cell_info_item_c::set_cp_len_eutra() -{ - set(types::cp_len_eutra); - return c.get(); -} -nof_dl_frames_eutra_e& otdoa_cell_info_item_c::set_nof_dl_frames_eutra() -{ - set(types::nof_dl_frames_eutra); - return c.get(); -} -nof_ant_ports_eutra_e& otdoa_cell_info_item_c::set_nof_ant_ports_eutra() -{ - set(types::nof_ant_ports_eutra); - return c.get(); -} -fixed_bitstring<64, false, true>& otdoa_cell_info_item_c::set_sfn_initisation_time_eutra() -{ - set(types::sfn_initisation_time_eutra); - return c.get>(); -} -ng_ran_access_point_position_s& otdoa_cell_info_item_c::set_ng_ran_access_point_position() -{ - set(types::ng_ran_access_point_position); - return c.get(); -} -prs_muting_cfg_eutra_c& otdoa_cell_info_item_c::set_prs_muting_cfg_eutra() -{ - set(types::prs_muting_cfg_eutra); - return c.get(); -} -uint16_t& otdoa_cell_info_item_c::set_prsid_eutra() -{ - set(types::prsid_eutra); - return c.get(); -} -uint16_t& otdoa_cell_info_item_c::set_tpid_eutra() -{ - set(types::tpid_eutra); - return c.get(); -} -tp_type_eutra_e& otdoa_cell_info_item_c::set_tp_type_eutra() -{ - set(types::tp_type_eutra); - return c.get(); -} -uint8_t& otdoa_cell_info_item_c::set_nof_dl_frames_extended_eutra() -{ - set(types::nof_dl_frames_extended_eutra); - return c.get(); -} -cp_len_eutra_e& otdoa_cell_info_item_c::set_crs_cp_len_eutra() -{ - set(types::crs_cp_len_eutra); - return c.get(); -} -dl_bw_eutra_e& otdoa_cell_info_item_c::set_dl_bw_eutra() -{ - set(types::dl_bw_eutra); - return c.get(); -} -prs_occasion_group_eutra_e& otdoa_cell_info_item_c::set_prs_occasion_group_eutra() -{ - set(types::prs_occasion_group_eutra); - return c.get(); -} -prs_freq_hop_cfg_eutra_s& otdoa_cell_info_item_c::set_prs_freq_hop_cfg_eutra() -{ - set(types::prs_freq_hop_cfg_eutra); - return c.get(); -} -protocol_ie_single_container_s& otdoa_cell_info_item_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void otdoa_cell_info_item_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::pci_eutra: - j.write_int("pCI-EUTRA", c.get()); - break; - case types::cgi_eutra: - j.write_fieldname("cGI-EUTRA"); - c.get().to_json(j); - break; - case types::tac: - j.write_str("tAC", c.get>().to_string()); - break; - case types::earfcn: - j.write_int("eARFCN", c.get()); - break; - case types::prs_bw_eutra: - j.write_str("pRS-Bandwidth-EUTRA", c.get().to_string()); - break; - case types::prs_cfg_idx_eutra: - j.write_int("pRS-ConfigurationIndex-EUTRA", c.get()); - break; - case types::cp_len_eutra: - j.write_str("cPLength-EUTRA", c.get().to_string()); - break; - case types::nof_dl_frames_eutra: - j.write_str("numberOfDlFrames-EUTRA", c.get().to_string()); - break; - case types::nof_ant_ports_eutra: - j.write_str("numberOfAntennaPorts-EUTRA", c.get().to_string()); - break; - case types::sfn_initisation_time_eutra: - j.write_str("sFNInitialisationTime-EUTRA", c.get>().to_string()); - break; - case types::ng_ran_access_point_position: - j.write_fieldname("nG-RANAccessPointPosition"); - c.get().to_json(j); - break; - case types::prs_muting_cfg_eutra: - j.write_fieldname("pRSMutingConfiguration-EUTRA"); - c.get().to_json(j); - break; - case types::prsid_eutra: - j.write_int("prsid-EUTRA", c.get()); - break; - case types::tpid_eutra: - j.write_int("tpid-EUTRA", c.get()); - break; - case types::tp_type_eutra: - j.write_str("tpType-EUTRA", "prs-only-tp"); - break; - case types::nof_dl_frames_extended_eutra: - j.write_int("numberOfDlFrames-Extended-EUTRA", c.get()); - break; - case types::crs_cp_len_eutra: - j.write_str("crsCPlength-EUTRA", c.get().to_string()); - break; - case types::dl_bw_eutra: - j.write_str("dL-Bandwidth-EUTRA", c.get().to_string()); - break; - case types::prs_occasion_group_eutra: - j.write_str("pRSOccasionGroup-EUTRA", c.get().to_string()); - break; - case types::prs_freq_hop_cfg_eutra: - j.write_fieldname("pRSFrequencyHoppingConfiguration-EUTRA"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_c"); - } - j.end_obj(); -} -SRSASN_CODE otdoa_cell_info_item_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::pci_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)503u, true, true)); - break; - case types::cgi_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::tac: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::earfcn: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)0u, (uint32_t)262143u, true, true)); - break; - case types::prs_bw_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_idx_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::cp_len_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nof_dl_frames_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nof_ant_ports_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sfn_initisation_time_eutra: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::ng_ran_access_point_position: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_muting_cfg_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prsid_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::tpid_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::tp_type_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::nof_dl_frames_extended_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)160u, true, true)); - break; - case types::crs_cp_len_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::dl_bw_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_occasion_group_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_freq_hop_cfg_eutra: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_cell_info_item_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::pci_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)503u, true, true)); - break; - case types::cgi_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::tac: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::earfcn: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)0u, (uint32_t)262143u, true, true)); - break; - case types::prs_bw_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_idx_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::cp_len_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nof_dl_frames_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nof_ant_ports_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sfn_initisation_time_eutra: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::ng_ran_access_point_position: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_muting_cfg_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prsid_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::tpid_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::tp_type_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::nof_dl_frames_extended_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)160u, true, true)); - break; - case types::crs_cp_len_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::dl_bw_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_occasion_group_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_freq_hop_cfg_eutra: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "otdoa_cell_info_item_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* otdoa_cell_info_item_c::types_opts::to_string() const -{ - static const char* names[] = {"pCI-EUTRA", - "cGI-EUTRA", - "tAC", - "eARFCN", - "pRS-Bandwidth-EUTRA", - "pRS-ConfigurationIndex-EUTRA", - "cPLength-EUTRA", - "numberOfDlFrames-EUTRA", - "numberOfAntennaPorts-EUTRA", - "sFNInitialisationTime-EUTRA", - "nG-RANAccessPointPosition", - "pRSMutingConfiguration-EUTRA", - "prsid-EUTRA", - "tpid-EUTRA", - "tpType-EUTRA", - "numberOfDlFrames-Extended-EUTRA", - "crsCPlength-EUTRA", - "dL-Bandwidth-EUTRA", - "pRSOccasionGroup-EUTRA", - "pRSFrequencyHoppingConfiguration-EUTRA", - "choice-Extension"}; - return convert_enum_idx(names, 21, value, "otdoa_cell_info_item_c::types"); -} - -// OTDOA-Information-Item ::= ENUMERATED -const char* otdoa_info_item_opts::to_string() const -{ - static const char* names[] = {"pci", - "cGI", - "tac", - "earfcn", - "prsBandwidth", - "prsConfigIndex", - "cpLength", - "noDlFrames", - "noAntennaPorts", - "sFNInitTime", - "nG-RANAccessPointPosition", - "prsmutingconfiguration", - "prsid", - "tpid", - "tpType", - "crsCPlength", - "dlBandwidth", - "multipleprsConfigurationsperCell", - "prsOccasionGroup", - "prsFrequencyHoppingConfiguration", - "tddConfig"}; - return convert_enum_idx(names, 21, value, "otdoa_info_item_e"); -} - -// OtherRATMeasurementQuantities-Item ::= SEQUENCE -SRSASN_CODE other_rat_meas_quantities_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(other_rat_meas_quantities_value.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE other_rat_meas_quantities_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(other_rat_meas_quantities_value.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void other_rat_meas_quantities_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("otherRATMeasurementQuantitiesValue", other_rat_meas_quantities_value.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// OtherRATMeasuredResultsValue-ExtensionIE ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t other_rat_measured_results_value_ext_ie_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {55, 56}; - return map_enum_number(names, 2, idx, "id"); -} -bool other_rat_measured_results_value_ext_ie_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {55, 56}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e other_rat_measured_results_value_ext_ie_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 55: - return crit_e::ignore; - case 56: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -other_rat_measured_results_value_ext_ie_o::value_c -other_rat_measured_results_value_ext_ie_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 55: - ret.set(value_c::types::result_nr); - break; - case 56: - ret.set(value_c::types::result_eutra); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e other_rat_measured_results_value_ext_ie_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 55: - return presence_e::mandatory; - case 56: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void other_rat_measured_results_value_ext_ie_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::result_nr: - c = result_nr_l{}; - break; - case types::result_eutra: - c = result_eutra_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_ext_ie_o::value_c"); - } -} -result_nr_l& other_rat_measured_results_value_ext_ie_o::value_c::result_nr() -{ - assert_choice_type(types::result_nr, type_, "Value"); - return c.get(); -} -result_eutra_l& other_rat_measured_results_value_ext_ie_o::value_c::result_eutra() -{ - assert_choice_type(types::result_eutra, type_, "Value"); - return c.get(); -} -const result_nr_l& other_rat_measured_results_value_ext_ie_o::value_c::result_nr() const -{ - assert_choice_type(types::result_nr, type_, "Value"); - return c.get(); -} -const result_eutra_l& other_rat_measured_results_value_ext_ie_o::value_c::result_eutra() const -{ - assert_choice_type(types::result_eutra, type_, "Value"); - return c.get(); -} -void other_rat_measured_results_value_ext_ie_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::result_nr: - j.start_array("ResultNR"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::result_eutra: - j.start_array("ResultEUTRA"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_ext_ie_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE other_rat_measured_results_value_ext_ie_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::result_nr: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::result_eutra: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_ext_ie_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE other_rat_measured_results_value_ext_ie_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::result_nr: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::result_eutra: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_ext_ie_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* other_rat_measured_results_value_ext_ie_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"ResultNR", "ResultEUTRA"}; - return convert_enum_idx(names, 2, value, "other_rat_measured_results_value_ext_ie_o::value_c::types"); -} - -// PathlossReferenceSignal ::= CHOICE -void pathloss_ref_sig_c::destroy_() -{ - switch (type_) { - case types::ssb_ref: - c.destroy(); - break; - case types::dl_prs_ref: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void pathloss_ref_sig_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::ssb_ref: - c.init(); - break; - case types::dl_prs_ref: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "pathloss_ref_sig_c"); - } -} -pathloss_ref_sig_c::pathloss_ref_sig_c(const pathloss_ref_sig_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::ssb_ref: - c.init(other.c.get()); - break; - case types::dl_prs_ref: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "pathloss_ref_sig_c"); - } -} -pathloss_ref_sig_c& pathloss_ref_sig_c::operator=(const pathloss_ref_sig_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::ssb_ref: - c.set(other.c.get()); - break; - case types::dl_prs_ref: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "pathloss_ref_sig_c"); - } - - return *this; -} -ssb_s& pathloss_ref_sig_c::set_ssb_ref() -{ - set(types::ssb_ref); - return c.get(); -} -dl_prs_s& pathloss_ref_sig_c::set_dl_prs_ref() -{ - set(types::dl_prs_ref); - return c.get(); -} -protocol_ie_single_container_s& pathloss_ref_sig_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void pathloss_ref_sig_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::ssb_ref: - j.write_fieldname("sSB-Reference"); - c.get().to_json(j); - break; - case types::dl_prs_ref: - j.write_fieldname("dL-PRS-Reference"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "pathloss_ref_sig_c"); - } - j.end_obj(); -} -SRSASN_CODE pathloss_ref_sig_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::ssb_ref: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::dl_prs_ref: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "pathloss_ref_sig_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE pathloss_ref_sig_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::ssb_ref: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::dl_prs_ref: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "pathloss_ref_sig_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* pathloss_ref_sig_c::types_opts::to_string() const -{ - static const char* names[] = {"sSB-Reference", "dL-PRS-Reference", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "pathloss_ref_sig_c::types"); -} - -// PeriodicityItem ::= ENUMERATED -const char* periodicity_item_opts::to_string() const -{ - static const char* names[] = {"ms0dot125", "ms0dot25", "ms0dot5", "ms0dot625", "ms1", "ms1dot25", "ms2", - "ms2dot5", "ms4dot", "ms5", "ms8", "ms10", "ms16", "ms20", - "ms32", "ms40", "ms64", "ms80m", "ms160", "ms320", "ms640m", - "ms1280", "ms2560", "ms5120", "ms10240"}; - return convert_enum_idx(names, 25, value, "periodicity_item_e"); -} -float periodicity_item_opts::to_number() const -{ - static const float numbers[] = {0.125, 0.25, 0.5, 0.625, 1.0, 1.25, 2.0, 2.5, 4.0, - 5.0, 8.0, 10.0, 16.0, 20.0, 32.0, 40.0, 64.0, 80.0, - 160.0, 320.0, 640.0, 1280.0, 2560.0, 5120.0, 10240.0}; - return map_enum_number(numbers, 25, value, "periodicity_item_e"); -} -const char* periodicity_item_opts::to_number_string() const -{ - static const char* number_strs[] = {"0.125", "0.25", "0.5", "0.625", "1", "1.25", "2", "2.5", "4", - "5", "8", "10", "16", "20", "32", "40", "64", "80", - "160", "320", "640", "1280", "2560", "5120", "10240"}; - return convert_enum_idx(number_strs, 25, value, "periodicity_item_e"); -} - -template struct asn1::protocol_ext_field_s; - -template struct asn1::protocol_ext_field_s; - -template struct asn1::protocol_ext_field_s; - -template struct asn1::protocol_ie_single_container_s; - -// PRSTransmissionOffIndication ::= CHOICE -void prs_tx_off_ind_c::destroy_() -{ - switch (type_) { - case types::prs_tx_off_per_res_set: - c.destroy(); - break; - case types::prs_tx_off_per_res: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void prs_tx_off_ind_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::prs_tx_off_per_trp: - break; - case types::prs_tx_off_per_res_set: - c.init(); - break; - case types::prs_tx_off_per_res: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_tx_off_ind_c"); - } -} -prs_tx_off_ind_c::prs_tx_off_ind_c(const prs_tx_off_ind_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::prs_tx_off_per_trp: - break; - case types::prs_tx_off_per_res_set: - c.init(other.c.get()); - break; - case types::prs_tx_off_per_res: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_tx_off_ind_c"); - } -} -prs_tx_off_ind_c& prs_tx_off_ind_c::operator=(const prs_tx_off_ind_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::prs_tx_off_per_trp: - break; - case types::prs_tx_off_per_res_set: - c.set(other.c.get()); - break; - case types::prs_tx_off_per_res: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_tx_off_ind_c"); - } - - return *this; -} -void prs_tx_off_ind_c::set_prs_tx_off_per_trp() -{ - set(types::prs_tx_off_per_trp); -} -prs_tx_off_per_res_set_l& prs_tx_off_ind_c::set_prs_tx_off_per_res_set() -{ - set(types::prs_tx_off_per_res_set); - return c.get(); -} -prs_tx_off_per_res_l& prs_tx_off_ind_c::set_prs_tx_off_per_res() -{ - set(types::prs_tx_off_per_res); - return c.get(); -} -protocol_ie_single_container_s& prs_tx_off_ind_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void prs_tx_off_ind_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::prs_tx_off_per_trp: - break; - case types::prs_tx_off_per_res_set: - j.start_array("pRSTransmissionOffPerResourceSet"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::prs_tx_off_per_res: - j.start_array("pRSTransmissionOffPerResource"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "prs_tx_off_ind_c"); - } - j.end_obj(); -} -SRSASN_CODE prs_tx_off_ind_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::prs_tx_off_per_trp: - break; - case types::prs_tx_off_per_res_set: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::prs_tx_off_per_res: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_tx_off_ind_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_tx_off_ind_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::prs_tx_off_per_trp: - break; - case types::prs_tx_off_per_res_set: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::prs_tx_off_per_res: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_tx_off_ind_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* prs_tx_off_ind_c::types_opts::to_string() const -{ - static const char* names[] = {"pRSTransmissionOffPerTRP", - "pRSTransmissionOffPerResourceSet", - "pRSTransmissionOffPerResource", - "choice-Extension"}; - return convert_enum_idx(names, 4, value, "prs_tx_off_ind_c::types"); -} - -// ResultGERAN-Item ::= SEQUENCE -SRSASN_CODE result_geran_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, bcch, (uint16_t)0u, (uint16_t)1023u, true, true)); - HANDLE_CODE(pack_integer(bref, pci_geran, (uint8_t)0u, (uint8_t)63u, true, true)); - HANDLE_CODE(pack_integer(bref, rssi, (uint8_t)0u, (uint8_t)63u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_geran_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(bcch, bref, (uint16_t)0u, (uint16_t)1023u, true, true)); - HANDLE_CODE(unpack_integer(pci_geran, bref, (uint8_t)0u, (uint8_t)63u, true, true)); - HANDLE_CODE(unpack_integer(rssi, bref, (uint8_t)0u, (uint8_t)63u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_geran_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("bCCH", bcch); - j.write_int("physCellIDGERAN", pci_geran); - j.write_int("rSSI", rssi); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// ResultUTRAN-Item ::= SEQUENCE -SRSASN_CODE result_utran_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(utra_rs_cp_present, 1)); - HANDLE_CODE(bref.pack(utra_ec_n0_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, uarfcn, (uint16_t)0u, (uint16_t)16383u, true, true)); - HANDLE_CODE(pci_utran.pack(bref)); - if (utra_rs_cp_present) { - HANDLE_CODE(pack_integer(bref, utra_rs_cp, (int8_t)-5, (int8_t)91, true, true)); - } - if (utra_ec_n0_present) { - HANDLE_CODE(pack_integer(bref, utra_ec_n0, (uint8_t)0u, (uint8_t)49u, true, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE result_utran_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(utra_rs_cp_present, 1)); - HANDLE_CODE(bref.unpack(utra_ec_n0_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(uarfcn, bref, (uint16_t)0u, (uint16_t)16383u, true, true)); - HANDLE_CODE(pci_utran.unpack(bref)); - if (utra_rs_cp_present) { - HANDLE_CODE(unpack_integer(utra_rs_cp, bref, (int8_t)-5, (int8_t)91, true, true)); - } - if (utra_ec_n0_present) { - HANDLE_CODE(unpack_integer(utra_ec_n0, bref, (uint8_t)0u, (uint8_t)49u, true, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void result_utran_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("uARFCN", uarfcn); - j.write_fieldname("physCellIDUTRAN"); - pci_utran.to_json(j); - if (utra_rs_cp_present) { - j.write_int("uTRA-RSCP", utra_rs_cp); - } - if (utra_ec_n0_present) { - j.write_int("uTRA-EcN0", utra_ec_n0); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -void result_utran_item_s::pci_utran_c_::destroy_() {} -void result_utran_item_s::pci_utran_c_::set(types::options e) -{ - destroy_(); - type_ = e; -} -result_utran_item_s::pci_utran_c_::pci_utran_c_(const result_utran_item_s::pci_utran_c_& other) -{ - type_ = other.type(); - switch (type_) { - case types::phys_cell_i_du_tra_fdd: - c.init(other.c.get()); - break; - case types::phys_cell_i_du_tra_tdd: - c.init(other.c.get()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "result_utran_item_s::pci_utran_c_"); - } -} -result_utran_item_s::pci_utran_c_& -result_utran_item_s::pci_utran_c_::operator=(const result_utran_item_s::pci_utran_c_& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::phys_cell_i_du_tra_fdd: - c.set(other.c.get()); - break; - case types::phys_cell_i_du_tra_tdd: - c.set(other.c.get()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "result_utran_item_s::pci_utran_c_"); - } - - return *this; -} -uint16_t& result_utran_item_s::pci_utran_c_::set_phys_cell_i_du_tra_fdd() -{ - set(types::phys_cell_i_du_tra_fdd); - return c.get(); -} -uint8_t& result_utran_item_s::pci_utran_c_::set_phys_cell_i_du_tra_tdd() -{ - set(types::phys_cell_i_du_tra_tdd); - return c.get(); -} -void result_utran_item_s::pci_utran_c_::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::phys_cell_i_du_tra_fdd: - j.write_int("physCellIDUTRA-FDD", c.get()); - break; - case types::phys_cell_i_du_tra_tdd: - j.write_int("physCellIDUTRA-TDD", c.get()); - break; - default: - log_invalid_choice_id(type_, "result_utran_item_s::pci_utran_c_"); - } - j.end_obj(); -} -SRSASN_CODE result_utran_item_s::pci_utran_c_::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::phys_cell_i_du_tra_fdd: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)511u, true, true)); - break; - case types::phys_cell_i_du_tra_tdd: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)127u, true, true)); - break; - default: - log_invalid_choice_id(type_, "result_utran_item_s::pci_utran_c_"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE result_utran_item_s::pci_utran_c_::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::phys_cell_i_du_tra_fdd: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)511u, true, true)); - break; - case types::phys_cell_i_du_tra_tdd: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)127u, true, true)); - break; - default: - log_invalid_choice_id(type_, "result_utran_item_s::pci_utran_c_"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* result_utran_item_s::pci_utran_c_::types_opts::to_string() const -{ - static const char* names[] = {"physCellIDUTRA-FDD", "physCellIDUTRA-TDD"}; - return convert_enum_idx(names, 2, value, "result_utran_item_s::pci_utran_c_::types"); -} - -// SRSResourceSet-Item-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t srs_res_set_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {63}; - return map_enum_number(names, 1, idx, "id"); -} -bool srs_res_set_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 63 == id; -} -crit_e srs_res_set_item_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 63) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -srs_res_set_item_ext_ies_o::ext_c srs_res_set_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 63) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e srs_res_set_item_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 63) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void srs_res_set_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("SpatialRelationPerSRSResource"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE srs_res_set_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_set_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* srs_res_set_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"SpatialRelationPerSRSResource"}; - return convert_enum_idx(names, 1, value, "srs_res_set_item_ext_ies_o::ext_c::types"); -} - -// TRPInformationTypeItem ::= ENUMERATED -const char* trp_info_type_item_opts::to_string() const -{ - static const char* names[] = {"nrPCI", - "nG-RAN-CGI", - "arfcn", - "pRSConfig", - "sSBInfo", - "sFNInitTime", - "spatialDirectInfo", - "geoCoord", - "trp-type", - "ondemandPRSInfo", - "trpTxTeg", - "beam-antenna-info"}; - return convert_enum_idx(names, 12, value, "trp_info_type_item_e"); -} - -// TRP-MeasurementResponseItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t trp_meas_resp_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {60}; - return map_enum_number(names, 1, idx, "id"); -} -bool trp_meas_resp_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 60 == id; -} -crit_e trp_meas_resp_item_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 60) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -trp_meas_resp_item_ext_ies_o::ext_c trp_meas_resp_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 60) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_meas_resp_item_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 60) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void trp_meas_resp_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("CGI-NR"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE trp_meas_resp_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_resp_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* trp_meas_resp_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"CGI-NR"}; - return convert_enum_idx(names, 1, value, "trp_meas_resp_item_ext_ies_o::ext_c::types"); -} - -// TrpMeasurementResultItem ::= SEQUENCE -SRSASN_CODE trp_meas_result_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(meas_quality_present, 1)); - HANDLE_CODE(bref.pack(meas_beam_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(measured_results_value.pack(bref)); - HANDLE_CODE(time_stamp.pack(bref)); - if (meas_quality_present) { - HANDLE_CODE(meas_quality.pack(bref)); - } - if (meas_beam_info_present) { - HANDLE_CODE(meas_beam_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_result_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(meas_quality_present, 1)); - HANDLE_CODE(bref.unpack(meas_beam_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(measured_results_value.unpack(bref)); - HANDLE_CODE(time_stamp.unpack(bref)); - if (meas_quality_present) { - HANDLE_CODE(meas_quality.unpack(bref)); - } - if (meas_beam_info_present) { - HANDLE_CODE(meas_beam_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_result_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("measuredResultsValue"); - measured_results_value.to_json(j); - j.write_fieldname("timeStamp"); - time_stamp.to_json(j); - if (meas_quality_present) { - j.write_fieldname("measurementQuality"); - meas_quality.to_json(j); - } - if (meas_beam_info_present) { - j.write_fieldname("measurementBeamInfo"); - meas_beam_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TypeOfError ::= ENUMERATED -const char* type_of_error_opts::to_string() const -{ - static const char* names[] = {"not-understood", "missing"}; - return convert_enum_idx(names, 2, value, "type_of_error_e"); -} - -// UETxTEGAssociationItem-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t ue_tx_teg_assoc_item_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {104}; - return map_enum_number(names, 1, idx, "id"); -} -bool ue_tx_teg_assoc_item_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 104 == id; -} -crit_e ue_tx_teg_assoc_item_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 104) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -ue_tx_teg_assoc_item_ext_ies_o::ext_c ue_tx_teg_assoc_item_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 104) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e ue_tx_teg_assoc_item_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 104) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void ue_tx_teg_assoc_item_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("TimingErrorMargin", c.to_string()); - j.end_obj(); -} -SRSASN_CODE ue_tx_teg_assoc_item_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE ue_tx_teg_assoc_item_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* ue_tx_teg_assoc_item_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"TimingErrorMargin"}; - return convert_enum_idx(names, 1, value, "ue_tx_teg_assoc_item_ext_ies_o::ext_c::types"); -} - -// WLANMeasurementQuantities-Item ::= SEQUENCE -SRSASN_CODE wlan_meas_quantities_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(wlan_meas_quantities_value.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE wlan_meas_quantities_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(wlan_meas_quantities_value.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void wlan_meas_quantities_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("wLANMeasurementQuantitiesValue", "wlan"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// CarrierFreq ::= SEQUENCE -SRSASN_CODE carrier_freq_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, point_a, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(pack_integer(bref, offset_to_carrier, (uint16_t)0u, (uint16_t)2199u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE carrier_freq_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(point_a, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(unpack_integer(offset_to_carrier, bref, (uint16_t)0u, (uint16_t)2199u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void carrier_freq_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pointA", point_a); - j.write_int("offsetToCarrier", offset_to_carrier); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE crit_diagnostics_ie_list_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(ie_crit.pack(bref)); - HANDLE_CODE(pack_integer(bref, ie_id, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(type_of_error.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE crit_diagnostics_ie_list_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(ie_crit.unpack(bref)); - HANDLE_CODE(unpack_integer(ie_id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(type_of_error.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void crit_diagnostics_ie_list_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("iECriticality", ie_crit.to_string()); - j.write_int("iE-ID", ie_id); - j.write_str("typeOfError", type_of_error.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// E-CID-MeasurementResult-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t e_c_id_meas_result_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {37}; - return map_enum_number(names, 1, idx, "id"); -} -bool e_c_id_meas_result_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 37 == id; -} -crit_e e_c_id_meas_result_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 37) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -e_c_id_meas_result_ext_ies_o::ext_c e_c_id_meas_result_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 37) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_result_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 37) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void e_c_id_meas_result_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("GeographicalCoordinates"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_result_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_result_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_result_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"GeographicalCoordinates"}; - return convert_enum_idx(names, 1, value, "e_c_id_meas_result_ext_ies_o::ext_c::types"); -} - -// MeasurementQuantities-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_quantities_item_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {11}; - return map_enum_number(names, 1, idx, "id"); -} -bool meas_quantities_item_ies_o::is_id_valid(const uint32_t& id) -{ - return 11 == id; -} -crit_e meas_quantities_item_ies_o::get_crit(const uint32_t& id) -{ - if (id == 11) { - return crit_e::reject; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -meas_quantities_item_ies_o::value_c meas_quantities_item_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 11) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_quantities_item_ies_o::get_presence(const uint32_t& id) -{ - if (id == 11) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void meas_quantities_item_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("MeasurementQuantities-Item"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE meas_quantities_item_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_quantities_item_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* meas_quantities_item_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"MeasurementQuantities-Item"}; - return convert_enum_idx(names, 1, value, "meas_quantities_item_ies_o::value_c::types"); -} - -// MeasuredResultsValue ::= CHOICE -void measured_results_value_c::destroy_() -{ - switch (type_) { - case types::result_rsrp_eutra: - c.destroy(); - break; - case types::result_rsrq_eutra: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void measured_results_value_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::value_angle_of_arrival_eutra: - break; - case types::value_timing_advance_type1_eutra: - break; - case types::value_timing_advance_type2_eutra: - break; - case types::result_rsrp_eutra: - c.init(); - break; - case types::result_rsrq_eutra: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "measured_results_value_c"); - } -} -measured_results_value_c::measured_results_value_c(const measured_results_value_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::value_angle_of_arrival_eutra: - c.init(other.c.get()); - break; - case types::value_timing_advance_type1_eutra: - c.init(other.c.get()); - break; - case types::value_timing_advance_type2_eutra: - c.init(other.c.get()); - break; - case types::result_rsrp_eutra: - c.init(other.c.get()); - break; - case types::result_rsrq_eutra: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "measured_results_value_c"); - } -} -measured_results_value_c& measured_results_value_c::operator=(const measured_results_value_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::value_angle_of_arrival_eutra: - c.set(other.c.get()); - break; - case types::value_timing_advance_type1_eutra: - c.set(other.c.get()); - break; - case types::value_timing_advance_type2_eutra: - c.set(other.c.get()); - break; - case types::result_rsrp_eutra: - c.set(other.c.get()); - break; - case types::result_rsrq_eutra: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "measured_results_value_c"); - } - - return *this; -} -uint16_t& measured_results_value_c::set_value_angle_of_arrival_eutra() -{ - set(types::value_angle_of_arrival_eutra); - return c.get(); -} -uint16_t& measured_results_value_c::set_value_timing_advance_type1_eutra() -{ - set(types::value_timing_advance_type1_eutra); - return c.get(); -} -uint16_t& measured_results_value_c::set_value_timing_advance_type2_eutra() -{ - set(types::value_timing_advance_type2_eutra); - return c.get(); -} -result_rsrp_eutra_l& measured_results_value_c::set_result_rsrp_eutra() -{ - set(types::result_rsrp_eutra); - return c.get(); -} -result_rsrq_eutra_l& measured_results_value_c::set_result_rsrq_eutra() -{ - set(types::result_rsrq_eutra); - return c.get(); -} -protocol_ie_single_container_s& measured_results_value_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void measured_results_value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::value_angle_of_arrival_eutra: - j.write_int("valueAngleOfArrival-EUTRA", c.get()); - break; - case types::value_timing_advance_type1_eutra: - j.write_int("valueTimingAdvanceType1-EUTRA", c.get()); - break; - case types::value_timing_advance_type2_eutra: - j.write_int("valueTimingAdvanceType2-EUTRA", c.get()); - break; - case types::result_rsrp_eutra: - j.start_array("resultRSRP-EUTRA"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::result_rsrq_eutra: - j.start_array("resultRSRQ-EUTRA"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "measured_results_value_c"); - } - j.end_obj(); -} -SRSASN_CODE measured_results_value_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::value_angle_of_arrival_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)719u, false, true)); - break; - case types::value_timing_advance_type1_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)7690u, false, true)); - break; - case types::value_timing_advance_type2_eutra: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)7690u, false, true)); - break; - case types::result_rsrp_eutra: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 9, true)); - break; - case types::result_rsrq_eutra: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 9, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "measured_results_value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE measured_results_value_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::value_angle_of_arrival_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)719u, false, true)); - break; - case types::value_timing_advance_type1_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)7690u, false, true)); - break; - case types::value_timing_advance_type2_eutra: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)7690u, false, true)); - break; - case types::result_rsrp_eutra: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 9, true)); - break; - case types::result_rsrq_eutra: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 9, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "measured_results_value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* measured_results_value_c::types_opts::to_string() const -{ - static const char* names[] = {"valueAngleOfArrival-EUTRA", - "valueTimingAdvanceType1-EUTRA", - "valueTimingAdvanceType2-EUTRA", - "resultRSRP-EUTRA", - "resultRSRQ-EUTRA", - "choice-Extension"}; - return convert_enum_idx(names, 6, value, "measured_results_value_c::types"); -} -uint8_t measured_results_value_c::types_opts::to_number() const -{ - switch (value) { - case value_timing_advance_type1_eutra: - return 1; - case value_timing_advance_type2_eutra: - return 2; - default: - invalid_enum_number(value, "measured_results_value_c::types"); - } - return 0; -} - -// NG-RANCell ::= CHOICE -void ng_ran_cell_c::destroy_() -{ - switch (type_) { - case types::eutra_cell_id: - c.destroy>(); - break; - case types::nr_cell_id: - c.destroy>(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void ng_ran_cell_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::eutra_cell_id: - c.init>(); - break; - case types::nr_cell_id: - c.init>(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ng_ran_cell_c"); - } -} -ng_ran_cell_c::ng_ran_cell_c(const ng_ran_cell_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::eutra_cell_id: - c.init(other.c.get>()); - break; - case types::nr_cell_id: - c.init(other.c.get>()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ng_ran_cell_c"); - } -} -ng_ran_cell_c& ng_ran_cell_c::operator=(const ng_ran_cell_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::eutra_cell_id: - c.set(other.c.get>()); - break; - case types::nr_cell_id: - c.set(other.c.get>()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "ng_ran_cell_c"); - } - - return *this; -} -fixed_bitstring<28, false, true>& ng_ran_cell_c::set_eutra_cell_id() -{ - set(types::eutra_cell_id); - return c.get>(); -} -fixed_bitstring<36, false, true>& ng_ran_cell_c::set_nr_cell_id() -{ - set(types::nr_cell_id); - return c.get>(); -} -protocol_ie_single_container_s& ng_ran_cell_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void ng_ran_cell_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::eutra_cell_id: - j.write_str("eUTRA-CellID", c.get>().to_string()); - break; - case types::nr_cell_id: - j.write_str("nR-CellID", c.get>().to_string()); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "ng_ran_cell_c"); - } - j.end_obj(); -} -SRSASN_CODE ng_ran_cell_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::eutra_cell_id: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::nr_cell_id: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "ng_ran_cell_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE ng_ran_cell_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::eutra_cell_id: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::nr_cell_id: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "ng_ran_cell_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* ng_ran_cell_c::types_opts::to_string() const -{ - static const char* names[] = {"eUTRA-CellID", "nR-CellID", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "ng_ran_cell_c::types"); -} - -// OTDOA-Information-Type-Item ::= SEQUENCE -SRSASN_CODE otdoa_info_type_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(otdoa_info_item.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_type_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(otdoa_info_item.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void otdoa_info_type_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("oTDOA-Information-Item", otdoa_info_item.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// OtherRATMeasurementQuantities-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t other_rat_meas_quantities_item_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {16}; - return map_enum_number(names, 1, idx, "id"); -} -bool other_rat_meas_quantities_item_ies_o::is_id_valid(const uint32_t& id) -{ - return 16 == id; -} -crit_e other_rat_meas_quantities_item_ies_o::get_crit(const uint32_t& id) -{ - if (id == 16) { - return crit_e::reject; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -other_rat_meas_quantities_item_ies_o::value_c other_rat_meas_quantities_item_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 16) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e other_rat_meas_quantities_item_ies_o::get_presence(const uint32_t& id) -{ - if (id == 16) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void other_rat_meas_quantities_item_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("OtherRATMeasurementQuantities-Item"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE other_rat_meas_quantities_item_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE other_rat_meas_quantities_item_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* other_rat_meas_quantities_item_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"OtherRATMeasurementQuantities-Item"}; - return convert_enum_idx(names, 1, value, "other_rat_meas_quantities_item_ies_o::value_c::types"); -} - -// Outcome ::= ENUMERATED -const char* outcome_opts::to_string() const -{ - static const char* names[] = {"failed"}; - return convert_enum_idx(names, 1, value, "outcome_e"); -} - -// PathlossReferenceInformation ::= SEQUENCE -SRSASN_CODE pathloss_ref_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pathloss_ref_sig.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE pathloss_ref_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(pathloss_ref_sig.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void pathloss_ref_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("pathlossReferenceSignal"); - pathloss_ref_sig.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -template struct asn1::protocol_ie_single_container_s; - -// PRSTransmissionOffInformation ::= SEQUENCE -SRSASN_CODE prs_tx_off_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(prs_tx_off_ind.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_tx_off_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(prs_tx_off_ind.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_tx_off_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("pRSTransmissionOffIndication"); - prs_tx_off_ind.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// RequestedDLPRSTransmissionCharacteristics ::= SEQUENCE -SRSASN_CODE requested_dl_prs_tx_characteristics_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(numof_freq_layers_present, 1)); - HANDLE_CODE(bref.pack(start_time_and_dur_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, requested_dl_prs_res_set_list, 1, 8, true)); - if (numof_freq_layers_present) { - HANDLE_CODE(pack_integer(bref, numof_freq_layers, (uint8_t)1u, (uint8_t)4u, false, true)); - } - if (start_time_and_dur_present) { - HANDLE_CODE(start_time_and_dur.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE requested_dl_prs_tx_characteristics_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(numof_freq_layers_present, 1)); - HANDLE_CODE(bref.unpack(start_time_and_dur_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(requested_dl_prs_res_set_list, bref, 1, 8, true)); - if (numof_freq_layers_present) { - HANDLE_CODE(unpack_integer(numof_freq_layers, bref, (uint8_t)1u, (uint8_t)4u, false, true)); - } - if (start_time_and_dur_present) { - HANDLE_CODE(start_time_and_dur.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void requested_dl_prs_tx_characteristics_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("requestedDLPRSResourceSet-List"); - for (const auto& e1 : requested_dl_prs_res_set_list) { - e1.to_json(j); - } - j.end_array(); - if (numof_freq_layers_present) { - j.write_int("numberofFrequencyLayers", numof_freq_layers); - } - if (start_time_and_dur_present) { - j.write_fieldname("startTimeAndDuration"); - start_time_and_dur.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// RequestedSRSTransmissionCharacteristics-ExtIEs ::= OBJECT SET OF NRPPA-PROTOCOL-EXTENSION -uint32_t requested_srs_tx_characteristics_ext_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {61}; - return map_enum_number(names, 1, idx, "id"); -} -bool requested_srs_tx_characteristics_ext_ies_o::is_id_valid(const uint32_t& id) -{ - return 61 == id; -} -crit_e requested_srs_tx_characteristics_ext_ies_o::get_crit(const uint32_t& id) -{ - if (id == 61) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -requested_srs_tx_characteristics_ext_ies_o::ext_c -requested_srs_tx_characteristics_ext_ies_o::get_ext(const uint32_t& id) -{ - ext_c ret{}; - if (id != 61) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e requested_srs_tx_characteristics_ext_ies_o::get_presence(const uint32_t& id) -{ - if (id == 61) { - return presence_e::optional; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Extension ::= OPEN TYPE -void requested_srs_tx_characteristics_ext_ies_o::ext_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("INTEGER (0..3279165)", c); - j.end_obj(); -} -SRSASN_CODE requested_srs_tx_characteristics_ext_ies_o::ext_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, c, (uint32_t)0u, (uint32_t)3279165u, false, true)); - return SRSASN_SUCCESS; -} -SRSASN_CODE requested_srs_tx_characteristics_ext_ies_o::ext_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(c, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - return SRSASN_SUCCESS; -} - -const char* requested_srs_tx_characteristics_ext_ies_o::ext_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (0..3279165)"}; - return convert_enum_idx(names, 1, value, "requested_srs_tx_characteristics_ext_ies_o::ext_c::types"); -} -uint8_t requested_srs_tx_characteristics_ext_ies_o::ext_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {0}; - return map_enum_number(numbers, 1, value, "requested_srs_tx_characteristics_ext_ies_o::ext_c::types"); -} - -// Search-window-information ::= SEQUENCE -SRSASN_CODE search_win_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, expected_propagation_delay, (int16_t)-3841, (int16_t)3841, true, true)); - HANDLE_CODE(pack_integer(bref, delay_uncertainty, (uint8_t)1u, (uint8_t)246u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE search_win_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(expected_propagation_delay, bref, (int16_t)-3841, (int16_t)3841, true, true)); - HANDLE_CODE(unpack_integer(delay_uncertainty, bref, (uint8_t)1u, (uint8_t)246u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void search_win_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("expectedPropagationDelay", expected_propagation_delay); - j.write_int("delayUncertainty", delay_uncertainty); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE semipersistent_srs_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += srs_spatial_relation_present ? 1 : 0; - nof_ies += srs_spatial_relation_per_srs_res_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (srs_spatial_relation_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)48, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_spatial_relation.pack(bref)); - } - if (srs_spatial_relation_per_srs_res_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)63, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_spatial_relation_per_srs_res.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE semipersistent_srs_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 48: { - srs_spatial_relation_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_spatial_relation.unpack(bref)); - break; - } - case 63: { - srs_spatial_relation_per_srs_res_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_spatial_relation_per_srs_res.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void semipersistent_srs_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (srs_spatial_relation_present) { - j.write_int("id", 48); - j.write_str("criticality", "ignore"); - srs_spatial_relation.to_json(j); - } - if (srs_spatial_relation_per_srs_res_present) { - j.write_int("id", 63); - j.write_str("criticality", "ignore"); - srs_spatial_relation_per_srs_res.to_json(j); - } - j.end_obj(); -} - -// SRSCarrier-List-Item ::= SEQUENCE -SRSASN_CODE srs_carrier_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(pci_nr_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, point_a, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, ul_ch_bw_per_scs_list, 1, 5, true)); - HANDLE_CODE(active_ul_bwp.pack(bref)); - if (pci_nr_present) { - HANDLE_CODE(pack_integer(bref, pci_nr, (uint16_t)0u, (uint16_t)1007u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_carrier_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(pci_nr_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(point_a, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(ul_ch_bw_per_scs_list, bref, 1, 5, true)); - HANDLE_CODE(active_ul_bwp.unpack(bref)); - if (pci_nr_present) { - HANDLE_CODE(unpack_integer(pci_nr, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srs_carrier_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pointA", point_a); - j.start_array("uplinkChannelBW-PerSCS-List"); - for (const auto& e1 : ul_ch_bw_per_scs_list) { - e1.to_json(j); - } - j.end_array(); - j.write_fieldname("activeULBWP"); - active_ul_bwp.to_json(j); - if (pci_nr_present) { - j.write_int("pCI-NR", pci_nr); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSResourceTrigger ::= SEQUENCE -SRSASN_CODE srs_res_trigger_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, aperiodic_srs_res_trigger_list, 1, 3, integer_packer(1, 3, false, true))); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_trigger_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE( - unpack_dyn_seq_of(aperiodic_srs_res_trigger_list, bref, 1, 3, integer_packer(1, 3, false, true))); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srs_res_trigger_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("aperiodicSRSResourceTriggerList"); - for (const auto& e1 : aperiodic_srs_res_trigger_list) { - j.write_int(e1); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE sys_info_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(broadcast_periodicity.pack(bref)); - HANDLE_CODE(pack_dyn_seq_of(bref, pos_sibs, 1, 32, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE sys_info_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(broadcast_periodicity.unpack(bref)); - HANDLE_CODE(unpack_dyn_seq_of(pos_sibs, bref, 1, 32, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void sys_info_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("broadcastPeriodicity", broadcast_periodicity.to_string()); - j.start_array("posSIBs"); - for (const auto& e1 : pos_sibs) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPInformation ::= SEQUENCE -SRSASN_CODE trp_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_info_type_resp_list, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(unpack_dyn_seq_of(trp_info_type_resp_list, bref, 1, 64, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - j.start_array("tRPInformationTypeResponseList"); - for (const auto& e1 : trp_info_type_resp_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPInformationTypeItemTRPReq ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t trp_info_type_item_trp_req_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {57}; - return map_enum_number(names, 1, idx, "id"); -} -bool trp_info_type_item_trp_req_o::is_id_valid(const uint32_t& id) -{ - return 57 == id; -} -crit_e trp_info_type_item_trp_req_o::get_crit(const uint32_t& id) -{ - if (id == 57) { - return crit_e::reject; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -trp_info_type_item_trp_req_o::value_c trp_info_type_item_trp_req_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 57) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_info_type_item_trp_req_o::get_presence(const uint32_t& id) -{ - if (id == 57) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void trp_info_type_item_trp_req_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("TRPInformationTypeItem", c.to_string()); - j.end_obj(); -} -SRSASN_CODE trp_info_type_item_trp_req_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_type_item_trp_req_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* trp_info_type_item_trp_req_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"TRPInformationTypeItem"}; - return convert_enum_idx(names, 1, value, "trp_info_type_item_trp_req_o::value_c::types"); -} - -// TRPMeasurementQuantities-Item ::= ENUMERATED -const char* trp_meas_quantities_item_opts::to_string() const -{ - static const char* names[] = { - "gNB-RxTxTimeDiff", "uL-SRS-RSRP", "uL-AoA", "uL-RTOA", "multiple-UL-AoA", "uL-SRS-RSRPP"}; - return convert_enum_idx(names, 6, value, "trp_meas_quantities_item_e"); -} - -SRSASN_CODE trp_meas_request_item_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += cell_id_present ? 1 : 0; - nof_ies += ao_a_search_win_present ? 1 : 0; - nof_ies += nof_trp_rx_teg_present ? 1 : 0; - nof_ies += nof_trp_rx_tx_teg_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (cell_id_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)60, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cell_id.pack(bref)); - } - if (ao_a_search_win_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)69, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(ao_a_search_win.pack(bref)); - } - if (nof_trp_rx_teg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)82, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_teg.pack(bref)); - } - if (nof_trp_rx_tx_teg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)83, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_tx_teg.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_request_item_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 60: { - cell_id_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cell_id.unpack(bref)); - break; - } - case 69: { - ao_a_search_win_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(ao_a_search_win.unpack(bref)); - break; - } - case 82: { - nof_trp_rx_teg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_teg.unpack(bref)); - break; - } - case 83: { - nof_trp_rx_tx_teg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_tx_teg.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void trp_meas_request_item_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (cell_id_present) { - j.write_int("id", 60); - j.write_str("criticality", "ignore"); - cell_id.to_json(j); - } - if (ao_a_search_win_present) { - j.write_int("id", 69); - j.write_str("criticality", "ignore"); - ao_a_search_win.to_json(j); - } - if (nof_trp_rx_teg_present) { - j.write_int("id", 82); - j.write_str("criticality", "ignore"); - j.write_str("Extension", nof_trp_rx_teg.to_string()); - } - if (nof_trp_rx_tx_teg_present) { - j.write_int("id", 83); - j.write_str("criticality", "ignore"); - j.write_str("Extension", nof_trp_rx_tx_teg.to_string()); - } - j.end_obj(); -} - -SRSASN_CODE trp_meas_upd_item_ext_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += nof_trp_rx_teg_present ? 1 : 0; - nof_ies += nof_trp_rx_tx_teg_present ? 1 : 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - if (nof_trp_rx_teg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)82, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_teg.pack(bref)); - } - if (nof_trp_rx_tx_teg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)83, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_tx_teg.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_upd_item_ext_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 82: { - nof_trp_rx_teg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_teg.unpack(bref)); - break; - } - case 83: { - nof_trp_rx_tx_teg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(nof_trp_rx_tx_teg.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void trp_meas_upd_item_ext_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (nof_trp_rx_teg_present) { - j.write_int("id", 82); - j.write_str("criticality", "ignore"); - j.write_str("Extension", nof_trp_rx_teg.to_string()); - } - if (nof_trp_rx_tx_teg_present) { - j.write_int("id", 83); - j.write_str("criticality", "ignore"); - j.write_str("Extension", nof_trp_rx_tx_teg.to_string()); - } - j.end_obj(); -} - -// WLANBand ::= ENUMERATED -const char* wlan_band_opts::to_string() const -{ - static const char* names[] = {"band2dot4", "band5"}; - return convert_enum_idx(names, 2, value, "wlan_band_e"); -} -float wlan_band_opts::to_number() const -{ - static const float numbers[] = {2.4, 5.0}; - return map_enum_number(numbers, 2, value, "wlan_band_e"); -} -const char* wlan_band_opts::to_number_string() const -{ - static const char* number_strs[] = {"2.4", "5"}; - return convert_enum_idx(number_strs, 2, value, "wlan_band_e"); -} - -// WLANCountryCode ::= ENUMERATED -const char* wlan_country_code_opts::to_string() const -{ - static const char* names[] = {"unitedStates", "europe", "japan", "global"}; - return convert_enum_idx(names, 4, value, "wlan_country_code_e"); -} - -// WLANMeasurementQuantities-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t wlan_meas_quantities_item_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {20}; - return map_enum_number(names, 1, idx, "id"); -} -bool wlan_meas_quantities_item_ies_o::is_id_valid(const uint32_t& id) -{ - return 20 == id; -} -crit_e wlan_meas_quantities_item_ies_o::get_crit(const uint32_t& id) -{ - if (id == 20) { - return crit_e::reject; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -wlan_meas_quantities_item_ies_o::value_c wlan_meas_quantities_item_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 20) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e wlan_meas_quantities_item_ies_o::get_presence(const uint32_t& id) -{ - if (id == 20) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void wlan_meas_quantities_item_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("WLANMeasurementQuantities-Item"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE wlan_meas_quantities_item_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE wlan_meas_quantities_item_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* wlan_meas_quantities_item_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"WLANMeasurementQuantities-Item"}; - return convert_enum_idx(names, 1, value, "wlan_meas_quantities_item_ies_o::value_c::types"); -} - -// AperiodicSRS ::= SEQUENCE -SRSASN_CODE aperiodic_srs_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(srs_res_trigger_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(aperiodic.pack(bref)); - if (srs_res_trigger_present) { - HANDLE_CODE(srs_res_trigger.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE aperiodic_srs_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(srs_res_trigger_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(aperiodic.unpack(bref)); - if (srs_res_trigger_present) { - HANDLE_CODE(srs_res_trigger.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void aperiodic_srs_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("aperiodic", "true"); - if (srs_res_trigger_present) { - j.write_fieldname("sRSResourceTrigger"); - srs_res_trigger.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* aperiodic_srs_s::aperiodic_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "aperiodic_srs_s::aperiodic_e_"); -} - -SRSASN_CODE assist_info_fail_list_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pos_sib_type.pack(bref)); - HANDLE_CODE(outcome.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_fail_list_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(pos_sib_type.unpack(bref)); - HANDLE_CODE(outcome.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void assist_info_fail_list_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("posSIB-Type", pos_sib_type.to_string()); - j.write_str("outcome", "failed"); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// BandwidthSRS ::= CHOICE -void bw_srs_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void bw_srs_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::fr1: - break; - case types::fr2: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "bw_srs_c"); - } -} -bw_srs_c::bw_srs_c(const bw_srs_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::fr1: - c.init(other.c.get()); - break; - case types::fr2: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "bw_srs_c"); - } -} -bw_srs_c& bw_srs_c::operator=(const bw_srs_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::fr1: - c.set(other.c.get()); - break; - case types::fr2: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "bw_srs_c"); - } - - return *this; -} -bw_srs_c::fr1_e_& bw_srs_c::set_fr1() -{ - set(types::fr1); - return c.get(); -} -bw_srs_c::fr2_e_& bw_srs_c::set_fr2() -{ - set(types::fr2); - return c.get(); -} -protocol_ie_single_container_s& bw_srs_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void bw_srs_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::fr1: - j.write_str("fR1", c.get().to_string()); - break; - case types::fr2: - j.write_str("fR2", c.get().to_string()); - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "bw_srs_c"); - } - j.end_obj(); -} -SRSASN_CODE bw_srs_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::fr1: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::fr2: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "bw_srs_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE bw_srs_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::fr1: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::fr2: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "bw_srs_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* bw_srs_c::fr1_opts::to_string() const -{ - static const char* names[] = {"mHz5", "mHz10", "mHz20", "mHz40", "mHz50", "mHz80", "mHz100"}; - return convert_enum_idx(names, 7, value, "bw_srs_c::fr1_e_"); -} -uint8_t bw_srs_c::fr1_opts::to_number() const -{ - static const uint8_t numbers[] = {5, 10, 20, 40, 50, 80, 100}; - return map_enum_number(numbers, 7, value, "bw_srs_c::fr1_e_"); -} - -const char* bw_srs_c::fr2_opts::to_string() const -{ - static const char* names[] = {"mHz50", "mHz100", "mHz200", "mHz400"}; - return convert_enum_idx(names, 4, value, "bw_srs_c::fr2_e_"); -} -uint16_t bw_srs_c::fr2_opts::to_number() const -{ - static const uint16_t numbers[] = {50, 100, 200, 400}; - return map_enum_number(numbers, 4, value, "bw_srs_c::fr2_e_"); -} - -const char* bw_srs_c::types_opts::to_string() const -{ - static const char* names[] = {"fR1", "fR2", "choice-extension"}; - return convert_enum_idx(names, 3, value, "bw_srs_c::types"); -} -uint8_t bw_srs_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 2}; - return map_enum_number(numbers, 2, value, "bw_srs_c::types"); -} - -// CauseMisc ::= ENUMERATED -const char* cause_misc_opts::to_string() const -{ - static const char* names[] = {"unspecified"}; - return convert_enum_idx(names, 1, value, "cause_misc_e"); -} - -// CauseProtocol ::= ENUMERATED -const char* cause_protocol_opts::to_string() const -{ - static const char* names[] = {"transfer-syntax-error", - "abstract-syntax-error-reject", - "abstract-syntax-error-ignore-and-notify", - "message-not-compatible-with-receiver-state", - "semantic-error", - "unspecified", - "abstract-syntax-error-falsely-constructed-message"}; - return convert_enum_idx(names, 7, value, "cause_protocol_e"); -} - -// CauseRadioNetwork ::= ENUMERATED -const char* cause_radio_network_opts::to_string() const -{ - static const char* names[] = {"unspecified", - "requested-item-not-supported", - "requested-item-temporarily-not-available", - "serving-NG-RAN-node-changed", - "requested-item-not-supported-on-time"}; - return convert_enum_idx(names, 5, value, "cause_radio_network_e"); -} - -// NG-RAN-CGI ::= SEQUENCE -SRSASN_CODE ng_ran_cgi_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(plmn_id.pack(bref)); - HANDLE_CODE(ng_ra_ncell.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ng_ran_cgi_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(plmn_id.unpack(bref)); - HANDLE_CODE(ng_ra_ncell.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ng_ran_cgi_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("pLMN-Identity", plmn_id.to_string()); - j.write_fieldname("nG-RANcell"); - ng_ra_ncell.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// Value ::= OPEN TYPE -void nr_ppa_private_ies_empty_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.end_obj(); -} -SRSASN_CODE nr_ppa_private_ies_empty_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_private_ies_empty_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - return SRSASN_SUCCESS; -} - -const char* nr_ppa_private_ies_empty_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {}; - return convert_enum_idx(names, 0, value, "nr_ppa_private_ies_empty_o::value_c::types"); -} - -SRSASN_CODE otdoa_cells_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, otdoa_cell_info, 1, 63, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_cells_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(otdoa_cell_info, bref, 1, 63, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void otdoa_cells_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("oTDOACellInfo"); - for (const auto& e1 : otdoa_cell_info) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// OTDOA-Information-Type-ItemIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t otdoa_info_type_item_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {10}; - return map_enum_number(names, 1, idx, "id"); -} -bool otdoa_info_type_item_ies_o::is_id_valid(const uint32_t& id) -{ - return 10 == id; -} -crit_e otdoa_info_type_item_ies_o::get_crit(const uint32_t& id) -{ - if (id == 10) { - return crit_e::reject; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -otdoa_info_type_item_ies_o::value_c otdoa_info_type_item_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 10) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e otdoa_info_type_item_ies_o::get_presence(const uint32_t& id) -{ - if (id == 10) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void otdoa_info_type_item_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("OTDOA-Information-Type-Item"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE otdoa_info_type_item_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_type_item_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* otdoa_info_type_item_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"OTDOA-Information-Type-Item"}; - return convert_enum_idx(names, 1, value, "otdoa_info_type_item_ies_o::value_c::types"); -} - -// OtherRATMeasuredResultsValue ::= CHOICE -void other_rat_measured_results_value_c::destroy_() -{ - switch (type_) { - case types::result_geran: - c.destroy(); - break; - case types::result_utran: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void other_rat_measured_results_value_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::result_geran: - c.init(); - break; - case types::result_utran: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_c"); - } -} -other_rat_measured_results_value_c::other_rat_measured_results_value_c(const other_rat_measured_results_value_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::result_geran: - c.init(other.c.get()); - break; - case types::result_utran: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_c"); - } -} -other_rat_measured_results_value_c& -other_rat_measured_results_value_c::operator=(const other_rat_measured_results_value_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::result_geran: - c.set(other.c.get()); - break; - case types::result_utran: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_c"); - } - - return *this; -} -result_geran_l& other_rat_measured_results_value_c::set_result_geran() -{ - set(types::result_geran); - return c.get(); -} -result_utran_l& other_rat_measured_results_value_c::set_result_utran() -{ - set(types::result_utran); - return c.get(); -} -protocol_ie_single_container_s& -other_rat_measured_results_value_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void other_rat_measured_results_value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::result_geran: - j.start_array("resultGERAN"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::result_utran: - j.start_array("resultUTRAN"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_c"); - } - j.end_obj(); -} -SRSASN_CODE other_rat_measured_results_value_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::result_geran: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::result_utran: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 8, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE other_rat_measured_results_value_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::result_geran: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::result_utran: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 8, true)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "other_rat_measured_results_value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* other_rat_measured_results_value_c::types_opts::to_string() const -{ - static const char* names[] = {"resultGERAN", "resultUTRAN", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "other_rat_measured_results_value_c::types"); -} - -// PrivateIE-ID ::= CHOICE -void private_ie_id_c::set(types::options e) -{ - type_ = e; -} -uint32_t& private_ie_id_c::set_local() -{ - set(types::local); - return c; -} -void private_ie_id_c::set_global() -{ - set(types::global); -} -void private_ie_id_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::local: - j.write_int("local", c); - break; - case types::global: - break; - default: - log_invalid_choice_id(type_, "private_ie_id_c"); - } - j.end_obj(); -} -SRSASN_CODE private_ie_id_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::local: - HANDLE_CODE(pack_integer(bref, c, (uint32_t)0u, (uint32_t)65535u, false, true)); - break; - case types::global: - break; - default: - log_invalid_choice_id(type_, "private_ie_id_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE private_ie_id_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::local: - HANDLE_CODE(unpack_integer(c, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - break; - case types::global: - break; - default: - log_invalid_choice_id(type_, "private_ie_id_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* private_ie_id_c::types_opts::to_string() const -{ - static const char* names[] = {"local", "global"}; - return convert_enum_idx(names, 2, value, "private_ie_id_c::types"); -} - -template struct asn1::protocol_ie_single_container_s; - -template struct asn1::protocol_ie_single_container_s; - -template struct asn1::protocol_ie_single_container_s; - -template struct asn1::protocol_ie_single_container_s; - -// PRS-Measurements-Info-List-Item ::= SEQUENCE -SRSASN_CODE prs_meass_info_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, point_a, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(meas_prs_periodicity.pack(bref)); - HANDLE_CODE(pack_integer(bref, meas_prs_offset, (uint8_t)0u, (uint8_t)159u, true, true)); - HANDLE_CODE(meas_prs_len.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_meass_info_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(point_a, bref, (uint32_t)0u, (uint32_t)3279165u, false, true)); - HANDLE_CODE(meas_prs_periodicity.unpack(bref)); - HANDLE_CODE(unpack_integer(meas_prs_offset, bref, (uint8_t)0u, (uint8_t)159u, true, true)); - HANDLE_CODE(meas_prs_len.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_meass_info_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("pointA", point_a); - j.write_str("measPRSPeriodicity", meas_prs_periodicity.to_string()); - j.write_int("measPRSOffset", meas_prs_offset); - j.write_str("measurementPRSLength", meas_prs_len.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* prs_meass_info_list_item_s::meas_prs_periodicity_opts::to_string() const -{ - static const char* names[] = {"ms20", "ms40", "ms80", "ms160"}; - return convert_enum_idx(names, 4, value, "prs_meass_info_list_item_s::meas_prs_periodicity_e_"); -} -uint8_t prs_meass_info_list_item_s::meas_prs_periodicity_opts::to_number() const -{ - static const uint8_t numbers[] = {20, 40, 80, 160}; - return map_enum_number(numbers, 4, value, "prs_meass_info_list_item_s::meas_prs_periodicity_e_"); -} - -const char* prs_meass_info_list_item_s::meas_prs_len_opts::to_string() const -{ - static const char* names[] = {"ms1dot5", "ms3", "ms3dot5", "ms4", "ms5dot5", "ms6", "ms10", "ms20"}; - return convert_enum_idx(names, 8, value, "prs_meass_info_list_item_s::meas_prs_len_e_"); -} -float prs_meass_info_list_item_s::meas_prs_len_opts::to_number() const -{ - static const float numbers[] = {1.5, 3.0, 3.5, 4.0, 5.5, 6.0, 10.0, 20.0}; - return map_enum_number(numbers, 8, value, "prs_meass_info_list_item_s::meas_prs_len_e_"); -} -const char* prs_meass_info_list_item_s::meas_prs_len_opts::to_number_string() const -{ - static const char* number_strs[] = {"1.5", "3", "3.5", "4", "5.5", "6", "10", "20"}; - return convert_enum_idx(number_strs, 8, value, "prs_meass_info_list_item_s::meas_prs_len_e_"); -} - -// PRSTransmissionTRPItem ::= SEQUENCE -SRSASN_CODE prs_tx_trp_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(prs_cfg.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_tx_trp_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(prs_cfg.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prs_tx_trp_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - j.write_fieldname("pRSConfiguration"); - prs_cfg.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// PRSTRPItem ::= SEQUENCE -SRSASN_CODE prstrp_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(requested_dl_prs_tx_characteristics_present, 1)); - HANDLE_CODE(bref.pack(prs_tx_off_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (requested_dl_prs_tx_characteristics_present) { - HANDLE_CODE(requested_dl_prs_tx_characteristics.pack(bref)); - } - if (prs_tx_off_info_present) { - HANDLE_CODE(prs_tx_off_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prstrp_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(requested_dl_prs_tx_characteristics_present, 1)); - HANDLE_CODE(bref.unpack(prs_tx_off_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (requested_dl_prs_tx_characteristics_present) { - HANDLE_CODE(requested_dl_prs_tx_characteristics.unpack(bref)); - } - if (prs_tx_off_info_present) { - HANDLE_CODE(prs_tx_off_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void prstrp_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - if (requested_dl_prs_tx_characteristics_present) { - j.write_fieldname("requestedDLPRSTransmissionCharacteristics"); - requested_dl_prs_tx_characteristics.to_json(j); - } - if (prs_tx_off_info_present) { - j.write_fieldname("pRSTransmissionOffInformation"); - prs_tx_off_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SemipersistentSRS ::= SEQUENCE -SRSASN_CODE semipersistent_srs_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_res_set_id, (uint8_t)0u, (uint8_t)15u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE semipersistent_srs_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_res_set_id, bref, (uint8_t)0u, (uint8_t)15u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void semipersistent_srs_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResourceSetID", srs_res_set_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// SRSResourceSet-Item ::= SEQUENCE -SRSASN_CODE srs_res_set_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(nof_srs_res_per_set_present, 1)); - HANDLE_CODE(bref.pack(periodicity_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(spatial_relation_info_present, 1)); - HANDLE_CODE(bref.pack(pathloss_ref_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - if (nof_srs_res_per_set_present) { - HANDLE_CODE(pack_integer(bref, nof_srs_res_per_set, (uint8_t)1u, (uint8_t)16u, true, true)); - } - if (periodicity_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, periodicity_list, 1, 16, true)); - } - if (spatial_relation_info_present) { - HANDLE_CODE(spatial_relation_info.pack(bref)); - } - if (pathloss_ref_info_present) { - HANDLE_CODE(pathloss_ref_info.pack(bref)); - } - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_set_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(nof_srs_res_per_set_present, 1)); - bool periodicity_list_present; - HANDLE_CODE(bref.unpack(periodicity_list_present, 1)); - HANDLE_CODE(bref.unpack(spatial_relation_info_present, 1)); - HANDLE_CODE(bref.unpack(pathloss_ref_info_present, 1)); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (nof_srs_res_per_set_present) { - HANDLE_CODE(unpack_integer(nof_srs_res_per_set, bref, (uint8_t)1u, (uint8_t)16u, true, true)); - } - if (periodicity_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(periodicity_list, bref, 1, 16, true)); - } - if (spatial_relation_info_present) { - HANDLE_CODE(spatial_relation_info.unpack(bref)); - } - if (pathloss_ref_info_present) { - HANDLE_CODE(pathloss_ref_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void srs_res_set_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (nof_srs_res_per_set_present) { - j.write_int("numberOfSRSResourcePerSet", nof_srs_res_per_set); - } - if (periodicity_list.size() > 0) { - j.start_array("periodicityList"); - for (const auto& e1 : periodicity_list) { - j.write_str(e1.to_string()); - } - j.end_array(); - } - if (spatial_relation_info_present) { - j.write_fieldname("spatialRelationInformation"); - spatial_relation_info.to_json(j); - } - if (pathloss_ref_info_present) { - j.write_fieldname("pathlossReferenceInformation"); - pathloss_ref_info.to_json(j); - } - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -// TriggeringMessage ::= ENUMERATED -const char* trigger_msg_opts::to_string() const -{ - static const char* names[] = {"initiating-message", "successful-outcome", "unsuccessful-outcome"}; - return convert_enum_idx(names, 3, value, "trigger_msg_e"); -} - -SRSASN_CODE trp_info_list_trp_resp_item_s_::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(trp_info.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_list_trp_resp_item_s_::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(trp_info.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_info_list_trp_resp_item_s_::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("tRPInformation"); - trp_info.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPItem ::= SEQUENCE -SRSASN_CODE trp_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRPMeasurementQuantitiesList-Item ::= SEQUENCE -SRSASN_CODE trp_meas_quantities_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(timing_report_granularity_factor_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(trp_meas_quantities_item.pack(bref)); - if (timing_report_granularity_factor_present) { - HANDLE_CODE(pack_integer(bref, timing_report_granularity_factor, (uint8_t)0u, (uint8_t)5u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_quantities_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(timing_report_granularity_factor_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(trp_meas_quantities_item.unpack(bref)); - if (timing_report_granularity_factor_present) { - HANDLE_CODE(unpack_integer(timing_report_granularity_factor, bref, (uint8_t)0u, (uint8_t)5u, false, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_quantities_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("tRPMeasurementQuantities-Item", trp_meas_quantities_item.to_string()); - if (timing_report_granularity_factor_present) { - j.write_int("timingReportingGranularityFactor", timing_report_granularity_factor); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRP-MeasurementRequestItem ::= SEQUENCE -SRSASN_CODE trp_meas_request_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(search_win_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (search_win_info_present) { - HANDLE_CODE(search_win_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_request_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(search_win_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (search_win_info_present) { - HANDLE_CODE(search_win_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_request_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - if (search_win_info_present) { - j.write_fieldname("search-window-information"); - search_win_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRP-MeasurementResponseItem ::= SEQUENCE -SRSASN_CODE trp_meas_resp_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, meas_result, 1, 16384, true)); - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_resp_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(unpack_dyn_seq_of(meas_result, bref, 1, 16384, true)); - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_resp_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - j.start_array("measurementResult"); - for (const auto& e1 : meas_result) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts.size() > 0) { - j.write_fieldname("iE-extensions"); - } - j.end_obj(); -} - -// TRP-MeasurementUpdateItem ::= SEQUENCE -SRSASN_CODE trp_meas_upd_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ao_a_win_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (ao_a_win_info_present) { - HANDLE_CODE(ao_a_win_info.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_meas_upd_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ao_a_win_info_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - if (ao_a_win_info_present) { - HANDLE_CODE(ao_a_win_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_meas_upd_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - if (ao_a_win_info_present) { - j.write_fieldname("aoA-window-information"); - ao_a_win_info.to_json(j); - } - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// UETxTEGAssociationItem ::= SEQUENCE -SRSASN_CODE ue_tx_teg_assoc_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(carrier_freq_present, 1)); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - HANDLE_CODE(pack_integer(bref, ue_tx_teg_id, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(pack_dyn_seq_of(bref, pos_srs_res_id_list, 1, 64, integer_packer(0, 63, false, true))); - HANDLE_CODE(time_stamp.pack(bref)); - if (carrier_freq_present) { - HANDLE_CODE(carrier_freq.pack(bref)); - } - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ue_tx_teg_assoc_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(carrier_freq_present, 1)); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(ue_tx_teg_id, bref, (uint8_t)0u, (uint8_t)7u, false, true)); - HANDLE_CODE(unpack_dyn_seq_of(pos_srs_res_id_list, bref, 1, 64, integer_packer(0, 63, false, true))); - HANDLE_CODE(time_stamp.unpack(bref)); - if (carrier_freq_present) { - HANDLE_CODE(carrier_freq.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void ue_tx_teg_assoc_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("uE-Tx-TEG-ID", ue_tx_teg_id); - j.start_array("posSRSResourceID-List"); - for (const auto& e1 : pos_srs_res_id_list) { - j.write_int(e1); - } - j.end_array(); - j.write_fieldname("timeStamp"); - time_stamp.to_json(j); - if (carrier_freq_present) { - j.write_fieldname("carrierFreq"); - carrier_freq.to_json(j); - } - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -// WLANMeasurementResult-Item ::= SEQUENCE -SRSASN_CODE wlan_meas_result_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ssi_d.size() > 0, 1)); - HANDLE_CODE(bref.pack(bs_si_d_present, 1)); - HANDLE_CODE(bref.pack(hes_si_d_present, 1)); - HANDLE_CODE(bref.pack(operating_class_present, 1)); - HANDLE_CODE(bref.pack(country_code_present, 1)); - HANDLE_CODE(bref.pack(wlan_ch_list.size() > 0, 1)); - HANDLE_CODE(bref.pack(wlan_band_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, wlan_rssi, (uint8_t)0u, (uint8_t)141u, true, true)); - if (ssi_d.size() > 0) { - HANDLE_CODE(ssi_d.pack(bref)); - } - if (bs_si_d_present) { - HANDLE_CODE(bs_si_d.pack(bref)); - } - if (hes_si_d_present) { - HANDLE_CODE(hes_si_d.pack(bref)); - } - if (operating_class_present) { - HANDLE_CODE(pack_integer(bref, operating_class, (uint16_t)0u, (uint16_t)255u, false, true)); - } - if (country_code_present) { - HANDLE_CODE(country_code.pack(bref)); - } - if (wlan_ch_list.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, wlan_ch_list, 1, 16, integer_packer(0, 255, false, true))); - } - if (wlan_band_present) { - HANDLE_CODE(wlan_band.pack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE wlan_meas_result_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - bool ssi_d_present; - HANDLE_CODE(bref.unpack(ssi_d_present, 1)); - HANDLE_CODE(bref.unpack(bs_si_d_present, 1)); - HANDLE_CODE(bref.unpack(hes_si_d_present, 1)); - HANDLE_CODE(bref.unpack(operating_class_present, 1)); - HANDLE_CODE(bref.unpack(country_code_present, 1)); - bool wlan_ch_list_present; - HANDLE_CODE(bref.unpack(wlan_ch_list_present, 1)); - HANDLE_CODE(bref.unpack(wlan_band_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(wlan_rssi, bref, (uint8_t)0u, (uint8_t)141u, true, true)); - if (ssi_d_present) { - HANDLE_CODE(ssi_d.unpack(bref)); - } - if (bs_si_d_present) { - HANDLE_CODE(bs_si_d.unpack(bref)); - } - if (hes_si_d_present) { - HANDLE_CODE(hes_si_d.unpack(bref)); - } - if (operating_class_present) { - HANDLE_CODE(unpack_integer(operating_class, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - } - if (country_code_present) { - HANDLE_CODE(country_code.unpack(bref)); - } - if (wlan_ch_list_present) { - HANDLE_CODE(unpack_dyn_seq_of(wlan_ch_list, bref, 1, 16, integer_packer(0, 255, false, true))); - } - if (wlan_band_present) { - HANDLE_CODE(wlan_band.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void wlan_meas_result_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("wLAN-RSSI", wlan_rssi); - if (ssi_d.size() > 0) { - j.write_str("sSID", ssi_d.to_string()); - } - if (bs_si_d_present) { - j.write_str("bSSID", bs_si_d.to_string()); - } - if (hes_si_d_present) { - j.write_str("hESSID", hes_si_d.to_string()); - } - if (operating_class_present) { - j.write_int("operatingClass", operating_class); - } - if (country_code_present) { - j.write_str("countryCode", country_code.to_string()); - } - if (wlan_ch_list.size() > 0) { - j.start_array("wLANChannelList"); - for (const auto& e1 : wlan_ch_list) { - j.write_int(e1); - } - j.end_array(); - } - if (wlan_band_present) { - j.write_str("wLANBand", wlan_band.to_string()); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// Assistance-Information ::= SEQUENCE -SRSASN_CODE assist_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, sys_info, 1, 32, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(sys_info, bref, 1, 32, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void assist_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("systemInformation"); - for (const auto& e1 : sys_info) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// Broadcast ::= ENUMERATED -const char* broadcast_opts::to_string() const -{ - static const char* names[] = {"start", "stop"}; - return convert_enum_idx(names, 2, value, "broadcast_e"); -} - -// Cause ::= CHOICE -void cause_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void cause_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::radio_network: - break; - case types::protocol: - break; - case types::misc: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "cause_c"); - } -} -cause_c::cause_c(const cause_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::radio_network: - c.init(other.c.get()); - break; - case types::protocol: - c.init(other.c.get()); - break; - case types::misc: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "cause_c"); - } -} -cause_c& cause_c::operator=(const cause_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::radio_network: - c.set(other.c.get()); - break; - case types::protocol: - c.set(other.c.get()); - break; - case types::misc: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "cause_c"); - } - - return *this; -} -cause_radio_network_e& cause_c::set_radio_network() -{ - set(types::radio_network); - return c.get(); -} -cause_protocol_e& cause_c::set_protocol() -{ - set(types::protocol); - return c.get(); -} -cause_misc_e& cause_c::set_misc() -{ - set(types::misc); - return c.get(); -} -protocol_ie_single_container_s& cause_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void cause_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::radio_network: - j.write_str("radioNetwork", c.get().to_string()); - break; - case types::protocol: - j.write_str("protocol", c.get().to_string()); - break; - case types::misc: - j.write_str("misc", "unspecified"); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "cause_c"); - } - j.end_obj(); -} -SRSASN_CODE cause_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::radio_network: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::protocol: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::misc: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "cause_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE cause_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::radio_network: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::protocol: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::misc: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "cause_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* cause_c::types_opts::to_string() const -{ - static const char* names[] = {"radioNetwork", "protocol", "misc", "choice-Extension"}; - return convert_enum_idx(names, 4, value, "cause_c::types"); -} -uint8_t cause_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {2}; - return map_enum_number(numbers, 1, value, "cause_c::types"); -} - -// CriticalityDiagnostics ::= SEQUENCE -SRSASN_CODE crit_diagnostics_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(proc_code_present, 1)); - HANDLE_CODE(bref.pack(trigger_msg_present, 1)); - HANDLE_CODE(bref.pack(proc_crit_present, 1)); - HANDLE_CODE(bref.pack(nrppatransaction_id_present, 1)); - HANDLE_CODE(bref.pack(ies_crit_diagnostics.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - if (proc_code_present) { - HANDLE_CODE(pack_integer(bref, proc_code, (uint16_t)0u, (uint16_t)255u, false, true)); - } - if (trigger_msg_present) { - HANDLE_CODE(trigger_msg.pack(bref)); - } - if (proc_crit_present) { - HANDLE_CODE(proc_crit.pack(bref)); - } - if (nrppatransaction_id_present) { - HANDLE_CODE(pack_integer(bref, nrppatransaction_id, (uint16_t)0u, (uint16_t)32767u, false, true)); - } - if (ies_crit_diagnostics.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ies_crit_diagnostics, 1, 256, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE crit_diagnostics_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(proc_code_present, 1)); - HANDLE_CODE(bref.unpack(trigger_msg_present, 1)); - HANDLE_CODE(bref.unpack(proc_crit_present, 1)); - HANDLE_CODE(bref.unpack(nrppatransaction_id_present, 1)); - bool ies_crit_diagnostics_present; - HANDLE_CODE(bref.unpack(ies_crit_diagnostics_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (proc_code_present) { - HANDLE_CODE(unpack_integer(proc_code, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - } - if (trigger_msg_present) { - HANDLE_CODE(trigger_msg.unpack(bref)); - } - if (proc_crit_present) { - HANDLE_CODE(proc_crit.unpack(bref)); - } - if (nrppatransaction_id_present) { - HANDLE_CODE(unpack_integer(nrppatransaction_id, bref, (uint16_t)0u, (uint16_t)32767u, false, true)); - } - if (ies_crit_diagnostics_present) { - HANDLE_CODE(unpack_dyn_seq_of(ies_crit_diagnostics, bref, 1, 256, true)); - } - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void crit_diagnostics_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (proc_code_present) { - j.write_int("procedureCode", proc_code); - } - if (trigger_msg_present) { - j.write_str("triggeringMessage", trigger_msg.to_string()); - } - if (proc_crit_present) { - j.write_str("procedureCriticality", proc_crit.to_string()); - } - if (nrppatransaction_id_present) { - j.write_int("nrppatransactionID", nrppatransaction_id); - } - if (ies_crit_diagnostics.size() > 0) { - j.start_array("iEsCriticalityDiagnostics"); - for (const auto& e1 : ies_crit_diagnostics) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// E-CID-MeasurementResult ::= SEQUENCE -SRSASN_CODE e_c_id_meas_result_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ng_ran_access_point_position_present, 1)); - HANDLE_CODE(bref.pack(measured_results.size() > 0, 1)); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - HANDLE_CODE(serving_cell_id.pack(bref)); - HANDLE_CODE(serving_cell_tac.pack(bref)); - if (ng_ran_access_point_position_present) { - HANDLE_CODE(ng_ran_access_point_position.pack(bref)); - } - if (measured_results.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, measured_results, 1, 64, true)); - } - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_result_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ng_ran_access_point_position_present, 1)); - bool measured_results_present; - HANDLE_CODE(bref.unpack(measured_results_present, 1)); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(serving_cell_id.unpack(bref)); - HANDLE_CODE(serving_cell_tac.unpack(bref)); - if (ng_ran_access_point_position_present) { - HANDLE_CODE(ng_ran_access_point_position.unpack(bref)); - } - if (measured_results_present) { - HANDLE_CODE(unpack_dyn_seq_of(measured_results, bref, 1, 64, true)); - } - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void e_c_id_meas_result_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("servingCell-ID"); - serving_cell_id.to_json(j); - j.write_str("servingCellTAC", serving_cell_tac.to_string()); - if (ng_ran_access_point_position_present) { - j.write_fieldname("nG-RANAccessPointPosition"); - ng_ran_access_point_position.to_json(j); - } - if (measured_results.size() > 0) { - j.start_array("measuredResults"); - for (const auto& e1 : measured_results) { - e1.to_json(j); - } - j.end_array(); - } - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -// MeasurementAmount ::= ENUMERATED -const char* meas_amount_opts::to_string() const -{ - static const char* names[] = {"ma0", "ma1", "ma2", "ma4", "ma8", "ma16", "ma32", "ma64"}; - return convert_enum_idx(names, 8, value, "meas_amount_e"); -} -uint8_t meas_amount_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 1, 2, 4, 8, 16, 32, 64}; - return map_enum_number(numbers, 8, value, "meas_amount_e"); -} - -// MeasurementBeamInfoRequest ::= ENUMERATED -const char* meas_beam_info_request_opts::to_string() const -{ - static const char* names[] = {"true"}; - return convert_enum_idx(names, 1, value, "meas_beam_info_request_e"); -} - -// MeasurementPeriodicity ::= ENUMERATED -const char* meas_periodicity_opts::to_string() const -{ - static const char* names[] = {"ms120", - "ms240", - "ms480", - "ms640", - "ms1024", - "ms2048", - "ms5120", - "ms10240", - "min1", - "min6", - "min12", - "min30", - "min60", - "ms20480", - "ms40960", - "extended"}; - return convert_enum_idx(names, 16, value, "meas_periodicity_e"); -} -uint16_t meas_periodicity_opts::to_number() const -{ - static const uint16_t numbers[] = {120, 240, 480, 640, 1024, 2048, 5120, 10240, 1, 6, 12, 30, 60, 20480, 40960}; - return map_enum_number(numbers, 15, value, "meas_periodicity_e"); -} - -// MeasurementPeriodicityExtended ::= ENUMERATED -const char* meas_periodicity_extended_opts::to_string() const -{ - static const char* names[] = { - "ms160", "ms320", "ms1280", "ms2560", "ms61440", "ms81920", "ms368640", "ms737280", "ms1843200"}; - return convert_enum_idx(names, 9, value, "meas_periodicity_extended_e"); -} -uint32_t meas_periodicity_extended_opts::to_number() const -{ - static const uint32_t numbers[] = {160, 320, 1280, 2560, 61440, 81920, 368640, 737280, 1843200}; - return map_enum_number(numbers, 9, value, "meas_periodicity_extended_e"); -} - -// MeasurementPeriodicityNR-AoA ::= ENUMERATED -const char* meas_periodicity_nr_ao_a_opts::to_string() const -{ - static const char* names[] = {"ms160", - "ms320", - "ms640", - "ms1280", - "ms2560", - "ms5120", - "ms10240", - "ms20480", - "ms40960", - "ms61440", - "ms81920", - "ms368640", - "ms737280", - "ms1843200"}; - return convert_enum_idx(names, 14, value, "meas_periodicity_nr_ao_a_e"); -} -uint32_t meas_periodicity_nr_ao_a_opts::to_number() const -{ - static const uint32_t numbers[] = { - 160, 320, 640, 1280, 2560, 5120, 10240, 20480, 40960, 61440, 81920, 368640, 737280, 1843200}; - return map_enum_number(numbers, 14, value, "meas_periodicity_nr_ao_a_e"); -} - -// MeasurementTimeOccasion ::= ENUMERATED -const char* meas_time_occasion_opts::to_string() const -{ - static const char* names[] = {"o1", "o4"}; - return convert_enum_idx(names, 2, value, "meas_time_occasion_e"); -} -uint8_t meas_time_occasion_opts::to_number() const -{ - static const uint8_t numbers[] = {1, 4}; - return map_enum_number(numbers, 2, value, "meas_time_occasion_e"); -} - -// PrivateIE-Field{NRPPA-PRIVATE-IES : IEsSetParam} ::= SEQUENCE{{NRPPA-PRIVATE-IES}} -template -SRSASN_CODE private_ie_field_s::pack(bit_ref& bref) const -{ - HANDLE_CODE(id.pack(bref)); - HANDLE_CODE(crit.pack(bref)); - HANDLE_CODE(value.pack(bref)); - - return SRSASN_SUCCESS; -} -template -SRSASN_CODE private_ie_field_s::unpack(cbit_ref& bref) -{ - HANDLE_CODE(id.unpack(bref)); - HANDLE_CODE(crit.unpack(bref)); - HANDLE_CODE(value.unpack(bref)); - - return SRSASN_SUCCESS; -} -template -void private_ie_field_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("id"); - id.to_json(j); - j.write_str("criticality", crit.to_string()); - j.end_obj(); -} - -template struct asn1::protocol_ie_single_container_s; - -// PRSConfigRequestType ::= ENUMERATED -const char* prs_cfg_request_type_opts::to_string() const -{ - static const char* names[] = {"configure", "off"}; - return convert_enum_idx(names, 2, value, "prs_cfg_request_type_e"); -} - -// ReportCharacteristics ::= ENUMERATED -const char* report_characteristics_opts::to_string() const -{ - static const char* names[] = {"onDemand", "periodic"}; - return convert_enum_idx(names, 2, value, "report_characteristics_e"); -} - -// RequestType ::= ENUMERATED -const char* request_type_opts::to_string() const -{ - static const char* names[] = {"activate", "deactivate"}; - return convert_enum_idx(names, 2, value, "request_type_e"); -} - -// RequestedSRSTransmissionCharacteristics ::= SEQUENCE -SRSASN_CODE requested_srs_tx_characteristics_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(nof_txs_present, 1)); - HANDLE_CODE(bref.pack(list_of_srs_res_set.size() > 0, 1)); - HANDLE_CODE(bref.pack(ssb_info_present, 1)); - HANDLE_CODE(bref.pack(ie_exts.size() > 0, 1)); - - if (nof_txs_present) { - HANDLE_CODE(pack_integer(bref, nof_txs, (uint16_t)0u, (uint16_t)500u, true, true)); - } - HANDLE_CODE(res_type.pack(bref)); - HANDLE_CODE(bw.pack(bref)); - if (list_of_srs_res_set.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, list_of_srs_res_set, 1, 16, true)); - } - if (ssb_info_present) { - HANDLE_CODE(ssb_info.pack(bref)); - } - if (ie_exts.size() > 0) { - HANDLE_CODE(pack_dyn_seq_of(bref, ie_exts, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE requested_srs_tx_characteristics_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(nof_txs_present, 1)); - bool list_of_srs_res_set_present; - HANDLE_CODE(bref.unpack(list_of_srs_res_set_present, 1)); - HANDLE_CODE(bref.unpack(ssb_info_present, 1)); - bool ie_exts_present; - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - if (nof_txs_present) { - HANDLE_CODE(unpack_integer(nof_txs, bref, (uint16_t)0u, (uint16_t)500u, true, true)); - } - HANDLE_CODE(res_type.unpack(bref)); - HANDLE_CODE(bw.unpack(bref)); - if (list_of_srs_res_set_present) { - HANDLE_CODE(unpack_dyn_seq_of(list_of_srs_res_set, bref, 1, 16, true)); - } - if (ssb_info_present) { - HANDLE_CODE(ssb_info.unpack(bref)); - } - if (ie_exts_present) { - HANDLE_CODE(unpack_dyn_seq_of(ie_exts, bref, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -void requested_srs_tx_characteristics_s::to_json(json_writer& j) const -{ - j.start_obj(); - if (nof_txs_present) { - j.write_int("numberOfTransmissions", nof_txs); - } - j.write_str("resourceType", res_type.to_string()); - j.write_fieldname("bandwidth"); - bw.to_json(j); - if (list_of_srs_res_set.size() > 0) { - j.start_array("listOfSRSResourceSet"); - for (const auto& e1 : list_of_srs_res_set) { - e1.to_json(j); - } - j.end_array(); - } - if (ssb_info_present) { - j.write_fieldname("sSBInformation"); - ssb_info.to_json(j); - } - if (ie_exts.size() > 0) { - j.write_fieldname("iE-Extensions"); - } - j.end_obj(); -} - -const char* requested_srs_tx_characteristics_s::res_type_opts::to_string() const -{ - static const char* names[] = {"periodic", "semi-persistent", "aperiodic"}; - return convert_enum_idx(names, 3, value, "requested_srs_tx_characteristics_s::res_type_e_"); -} - -// ResponseTime ::= SEQUENCE -SRSASN_CODE resp_time_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, time, (uint8_t)1u, (uint8_t)128u, true, true)); - HANDLE_CODE(time_unit.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE resp_time_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(time, bref, (uint8_t)1u, (uint8_t)128u, true, true)); - HANDLE_CODE(time_unit.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void resp_time_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("time", time); - j.write_str("timeUnit", time_unit.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* resp_time_s::time_unit_opts::to_string() const -{ - static const char* names[] = {"second", "ten-seconds", "ten-milliseconds"}; - return convert_enum_idx(names, 3, value, "resp_time_s::time_unit_e_"); -} - -// SRSTransmissionStatus ::= ENUMERATED -const char* srs_tx_status_opts::to_string() const -{ - static const char* names[] = {"stopped"}; - return convert_enum_idx(names, 1, value, "srs_tx_status_e"); -} - -// SRSType ::= CHOICE -void srs_type_c::destroy_() -{ - switch (type_) { - case types::semipersistent_srs: - c.destroy(); - break; - case types::aperiodic_srs: - c.destroy(); - break; - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void srs_type_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::semipersistent_srs: - c.init(); - break; - case types::aperiodic_srs: - c.init(); - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "srs_type_c"); - } -} -srs_type_c::srs_type_c(const srs_type_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::semipersistent_srs: - c.init(other.c.get()); - break; - case types::aperiodic_srs: - c.init(other.c.get()); - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "srs_type_c"); - } -} -srs_type_c& srs_type_c::operator=(const srs_type_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::semipersistent_srs: - c.set(other.c.get()); - break; - case types::aperiodic_srs: - c.set(other.c.get()); - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "srs_type_c"); - } - - return *this; -} -semipersistent_srs_s& srs_type_c::set_semipersistent_srs() -{ - set(types::semipersistent_srs); - return c.get(); -} -aperiodic_srs_s& srs_type_c::set_aperiodic_srs() -{ - set(types::aperiodic_srs); - return c.get(); -} -protocol_ie_single_container_s& srs_type_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void srs_type_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::semipersistent_srs: - j.write_fieldname("semipersistentSRS"); - c.get().to_json(j); - break; - case types::aperiodic_srs: - j.write_fieldname("aperiodicSRS"); - c.get().to_json(j); - break; - case types::choice_ext: - j.write_fieldname("choice-Extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "srs_type_c"); - } - j.end_obj(); -} -SRSASN_CODE srs_type_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::semipersistent_srs: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::aperiodic_srs: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "srs_type_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_type_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::semipersistent_srs: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::aperiodic_srs: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "srs_type_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* srs_type_c::types_opts::to_string() const -{ - static const char* names[] = {"semipersistentSRS", "aperiodicSRS", "choice-Extension"}; - return convert_enum_idx(names, 3, value, "srs_type_c::types"); -} - -// SRSConfiguration ::= SEQUENCE -SRSASN_CODE srscfg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_dyn_seq_of(bref, srs_carrier_list, 1, 32, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srscfg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_dyn_seq_of(srs_carrier_list, bref, 1, 32, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srscfg_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("sRSCarrier-List"); - for (const auto& e1 : srs_carrier_list) { - e1.to_json(j); - } - j.end_array(); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// TRP-PRS-Information-List-Item ::= SEQUENCE -SRSASN_CODE trp_prs_info_list_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(cgi_nr_present, 1)); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, trp_id, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(pack_integer(bref, nr_pci, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.pack(bref)); - } - HANDLE_CODE(prs_cfg.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_prs_info_list_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(cgi_nr_present, 1)); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(trp_id, bref, (uint32_t)1u, (uint32_t)65535u, true, true)); - HANDLE_CODE(unpack_integer(nr_pci, bref, (uint16_t)0u, (uint16_t)1007u, false, true)); - if (cgi_nr_present) { - HANDLE_CODE(cgi_nr.unpack(bref)); - } - HANDLE_CODE(prs_cfg.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void trp_prs_info_list_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("tRP-ID", trp_id); - j.write_int("nR-PCI", nr_pci); - if (cgi_nr_present) { - j.write_fieldname("cGI-NR"); - cgi_nr.to_json(j); - } - j.write_fieldname("pRSConfiguration"); - prs_cfg.to_json(j); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -// UEReportingInformation ::= SEQUENCE -SRSASN_CODE ue_report_info_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(report_amount.pack(bref)); - HANDLE_CODE(report_interv.pack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE ue_report_info_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(report_amount.unpack(bref)); - HANDLE_CODE(report_interv.unpack(bref)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void ue_report_info_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_str("reportingAmount", report_amount.to_string()); - j.write_str("reportingInterval", report_interv.to_string()); - if (ie_exts_present) { - j.write_fieldname("iE-extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} - -const char* ue_report_info_s::report_amount_opts::to_string() const -{ - static const char* names[] = {"ma0", "ma1", "ma2", "ma4", "ma8", "ma16", "ma32", "ma64"}; - return convert_enum_idx(names, 8, value, "ue_report_info_s::report_amount_e_"); -} -uint8_t ue_report_info_s::report_amount_opts::to_number() const -{ - static const uint8_t numbers[] = {0, 1, 2, 4, 8, 16, 32, 64}; - return map_enum_number(numbers, 8, value, "ue_report_info_s::report_amount_e_"); -} - -const char* ue_report_info_s::report_interv_opts::to_string() const -{ - static const char* names[] = { - "none", "one", "two", "four", "eight", "ten", "sixteen", "twenty", "thirty-two", "sixty-four"}; - return convert_enum_idx(names, 10, value, "ue_report_info_s::report_interv_e_"); -} - -// UE-TEG-Info-Request ::= ENUMERATED -const char* ue_teg_info_request_opts::to_string() const -{ - static const char* names[] = {"onDemand", "periodic", "stop"}; - return convert_enum_idx(names, 3, value, "ue_teg_info_request_e"); -} - -// UE-TEG-ReportingPeriodicity ::= ENUMERATED -const char* ue_teg_report_periodicity_opts::to_string() const -{ - static const char* names[] = {"ms160", "ms320", "ms1280", "ms2560", "ms61440", "ms81920", "ms368640", "ms737280"}; - return convert_enum_idx(names, 8, value, "ue_teg_report_periodicity_e"); -} -uint32_t ue_teg_report_periodicity_opts::to_number() const -{ - static const uint32_t numbers[] = {160, 320, 1280, 2560, 61440, 81920, 368640, 737280}; - return map_enum_number(numbers, 8, value, "ue_teg_report_periodicity_e"); -} - -// AbortTransmission ::= CHOICE -void abort_tx_c::destroy_() -{ - switch (type_) { - case types::choice_ext: - c.destroy>(); - break; - default: - break; - } -} -void abort_tx_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::deactiv_srs_res_set_id: - break; - case types::release_all: - break; - case types::choice_ext: - c.init>(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "abort_tx_c"); - } -} -abort_tx_c::abort_tx_c(const abort_tx_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::deactiv_srs_res_set_id: - c.init(other.c.get()); - break; - case types::release_all: - break; - case types::choice_ext: - c.init(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "abort_tx_c"); - } -} -abort_tx_c& abort_tx_c::operator=(const abort_tx_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::deactiv_srs_res_set_id: - c.set(other.c.get()); - break; - case types::release_all: - break; - case types::choice_ext: - c.set(other.c.get>()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "abort_tx_c"); - } - - return *this; -} -uint8_t& abort_tx_c::set_deactiv_srs_res_set_id() -{ - set(types::deactiv_srs_res_set_id); - return c.get(); -} -void abort_tx_c::set_release_all() -{ - set(types::release_all); -} -protocol_ie_single_container_s& abort_tx_c::set_choice_ext() -{ - set(types::choice_ext); - return c.get>(); -} -void abort_tx_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::deactiv_srs_res_set_id: - j.write_int("deactivateSRSResourceSetID", c.get()); - break; - case types::release_all: - break; - case types::choice_ext: - j.write_fieldname("choice-extension"); - c.get>().to_json(j); - break; - default: - log_invalid_choice_id(type_, "abort_tx_c"); - } - j.end_obj(); -} -SRSASN_CODE abort_tx_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::deactiv_srs_res_set_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)15u, true, true)); - break; - case types::release_all: - break; - case types::choice_ext: - HANDLE_CODE(c.get>().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "abort_tx_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE abort_tx_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::deactiv_srs_res_set_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)15u, true, true)); - break; - case types::release_all: - break; - case types::choice_ext: - HANDLE_CODE(c.get>().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "abort_tx_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* abort_tx_c::types_opts::to_string() const -{ - static const char* names[] = {"deactivateSRSResourceSetID", "releaseALL", "choice-extension"}; - return convert_enum_idx(names, 3, value, "abort_tx_c::types"); -} - -// AssistanceInformationControl-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t assist_info_ctrl_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {23, 24, 38}; - return map_enum_number(names, 3, idx, "id"); -} -bool assist_info_ctrl_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {23, 24, 38}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e assist_info_ctrl_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 23: - return crit_e::reject; - case 24: - return crit_e::reject; - case 38: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -assist_info_ctrl_ies_o::value_c assist_info_ctrl_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 23: - ret.set(value_c::types::assist_info); - break; - case 24: - ret.set(value_c::types::broadcast); - break; - case 38: - ret.set(value_c::types::positioning_broadcast_cells); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e assist_info_ctrl_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 23: - return presence_e::optional; - case 24: - return presence_e::optional; - case 38: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void assist_info_ctrl_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::assist_info: - c = assist_info_s{}; - break; - case types::broadcast: - c = broadcast_e{}; - break; - case types::positioning_broadcast_cells: - c = positioning_broadcast_cells_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "assist_info_ctrl_ies_o::value_c"); - } -} -assist_info_s& assist_info_ctrl_ies_o::value_c::assist_info() -{ - assert_choice_type(types::assist_info, type_, "Value"); - return c.get(); -} -broadcast_e& assist_info_ctrl_ies_o::value_c::broadcast() -{ - assert_choice_type(types::broadcast, type_, "Value"); - return c.get(); -} -positioning_broadcast_cells_l& assist_info_ctrl_ies_o::value_c::positioning_broadcast_cells() -{ - assert_choice_type(types::positioning_broadcast_cells, type_, "Value"); - return c.get(); -} -const assist_info_s& assist_info_ctrl_ies_o::value_c::assist_info() const -{ - assert_choice_type(types::assist_info, type_, "Value"); - return c.get(); -} -const broadcast_e& assist_info_ctrl_ies_o::value_c::broadcast() const -{ - assert_choice_type(types::broadcast, type_, "Value"); - return c.get(); -} -const positioning_broadcast_cells_l& assist_info_ctrl_ies_o::value_c::positioning_broadcast_cells() const -{ - assert_choice_type(types::positioning_broadcast_cells, type_, "Value"); - return c.get(); -} -void assist_info_ctrl_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::assist_info: - j.write_fieldname("Assistance-Information"); - c.get().to_json(j); - break; - case types::broadcast: - j.write_str("Broadcast", c.get().to_string()); - break; - case types::positioning_broadcast_cells: - j.start_array("PositioningBroadcastCells"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "assist_info_ctrl_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE assist_info_ctrl_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::assist_info: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::broadcast: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_broadcast_cells: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 16384, true)); - break; - default: - log_invalid_choice_id(type_, "assist_info_ctrl_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_ctrl_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::assist_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::broadcast: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_broadcast_cells: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 16384, true)); - break; - default: - log_invalid_choice_id(type_, "assist_info_ctrl_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* assist_info_ctrl_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Assistance-Information", "Broadcast", "PositioningBroadcastCells"}; - return convert_enum_idx(names, 3, value, "assist_info_ctrl_ies_o::value_c::types"); -} - -// AssistanceInformationFeedback-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t assist_info_feedback_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {25, 38, 1}; - return map_enum_number(names, 3, idx, "id"); -} -bool assist_info_feedback_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {25, 38, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e assist_info_feedback_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 25: - return crit_e::reject; - case 38: - return crit_e::reject; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -assist_info_feedback_ies_o::value_c assist_info_feedback_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 25: - ret.set(value_c::types::assist_info_fail_list); - break; - case 38: - ret.set(value_c::types::positioning_broadcast_cells); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e assist_info_feedback_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 25: - return presence_e::optional; - case 38: - return presence_e::optional; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void assist_info_feedback_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::assist_info_fail_list: - c = assist_info_fail_list_l{}; - break; - case types::positioning_broadcast_cells: - c = positioning_broadcast_cells_l{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "assist_info_feedback_ies_o::value_c"); - } -} -assist_info_fail_list_l& assist_info_feedback_ies_o::value_c::assist_info_fail_list() -{ - assert_choice_type(types::assist_info_fail_list, type_, "Value"); - return c.get(); -} -positioning_broadcast_cells_l& assist_info_feedback_ies_o::value_c::positioning_broadcast_cells() -{ - assert_choice_type(types::positioning_broadcast_cells, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& assist_info_feedback_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const assist_info_fail_list_l& assist_info_feedback_ies_o::value_c::assist_info_fail_list() const -{ - assert_choice_type(types::assist_info_fail_list, type_, "Value"); - return c.get(); -} -const positioning_broadcast_cells_l& assist_info_feedback_ies_o::value_c::positioning_broadcast_cells() const -{ - assert_choice_type(types::positioning_broadcast_cells, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& assist_info_feedback_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void assist_info_feedback_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::assist_info_fail_list: - j.start_array("AssistanceInformationFailureList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::positioning_broadcast_cells: - j.start_array("PositioningBroadcastCells"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "assist_info_feedback_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE assist_info_feedback_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::assist_info_fail_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 32, true)); - break; - case types::positioning_broadcast_cells: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 16384, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "assist_info_feedback_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_feedback_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::assist_info_fail_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 32, true)); - break; - case types::positioning_broadcast_cells: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 16384, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "assist_info_feedback_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* assist_info_feedback_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = { - "AssistanceInformationFailureList", "PositioningBroadcastCells", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 3, value, "assist_info_feedback_ies_o::value_c::types"); -} - -// E-CIDMeasurementFailureIndication-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t e_c_id_meas_fail_ind_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {2, 6, 0}; - return map_enum_number(names, 3, idx, "id"); -} -bool e_c_id_meas_fail_ind_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {2, 6, 0}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e e_c_id_meas_fail_ind_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 2: - return crit_e::reject; - case 6: - return crit_e::reject; - case 0: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -e_c_id_meas_fail_ind_ies_o::value_c e_c_id_meas_fail_ind_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 2: - ret.set(value_c::types::lmf_ue_meas_id); - break; - case 6: - ret.set(value_c::types::ran_ue_meas_id); - break; - case 0: - ret.set(value_c::types::cause); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_fail_ind_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 2: - return presence_e::mandatory; - case 6: - return presence_e::mandatory; - case 0: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void e_c_id_meas_fail_ind_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_ue_meas_id: - c = uint8_t{}; - break; - case types::ran_ue_meas_id: - c = uint8_t{}; - break; - case types::cause: - c = cause_c{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_fail_ind_ies_o::value_c"); - } -} -uint8_t& e_c_id_meas_fail_ind_ies_o::value_c::lmf_ue_meas_id() -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -uint8_t& e_c_id_meas_fail_ind_ies_o::value_c::ran_ue_meas_id() -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -cause_c& e_c_id_meas_fail_ind_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_fail_ind_ies_o::value_c::lmf_ue_meas_id() const -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_fail_ind_ies_o::value_c::ran_ue_meas_id() const -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -const cause_c& e_c_id_meas_fail_ind_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -void e_c_id_meas_fail_ind_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::ran_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_fail_ind_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_fail_ind_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_fail_ind_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_fail_ind_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_fail_ind_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_fail_ind_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..15,...)", "INTEGER (1..15,...)", "Cause"}; - return convert_enum_idx(names, 3, value, "e_c_id_meas_fail_ind_ies_o::value_c::types"); -} - -// E-CIDMeasurementInitiationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t e_c_id_meas_initiation_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {2, 0, 1}; - return map_enum_number(names, 3, idx, "id"); -} -bool e_c_id_meas_initiation_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {2, 0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e e_c_id_meas_initiation_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 2: - return crit_e::reject; - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -e_c_id_meas_initiation_fail_ies_o::value_c e_c_id_meas_initiation_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 2: - ret.set(value_c::types::lmf_ue_meas_id); - break; - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_initiation_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 2: - return presence_e::mandatory; - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void e_c_id_meas_initiation_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_ue_meas_id: - c = uint8_t{}; - break; - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_fail_ies_o::value_c"); - } -} -uint8_t& e_c_id_meas_initiation_fail_ies_o::value_c::lmf_ue_meas_id() -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -cause_c& e_c_id_meas_initiation_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& e_c_id_meas_initiation_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_initiation_fail_ies_o::value_c::lmf_ue_meas_id() const -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -const cause_c& e_c_id_meas_initiation_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& e_c_id_meas_initiation_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void e_c_id_meas_initiation_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_initiation_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_initiation_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_initiation_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..15,...)", "Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 3, value, "e_c_id_meas_initiation_fail_ies_o::value_c::types"); -} -uint8_t e_c_id_meas_initiation_fail_ies_o::value_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {1}; - return map_enum_number(numbers, 1, value, "e_c_id_meas_initiation_fail_ies_o::value_c::types"); -} - -// E-CIDMeasurementInitiationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t e_c_id_meas_initiation_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {2, 3, 4, 5, 15, 19, 105}; - return map_enum_number(names, 7, idx, "id"); -} -bool e_c_id_meas_initiation_request_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {2, 3, 4, 5, 15, 19, 105}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e e_c_id_meas_initiation_request_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 2: - return crit_e::reject; - case 3: - return crit_e::reject; - case 4: - return crit_e::reject; - case 5: - return crit_e::reject; - case 15: - return crit_e::ignore; - case 19: - return crit_e::ignore; - case 105: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -e_c_id_meas_initiation_request_ies_o::value_c e_c_id_meas_initiation_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 2: - ret.set(value_c::types::lmf_ue_meas_id); - break; - case 3: - ret.set(value_c::types::report_characteristics); - break; - case 4: - ret.set(value_c::types::meas_periodicity); - break; - case 5: - ret.set(value_c::types::meas_quantities); - break; - case 15: - ret.set(value_c::types::other_rat_meas_quantities); - break; - case 19: - ret.set(value_c::types::wlan_meas_quantities); - break; - case 105: - ret.set(value_c::types::meas_periodicity_nr_ao_a); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_initiation_request_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 2: - return presence_e::mandatory; - case 3: - return presence_e::mandatory; - case 4: - return presence_e::conditional; - case 5: - return presence_e::mandatory; - case 15: - return presence_e::optional; - case 19: - return presence_e::optional; - case 105: - return presence_e::conditional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void e_c_id_meas_initiation_request_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_ue_meas_id: - c = uint8_t{}; - break; - case types::report_characteristics: - c = report_characteristics_e{}; - break; - case types::meas_periodicity: - c = meas_periodicity_e{}; - break; - case types::meas_quantities: - c = meas_quantities_l{}; - break; - case types::other_rat_meas_quantities: - c = other_rat_meas_quantities_l{}; - break; - case types::wlan_meas_quantities: - c = wlan_meas_quantities_l{}; - break; - case types::meas_periodicity_nr_ao_a: - c = meas_periodicity_nr_ao_a_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_request_ies_o::value_c"); - } -} -uint8_t& e_c_id_meas_initiation_request_ies_o::value_c::lmf_ue_meas_id() -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -report_characteristics_e& e_c_id_meas_initiation_request_ies_o::value_c::report_characteristics() -{ - assert_choice_type(types::report_characteristics, type_, "Value"); - return c.get(); -} -meas_periodicity_e& e_c_id_meas_initiation_request_ies_o::value_c::meas_periodicity() -{ - assert_choice_type(types::meas_periodicity, type_, "Value"); - return c.get(); -} -meas_quantities_l& e_c_id_meas_initiation_request_ies_o::value_c::meas_quantities() -{ - assert_choice_type(types::meas_quantities, type_, "Value"); - return c.get(); -} -other_rat_meas_quantities_l& e_c_id_meas_initiation_request_ies_o::value_c::other_rat_meas_quantities() -{ - assert_choice_type(types::other_rat_meas_quantities, type_, "Value"); - return c.get(); -} -wlan_meas_quantities_l& e_c_id_meas_initiation_request_ies_o::value_c::wlan_meas_quantities() -{ - assert_choice_type(types::wlan_meas_quantities, type_, "Value"); - return c.get(); -} -meas_periodicity_nr_ao_a_e& e_c_id_meas_initiation_request_ies_o::value_c::meas_periodicity_nr_ao_a() -{ - assert_choice_type(types::meas_periodicity_nr_ao_a, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_initiation_request_ies_o::value_c::lmf_ue_meas_id() const -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -const report_characteristics_e& e_c_id_meas_initiation_request_ies_o::value_c::report_characteristics() const -{ - assert_choice_type(types::report_characteristics, type_, "Value"); - return c.get(); -} -const meas_periodicity_e& e_c_id_meas_initiation_request_ies_o::value_c::meas_periodicity() const -{ - assert_choice_type(types::meas_periodicity, type_, "Value"); - return c.get(); -} -const meas_quantities_l& e_c_id_meas_initiation_request_ies_o::value_c::meas_quantities() const -{ - assert_choice_type(types::meas_quantities, type_, "Value"); - return c.get(); -} -const other_rat_meas_quantities_l& e_c_id_meas_initiation_request_ies_o::value_c::other_rat_meas_quantities() const -{ - assert_choice_type(types::other_rat_meas_quantities, type_, "Value"); - return c.get(); -} -const wlan_meas_quantities_l& e_c_id_meas_initiation_request_ies_o::value_c::wlan_meas_quantities() const -{ - assert_choice_type(types::wlan_meas_quantities, type_, "Value"); - return c.get(); -} -const meas_periodicity_nr_ao_a_e& e_c_id_meas_initiation_request_ies_o::value_c::meas_periodicity_nr_ao_a() const -{ - assert_choice_type(types::meas_periodicity_nr_ao_a, type_, "Value"); - return c.get(); -} -void e_c_id_meas_initiation_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::report_characteristics: - j.write_str("ReportCharacteristics", c.get().to_string()); - break; - case types::meas_periodicity: - j.write_str("MeasurementPeriodicity", c.get().to_string()); - break; - case types::meas_quantities: - j.start_array("MeasurementQuantities"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::other_rat_meas_quantities: - j.start_array("OtherRATMeasurementQuantities"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::wlan_meas_quantities: - j.start_array("WLANMeasurementQuantities"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::meas_periodicity_nr_ao_a: - j.write_str("MeasurementPeriodicityNR-AoA", c.get().to_string()); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_request_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_initiation_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::report_characteristics: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_periodicity: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_quantities: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - case types::other_rat_meas_quantities: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 0, 64, true)); - break; - case types::wlan_meas_quantities: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 0, 64, true)); - break; - case types::meas_periodicity_nr_ao_a: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_request_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_initiation_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::report_characteristics: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_periodicity: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_quantities: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - case types::other_rat_meas_quantities: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 0, 64, true)); - break; - case types::wlan_meas_quantities: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 0, 64, true)); - break; - case types::meas_periodicity_nr_ao_a: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_request_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_initiation_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..15,...)", - "ReportCharacteristics", - "MeasurementPeriodicity", - "MeasurementQuantities", - "OtherRATMeasurementQuantities", - "WLANMeasurementQuantities", - "MeasurementPeriodicityNR-AoA"}; - return convert_enum_idx(names, 7, value, "e_c_id_meas_initiation_request_ies_o::value_c::types"); -} -uint8_t e_c_id_meas_initiation_request_ies_o::value_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {1}; - return map_enum_number(numbers, 1, value, "e_c_id_meas_initiation_request_ies_o::value_c::types"); -} - -// E-CIDMeasurementInitiationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t e_c_id_meas_initiation_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {2, 6, 7, 1, 14, 17, 21}; - return map_enum_number(names, 7, idx, "id"); -} -bool e_c_id_meas_initiation_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {2, 6, 7, 1, 14, 17, 21}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e e_c_id_meas_initiation_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 2: - return crit_e::reject; - case 6: - return crit_e::reject; - case 7: - return crit_e::ignore; - case 1: - return crit_e::ignore; - case 14: - return crit_e::ignore; - case 17: - return crit_e::ignore; - case 21: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -e_c_id_meas_initiation_resp_ies_o::value_c e_c_id_meas_initiation_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 2: - ret.set(value_c::types::lmf_ue_meas_id); - break; - case 6: - ret.set(value_c::types::ran_ue_meas_id); - break; - case 7: - ret.set(value_c::types::e_c_id_meas_result); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - case 14: - ret.set(value_c::types::cell_portion_id); - break; - case 17: - ret.set(value_c::types::other_rat_meas_result); - break; - case 21: - ret.set(value_c::types::wlan_meas_result); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_initiation_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 2: - return presence_e::mandatory; - case 6: - return presence_e::mandatory; - case 7: - return presence_e::optional; - case 1: - return presence_e::optional; - case 14: - return presence_e::optional; - case 17: - return presence_e::optional; - case 21: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void e_c_id_meas_initiation_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_ue_meas_id: - c = uint8_t{}; - break; - case types::ran_ue_meas_id: - c = uint8_t{}; - break; - case types::e_c_id_meas_result: - c = e_c_id_meas_result_s{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::cell_portion_id: - c = uint16_t{}; - break; - case types::other_rat_meas_result: - c = other_rat_meas_result_l{}; - break; - case types::wlan_meas_result: - c = wlan_meas_result_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_resp_ies_o::value_c"); - } -} -uint8_t& e_c_id_meas_initiation_resp_ies_o::value_c::lmf_ue_meas_id() -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -uint8_t& e_c_id_meas_initiation_resp_ies_o::value_c::ran_ue_meas_id() -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -e_c_id_meas_result_s& e_c_id_meas_initiation_resp_ies_o::value_c::e_c_id_meas_result() -{ - assert_choice_type(types::e_c_id_meas_result, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& e_c_id_meas_initiation_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -uint16_t& e_c_id_meas_initiation_resp_ies_o::value_c::cell_portion_id() -{ - assert_choice_type(types::cell_portion_id, type_, "Value"); - return c.get(); -} -other_rat_meas_result_l& e_c_id_meas_initiation_resp_ies_o::value_c::other_rat_meas_result() -{ - assert_choice_type(types::other_rat_meas_result, type_, "Value"); - return c.get(); -} -wlan_meas_result_l& e_c_id_meas_initiation_resp_ies_o::value_c::wlan_meas_result() -{ - assert_choice_type(types::wlan_meas_result, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_initiation_resp_ies_o::value_c::lmf_ue_meas_id() const -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_initiation_resp_ies_o::value_c::ran_ue_meas_id() const -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -const e_c_id_meas_result_s& e_c_id_meas_initiation_resp_ies_o::value_c::e_c_id_meas_result() const -{ - assert_choice_type(types::e_c_id_meas_result, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& e_c_id_meas_initiation_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const uint16_t& e_c_id_meas_initiation_resp_ies_o::value_c::cell_portion_id() const -{ - assert_choice_type(types::cell_portion_id, type_, "Value"); - return c.get(); -} -const other_rat_meas_result_l& e_c_id_meas_initiation_resp_ies_o::value_c::other_rat_meas_result() const -{ - assert_choice_type(types::other_rat_meas_result, type_, "Value"); - return c.get(); -} -const wlan_meas_result_l& e_c_id_meas_initiation_resp_ies_o::value_c::wlan_meas_result() const -{ - assert_choice_type(types::wlan_meas_result, type_, "Value"); - return c.get(); -} -void e_c_id_meas_initiation_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::ran_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::e_c_id_meas_result: - j.write_fieldname("E-CID-MeasurementResult"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - case types::cell_portion_id: - j.write_int("INTEGER (0..4095,...)", c.get()); - break; - case types::other_rat_meas_result: - j.start_array("OtherRATMeasurementResult"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::wlan_meas_result: - j.start_array("WLANMeasurementResult"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_initiation_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::e_c_id_meas_result: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::cell_portion_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::other_rat_meas_result: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - case types::wlan_meas_result: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_initiation_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::e_c_id_meas_result: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::cell_portion_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - case types::other_rat_meas_result: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - case types::wlan_meas_result: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_initiation_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_initiation_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..15,...)", - "INTEGER (1..15,...)", - "E-CID-MeasurementResult", - "CriticalityDiagnostics", - "INTEGER (0..4095,...)", - "OtherRATMeasurementResult", - "WLANMeasurementResult"}; - return convert_enum_idx(names, 7, value, "e_c_id_meas_initiation_resp_ies_o::value_c::types"); -} - -// E-CIDMeasurementReport-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t e_c_id_meas_report_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {2, 6, 7, 14}; - return map_enum_number(names, 4, idx, "id"); -} -bool e_c_id_meas_report_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {2, 6, 7, 14}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e e_c_id_meas_report_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 2: - return crit_e::reject; - case 6: - return crit_e::reject; - case 7: - return crit_e::ignore; - case 14: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -e_c_id_meas_report_ies_o::value_c e_c_id_meas_report_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 2: - ret.set(value_c::types::lmf_ue_meas_id); - break; - case 6: - ret.set(value_c::types::ran_ue_meas_id); - break; - case 7: - ret.set(value_c::types::e_c_id_meas_result); - break; - case 14: - ret.set(value_c::types::cell_portion_id); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_report_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 2: - return presence_e::mandatory; - case 6: - return presence_e::mandatory; - case 7: - return presence_e::mandatory; - case 14: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void e_c_id_meas_report_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_ue_meas_id: - c = uint8_t{}; - break; - case types::ran_ue_meas_id: - c = uint8_t{}; - break; - case types::e_c_id_meas_result: - c = e_c_id_meas_result_s{}; - break; - case types::cell_portion_id: - c = uint16_t{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_report_ies_o::value_c"); - } -} -uint8_t& e_c_id_meas_report_ies_o::value_c::lmf_ue_meas_id() -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -uint8_t& e_c_id_meas_report_ies_o::value_c::ran_ue_meas_id() -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -e_c_id_meas_result_s& e_c_id_meas_report_ies_o::value_c::e_c_id_meas_result() -{ - assert_choice_type(types::e_c_id_meas_result, type_, "Value"); - return c.get(); -} -uint16_t& e_c_id_meas_report_ies_o::value_c::cell_portion_id() -{ - assert_choice_type(types::cell_portion_id, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_report_ies_o::value_c::lmf_ue_meas_id() const -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_report_ies_o::value_c::ran_ue_meas_id() const -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -const e_c_id_meas_result_s& e_c_id_meas_report_ies_o::value_c::e_c_id_meas_result() const -{ - assert_choice_type(types::e_c_id_meas_result, type_, "Value"); - return c.get(); -} -const uint16_t& e_c_id_meas_report_ies_o::value_c::cell_portion_id() const -{ - assert_choice_type(types::cell_portion_id, type_, "Value"); - return c.get(); -} -void e_c_id_meas_report_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::ran_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::e_c_id_meas_result: - j.write_fieldname("E-CID-MeasurementResult"); - c.get().to_json(j); - break; - case types::cell_portion_id: - j.write_int("INTEGER (0..4095,...)", c.get()); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_report_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_report_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::e_c_id_meas_result: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::cell_portion_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_report_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_report_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::e_c_id_meas_result: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::cell_portion_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_report_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_report_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = { - "INTEGER (1..15,...)", "INTEGER (1..15,...)", "E-CID-MeasurementResult", "INTEGER (0..4095,...)"}; - return convert_enum_idx(names, 4, value, "e_c_id_meas_report_ies_o::value_c::types"); -} - -// E-CIDMeasurementTerminationCommand-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t e_c_id_meas_termination_cmd_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {2, 6}; - return map_enum_number(names, 2, idx, "id"); -} -bool e_c_id_meas_termination_cmd_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {2, 6}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e e_c_id_meas_termination_cmd_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 2: - return crit_e::reject; - case 6: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -e_c_id_meas_termination_cmd_ies_o::value_c e_c_id_meas_termination_cmd_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 2: - ret.set(value_c::types::lmf_ue_meas_id); - break; - case 6: - ret.set(value_c::types::ran_ue_meas_id); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e e_c_id_meas_termination_cmd_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 2: - return presence_e::mandatory; - case 6: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void e_c_id_meas_termination_cmd_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_ue_meas_id: - c = uint8_t{}; - break; - case types::ran_ue_meas_id: - c = uint8_t{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_termination_cmd_ies_o::value_c"); - } -} -uint8_t& e_c_id_meas_termination_cmd_ies_o::value_c::lmf_ue_meas_id() -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -uint8_t& e_c_id_meas_termination_cmd_ies_o::value_c::ran_ue_meas_id() -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_termination_cmd_ies_o::value_c::lmf_ue_meas_id() const -{ - assert_choice_type(types::lmf_ue_meas_id, type_, "Value"); - return c.get(); -} -const uint8_t& e_c_id_meas_termination_cmd_ies_o::value_c::ran_ue_meas_id() const -{ - assert_choice_type(types::ran_ue_meas_id, type_, "Value"); - return c.get(); -} -void e_c_id_meas_termination_cmd_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - case types::ran_ue_meas_id: - j.write_int("INTEGER (1..15,...)", c.get()); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_termination_cmd_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE e_c_id_meas_termination_cmd_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)1u, (uint8_t)15u, true, true)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_termination_cmd_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_termination_cmd_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - case types::ran_ue_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - default: - log_invalid_choice_id(type_, "e_c_id_meas_termination_cmd_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* e_c_id_meas_termination_cmd_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..15,...)", "INTEGER (1..15,...)"}; - return convert_enum_idx(names, 2, value, "e_c_id_meas_termination_cmd_ies_o::value_c::types"); -} - -// ErrorIndication-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t error_ind_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool error_ind_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e error_ind_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -error_ind_ies_o::value_c error_ind_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e error_ind_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::optional; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void error_ind_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "error_ind_ies_o::value_c"); - } -} -cause_c& error_ind_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& error_ind_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& error_ind_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& error_ind_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void error_ind_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "error_ind_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE error_ind_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "error_ind_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE error_ind_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "error_ind_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* error_ind_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "error_ind_ies_o::value_c::types"); -} - -// MeasurementAbort-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_abort_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 40}; - return map_enum_number(names, 2, idx, "id"); -} -bool meas_abort_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 40}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_abort_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 40: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_abort_ies_o::value_c meas_abort_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 40: - ret.set(value_c::types::ran_meas_id); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_abort_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 40: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_abort_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::ran_meas_id: - c = uint32_t{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_abort_ies_o::value_c"); - } -} -uint32_t& meas_abort_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -uint32_t& meas_abort_ies_o::value_c::ran_meas_id() -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -const uint32_t& meas_abort_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const uint32_t& meas_abort_ies_o::value_c::ran_meas_id() const -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -void meas_abort_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::ran_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - default: - log_invalid_choice_id(type_, "meas_abort_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_abort_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - default: - log_invalid_choice_id(type_, "meas_abort_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_abort_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - default: - log_invalid_choice_id(type_, "meas_abort_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_abort_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..65536,...)", "INTEGER (1..65536,...)"}; - return convert_enum_idx(names, 2, value, "meas_abort_ies_o::value_c::types"); -} - -// MeasurementActivation-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_activation_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {98, 88}; - return map_enum_number(names, 2, idx, "id"); -} -bool meas_activation_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {98, 88}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_activation_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 98: - return crit_e::reject; - case 88: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_activation_ies_o::value_c meas_activation_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 98: - ret.set(value_c::types::request_type); - break; - case 88: - ret.set(value_c::types::prs_meass_info_list); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_activation_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 98: - return presence_e::mandatory; - case 88: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_activation_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::request_type: - c = request_type_e{}; - break; - case types::prs_meass_info_list: - c = prs_meass_info_list_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_activation_ies_o::value_c"); - } -} -request_type_e& meas_activation_ies_o::value_c::request_type() -{ - assert_choice_type(types::request_type, type_, "Value"); - return c.get(); -} -prs_meass_info_list_l& meas_activation_ies_o::value_c::prs_meass_info_list() -{ - assert_choice_type(types::prs_meass_info_list, type_, "Value"); - return c.get(); -} -const request_type_e& meas_activation_ies_o::value_c::request_type() const -{ - assert_choice_type(types::request_type, type_, "Value"); - return c.get(); -} -const prs_meass_info_list_l& meas_activation_ies_o::value_c::prs_meass_info_list() const -{ - assert_choice_type(types::prs_meass_info_list, type_, "Value"); - return c.get(); -} -void meas_activation_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::request_type: - j.write_str("RequestType", c.get().to_string()); - break; - case types::prs_meass_info_list: - j.start_array("PRS-Measurements-Info-List"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "meas_activation_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_activation_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::request_type: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_meass_info_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 4, true)); - break; - default: - log_invalid_choice_id(type_, "meas_activation_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_activation_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::request_type: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_meass_info_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 4, true)); - break; - default: - log_invalid_choice_id(type_, "meas_activation_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_activation_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"RequestType", "PRS-Measurements-Info-List"}; - return convert_enum_idx(names, 2, value, "meas_activation_ies_o::value_c::types"); -} - -// MeasurementFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 0, 1}; - return map_enum_number(names, 3, idx, "id"); -} -bool meas_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_fail_ies_o::value_c meas_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_fail_ies_o::value_c"); - } -} -uint32_t& meas_fail_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -cause_c& meas_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& meas_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const uint32_t& meas_fail_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const cause_c& meas_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& meas_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void meas_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "meas_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..65536,...)", "Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 3, value, "meas_fail_ies_o::value_c::types"); -} -uint8_t meas_fail_ies_o::value_c::types_opts::to_number() const -{ - static const uint8_t numbers[] = {1}; - return map_enum_number(numbers, 1, value, "meas_fail_ies_o::value_c::types"); -} - -// MeasurementFailureIndication-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_fail_ind_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 40, 0}; - return map_enum_number(names, 3, idx, "id"); -} -bool meas_fail_ind_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 40, 0}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_fail_ind_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 40: - return crit_e::reject; - case 0: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_fail_ind_ies_o::value_c meas_fail_ind_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 40: - ret.set(value_c::types::ran_meas_id); - break; - case 0: - ret.set(value_c::types::cause); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_fail_ind_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 40: - return presence_e::mandatory; - case 0: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_fail_ind_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::ran_meas_id: - c = uint32_t{}; - break; - case types::cause: - c = cause_c{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_fail_ind_ies_o::value_c"); - } -} -uint32_t& meas_fail_ind_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -uint32_t& meas_fail_ind_ies_o::value_c::ran_meas_id() -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -cause_c& meas_fail_ind_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const uint32_t& meas_fail_ind_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const uint32_t& meas_fail_ind_ies_o::value_c::ran_meas_id() const -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -const cause_c& meas_fail_ind_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -void meas_fail_ind_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::ran_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "meas_fail_ind_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_fail_ind_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_fail_ind_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_fail_ind_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_fail_ind_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_fail_ind_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..65536,...)", "INTEGER (1..65536,...)", "Cause"}; - return convert_enum_idx(names, 3, value, "meas_fail_ind_ies_o::value_c::types"); -} - -// MeasurementPreconfigurationConfirm-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_precfg_confirm_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {97, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool meas_precfg_confirm_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {97, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_precfg_confirm_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 97: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_precfg_confirm_ies_o::value_c meas_precfg_confirm_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 97: - ret.set(value_c::types::precfg_result); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_precfg_confirm_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 97: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_precfg_confirm_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::precfg_result: - c = fixed_bitstring<8, false, true>{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_precfg_confirm_ies_o::value_c"); - } -} -fixed_bitstring<8, false, true>& meas_precfg_confirm_ies_o::value_c::precfg_result() -{ - assert_choice_type(types::precfg_result, type_, "Value"); - return c.get>(); -} -crit_diagnostics_s& meas_precfg_confirm_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const fixed_bitstring<8, false, true>& meas_precfg_confirm_ies_o::value_c::precfg_result() const -{ - assert_choice_type(types::precfg_result, type_, "Value"); - return c.get>(); -} -const crit_diagnostics_s& meas_precfg_confirm_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void meas_precfg_confirm_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::precfg_result: - j.write_str("BIT STRING", c.get>().to_string()); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "meas_precfg_confirm_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_precfg_confirm_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::precfg_result: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_precfg_confirm_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_precfg_confirm_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::precfg_result: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_precfg_confirm_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_precfg_confirm_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"BIT STRING", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "meas_precfg_confirm_ies_o::value_c::types"); -} - -// MeasurementPreconfigurationRefuse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_precfg_refuse_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool meas_precfg_refuse_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_precfg_refuse_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_precfg_refuse_ies_o::value_c meas_precfg_refuse_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_precfg_refuse_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_precfg_refuse_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_precfg_refuse_ies_o::value_c"); - } -} -cause_c& meas_precfg_refuse_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& meas_precfg_refuse_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& meas_precfg_refuse_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& meas_precfg_refuse_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void meas_precfg_refuse_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "meas_precfg_refuse_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_precfg_refuse_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_precfg_refuse_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_precfg_refuse_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_precfg_refuse_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_precfg_refuse_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "meas_precfg_refuse_ies_o::value_c::types"); -} - -// MeasurementReport-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_report_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 40, 43}; - return map_enum_number(names, 3, idx, "id"); -} -bool meas_report_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 40, 43}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_report_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 40: - return crit_e::reject; - case 43: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_report_ies_o::value_c meas_report_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 40: - ret.set(value_c::types::ran_meas_id); - break; - case 43: - ret.set(value_c::types::trp_meas_report_list); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_report_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 40: - return presence_e::mandatory; - case 43: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_report_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::ran_meas_id: - c = uint32_t{}; - break; - case types::trp_meas_report_list: - c = trp_meas_resp_list_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_report_ies_o::value_c"); - } -} -uint32_t& meas_report_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -uint32_t& meas_report_ies_o::value_c::ran_meas_id() -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -trp_meas_resp_list_l& meas_report_ies_o::value_c::trp_meas_report_list() -{ - assert_choice_type(types::trp_meas_report_list, type_, "Value"); - return c.get(); -} -const uint32_t& meas_report_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const uint32_t& meas_report_ies_o::value_c::ran_meas_id() const -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -const trp_meas_resp_list_l& meas_report_ies_o::value_c::trp_meas_report_list() const -{ - assert_choice_type(types::trp_meas_report_list, type_, "Value"); - return c.get(); -} -void meas_report_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::ran_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::trp_meas_report_list: - j.start_array("TRP-MeasurementResponseList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "meas_report_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_report_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::trp_meas_report_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - default: - log_invalid_choice_id(type_, "meas_report_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_report_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::trp_meas_report_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - default: - log_invalid_choice_id(type_, "meas_report_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_report_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..65536,...)", "INTEGER (1..65536,...)", "TRP-MeasurementResponseList"}; - return convert_enum_idx(names, 3, value, "meas_report_ies_o::value_c::types"); -} - -// MeasurementRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 41, 3, 4, 52, 54, 26, 31, 49, 50, 64, 72, 92, 91, 95}; - return map_enum_number(names, 15, idx, "id"); -} -bool meas_request_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 41, 3, 4, 52, 54, 26, 31, 49, 50, 64, 72, 92, 91, 95}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_request_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 41: - return crit_e::reject; - case 3: - return crit_e::reject; - case 4: - return crit_e::reject; - case 52: - return crit_e::reject; - case 54: - return crit_e::ignore; - case 26: - return crit_e::ignore; - case 31: - return crit_e::ignore; - case 49: - return crit_e::ignore; - case 50: - return crit_e::ignore; - case 64: - return crit_e::reject; - case 72: - return crit_e::ignore; - case 92: - return crit_e::ignore; - case 91: - return crit_e::ignore; - case 95: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_request_ies_o::value_c meas_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 41: - ret.set(value_c::types::trp_meas_request_list); - break; - case 3: - ret.set(value_c::types::report_characteristics); - break; - case 4: - ret.set(value_c::types::meas_periodicity); - break; - case 52: - ret.set(value_c::types::trp_meas_quantities); - break; - case 54: - ret.set(value_c::types::sfn_initisation_time); - break; - case 26: - ret.set(value_c::types::srscfg); - break; - case 31: - ret.set(value_c::types::meas_beam_info_request); - break; - case 49: - ret.set(value_c::types::sys_frame_num); - break; - case 50: - ret.set(value_c::types::slot_num); - break; - case 64: - ret.set(value_c::types::meas_periodicity_extended); - break; - case 72: - ret.set(value_c::types::resp_time); - break; - case 92: - ret.set(value_c::types::meas_characteristics_request_ind); - break; - case 91: - ret.set(value_c::types::meas_time_occasion); - break; - case 95: - ret.set(value_c::types::meas_amount); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_request_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 41: - return presence_e::mandatory; - case 3: - return presence_e::mandatory; - case 4: - return presence_e::conditional; - case 52: - return presence_e::mandatory; - case 54: - return presence_e::optional; - case 26: - return presence_e::optional; - case 31: - return presence_e::optional; - case 49: - return presence_e::optional; - case 50: - return presence_e::optional; - case 64: - return presence_e::conditional; - case 72: - return presence_e::optional; - case 92: - return presence_e::optional; - case 91: - return presence_e::optional; - case 95: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_request_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::trp_meas_request_list: - c = trp_meas_request_list_l{}; - break; - case types::report_characteristics: - c = report_characteristics_e{}; - break; - case types::meas_periodicity: - c = meas_periodicity_e{}; - break; - case types::trp_meas_quantities: - c = trp_meas_quantities_l{}; - break; - case types::sfn_initisation_time: - c = fixed_bitstring<64, false, true>{}; - break; - case types::srscfg: - c = srscfg_s{}; - break; - case types::meas_beam_info_request: - c = meas_beam_info_request_e{}; - break; - case types::sys_frame_num: - c = uint16_t{}; - break; - case types::slot_num: - c = uint8_t{}; - break; - case types::meas_periodicity_extended: - c = meas_periodicity_extended_e{}; - break; - case types::resp_time: - c = resp_time_s{}; - break; - case types::meas_characteristics_request_ind: - c = fixed_bitstring<16, false, true>{}; - break; - case types::meas_time_occasion: - c = meas_time_occasion_e{}; - break; - case types::meas_amount: - c = meas_amount_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_request_ies_o::value_c"); - } -} -uint32_t& meas_request_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -trp_meas_request_list_l& meas_request_ies_o::value_c::trp_meas_request_list() -{ - assert_choice_type(types::trp_meas_request_list, type_, "Value"); - return c.get(); -} -report_characteristics_e& meas_request_ies_o::value_c::report_characteristics() -{ - assert_choice_type(types::report_characteristics, type_, "Value"); - return c.get(); -} -meas_periodicity_e& meas_request_ies_o::value_c::meas_periodicity() -{ - assert_choice_type(types::meas_periodicity, type_, "Value"); - return c.get(); -} -trp_meas_quantities_l& meas_request_ies_o::value_c::trp_meas_quantities() -{ - assert_choice_type(types::trp_meas_quantities, type_, "Value"); - return c.get(); -} -fixed_bitstring<64, false, true>& meas_request_ies_o::value_c::sfn_initisation_time() -{ - assert_choice_type(types::sfn_initisation_time, type_, "Value"); - return c.get>(); -} -srscfg_s& meas_request_ies_o::value_c::srscfg() -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -meas_beam_info_request_e& meas_request_ies_o::value_c::meas_beam_info_request() -{ - assert_choice_type(types::meas_beam_info_request, type_, "Value"); - return c.get(); -} -uint16_t& meas_request_ies_o::value_c::sys_frame_num() -{ - assert_choice_type(types::sys_frame_num, type_, "Value"); - return c.get(); -} -uint8_t& meas_request_ies_o::value_c::slot_num() -{ - assert_choice_type(types::slot_num, type_, "Value"); - return c.get(); -} -meas_periodicity_extended_e& meas_request_ies_o::value_c::meas_periodicity_extended() -{ - assert_choice_type(types::meas_periodicity_extended, type_, "Value"); - return c.get(); -} -resp_time_s& meas_request_ies_o::value_c::resp_time() -{ - assert_choice_type(types::resp_time, type_, "Value"); - return c.get(); -} -fixed_bitstring<16, false, true>& meas_request_ies_o::value_c::meas_characteristics_request_ind() -{ - assert_choice_type(types::meas_characteristics_request_ind, type_, "Value"); - return c.get>(); -} -meas_time_occasion_e& meas_request_ies_o::value_c::meas_time_occasion() -{ - assert_choice_type(types::meas_time_occasion, type_, "Value"); - return c.get(); -} -meas_amount_e& meas_request_ies_o::value_c::meas_amount() -{ - assert_choice_type(types::meas_amount, type_, "Value"); - return c.get(); -} -const uint32_t& meas_request_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const trp_meas_request_list_l& meas_request_ies_o::value_c::trp_meas_request_list() const -{ - assert_choice_type(types::trp_meas_request_list, type_, "Value"); - return c.get(); -} -const report_characteristics_e& meas_request_ies_o::value_c::report_characteristics() const -{ - assert_choice_type(types::report_characteristics, type_, "Value"); - return c.get(); -} -const meas_periodicity_e& meas_request_ies_o::value_c::meas_periodicity() const -{ - assert_choice_type(types::meas_periodicity, type_, "Value"); - return c.get(); -} -const trp_meas_quantities_l& meas_request_ies_o::value_c::trp_meas_quantities() const -{ - assert_choice_type(types::trp_meas_quantities, type_, "Value"); - return c.get(); -} -const fixed_bitstring<64, false, true>& meas_request_ies_o::value_c::sfn_initisation_time() const -{ - assert_choice_type(types::sfn_initisation_time, type_, "Value"); - return c.get>(); -} -const srscfg_s& meas_request_ies_o::value_c::srscfg() const -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -const meas_beam_info_request_e& meas_request_ies_o::value_c::meas_beam_info_request() const -{ - assert_choice_type(types::meas_beam_info_request, type_, "Value"); - return c.get(); -} -const uint16_t& meas_request_ies_o::value_c::sys_frame_num() const -{ - assert_choice_type(types::sys_frame_num, type_, "Value"); - return c.get(); -} -const uint8_t& meas_request_ies_o::value_c::slot_num() const -{ - assert_choice_type(types::slot_num, type_, "Value"); - return c.get(); -} -const meas_periodicity_extended_e& meas_request_ies_o::value_c::meas_periodicity_extended() const -{ - assert_choice_type(types::meas_periodicity_extended, type_, "Value"); - return c.get(); -} -const resp_time_s& meas_request_ies_o::value_c::resp_time() const -{ - assert_choice_type(types::resp_time, type_, "Value"); - return c.get(); -} -const fixed_bitstring<16, false, true>& meas_request_ies_o::value_c::meas_characteristics_request_ind() const -{ - assert_choice_type(types::meas_characteristics_request_ind, type_, "Value"); - return c.get>(); -} -const meas_time_occasion_e& meas_request_ies_o::value_c::meas_time_occasion() const -{ - assert_choice_type(types::meas_time_occasion, type_, "Value"); - return c.get(); -} -const meas_amount_e& meas_request_ies_o::value_c::meas_amount() const -{ - assert_choice_type(types::meas_amount, type_, "Value"); - return c.get(); -} -void meas_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::trp_meas_request_list: - j.start_array("TRP-MeasurementRequestList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::report_characteristics: - j.write_str("ReportCharacteristics", c.get().to_string()); - break; - case types::meas_periodicity: - j.write_str("MeasurementPeriodicity", c.get().to_string()); - break; - case types::trp_meas_quantities: - j.start_array("TRPMeasurementQuantities"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::sfn_initisation_time: - j.write_str("BIT STRING", c.get>().to_string()); - break; - case types::srscfg: - j.write_fieldname("SRSConfiguration"); - c.get().to_json(j); - break; - case types::meas_beam_info_request: - j.write_str("MeasurementBeamInfoRequest", "true"); - break; - case types::sys_frame_num: - j.write_int("INTEGER (0..1023)", c.get()); - break; - case types::slot_num: - j.write_int("INTEGER (0..79)", c.get()); - break; - case types::meas_periodicity_extended: - j.write_str("MeasurementPeriodicityExtended", c.get().to_string()); - break; - case types::resp_time: - j.write_fieldname("ResponseTime"); - c.get().to_json(j); - break; - case types::meas_characteristics_request_ind: - j.write_str("BIT STRING", c.get>().to_string()); - break; - case types::meas_time_occasion: - j.write_str("MeasurementTimeOccasion", c.get().to_string()); - break; - case types::meas_amount: - j.write_str("MeasurementAmount", c.get().to_string()); - break; - default: - log_invalid_choice_id(type_, "meas_request_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::trp_meas_request_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - case types::report_characteristics: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_periodicity: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_meas_quantities: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 16384, true)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::srscfg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_beam_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sys_frame_num: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)1023u, false, true)); - break; - case types::slot_num: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)79u, false, true)); - break; - case types::meas_periodicity_extended: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::resp_time: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_characteristics_request_ind: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::meas_time_occasion: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_amount: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_request_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::trp_meas_request_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - case types::report_characteristics: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_periodicity: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_meas_quantities: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 16384, true)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::srscfg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_beam_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sys_frame_num: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)1023u, false, true)); - break; - case types::slot_num: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)79u, false, true)); - break; - case types::meas_periodicity_extended: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::resp_time: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_characteristics_request_ind: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::meas_time_occasion: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_amount: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_request_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..65536,...)", - "TRP-MeasurementRequestList", - "ReportCharacteristics", - "MeasurementPeriodicity", - "TRPMeasurementQuantities", - "BIT STRING", - "SRSConfiguration", - "MeasurementBeamInfoRequest", - "INTEGER (0..1023)", - "INTEGER (0..79)", - "MeasurementPeriodicityExtended", - "ResponseTime", - "BIT STRING", - "MeasurementTimeOccasion", - "MeasurementAmount"}; - return convert_enum_idx(names, 15, value, "meas_request_ies_o::value_c::types"); -} - -// MeasurementResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 40, 42, 1}; - return map_enum_number(names, 4, idx, "id"); -} -bool meas_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 40, 42, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 40: - return crit_e::reject; - case 42: - return crit_e::reject; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_resp_ies_o::value_c meas_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 40: - ret.set(value_c::types::ran_meas_id); - break; - case 42: - ret.set(value_c::types::trp_meas_resp_list); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 40: - return presence_e::mandatory; - case 42: - return presence_e::optional; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::ran_meas_id: - c = uint32_t{}; - break; - case types::trp_meas_resp_list: - c = trp_meas_resp_list_l{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_resp_ies_o::value_c"); - } -} -uint32_t& meas_resp_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -uint32_t& meas_resp_ies_o::value_c::ran_meas_id() -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -trp_meas_resp_list_l& meas_resp_ies_o::value_c::trp_meas_resp_list() -{ - assert_choice_type(types::trp_meas_resp_list, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& meas_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const uint32_t& meas_resp_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const uint32_t& meas_resp_ies_o::value_c::ran_meas_id() const -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -const trp_meas_resp_list_l& meas_resp_ies_o::value_c::trp_meas_resp_list() const -{ - assert_choice_type(types::trp_meas_resp_list, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& meas_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void meas_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::ran_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::trp_meas_resp_list: - j.start_array("TRP-MeasurementResponseList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "meas_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::trp_meas_resp_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::trp_meas_resp_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = { - "INTEGER (1..65536,...)", "INTEGER (1..65536,...)", "TRP-MeasurementResponseList", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 4, value, "meas_resp_ies_o::value_c::types"); -} - -// MeasurementUpdate-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_upd_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {39, 40, 26, 70, 92, 91}; - return map_enum_number(names, 6, idx, "id"); -} -bool meas_upd_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {39, 40, 26, 70, 92, 91}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e meas_upd_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 39: - return crit_e::reject; - case 40: - return crit_e::reject; - case 26: - return crit_e::ignore; - case 70: - return crit_e::reject; - case 92: - return crit_e::ignore; - case 91: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -meas_upd_ies_o::value_c meas_upd_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 39: - ret.set(value_c::types::lmf_meas_id); - break; - case 40: - ret.set(value_c::types::ran_meas_id); - break; - case 26: - ret.set(value_c::types::srscfg); - break; - case 70: - ret.set(value_c::types::trp_meas_upd_list); - break; - case 92: - ret.set(value_c::types::meas_characteristics_request_ind); - break; - case 91: - ret.set(value_c::types::meas_time_occasion); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_upd_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 39: - return presence_e::mandatory; - case 40: - return presence_e::mandatory; - case 26: - return presence_e::optional; - case 70: - return presence_e::optional; - case 92: - return presence_e::optional; - case 91: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void meas_upd_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::lmf_meas_id: - c = uint32_t{}; - break; - case types::ran_meas_id: - c = uint32_t{}; - break; - case types::srscfg: - c = srscfg_s{}; - break; - case types::trp_meas_upd_list: - c = trp_meas_upd_list_l{}; - break; - case types::meas_characteristics_request_ind: - c = fixed_bitstring<16, false, true>{}; - break; - case types::meas_time_occasion: - c = meas_time_occasion_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "meas_upd_ies_o::value_c"); - } -} -uint32_t& meas_upd_ies_o::value_c::lmf_meas_id() -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -uint32_t& meas_upd_ies_o::value_c::ran_meas_id() -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -srscfg_s& meas_upd_ies_o::value_c::srscfg() -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -trp_meas_upd_list_l& meas_upd_ies_o::value_c::trp_meas_upd_list() -{ - assert_choice_type(types::trp_meas_upd_list, type_, "Value"); - return c.get(); -} -fixed_bitstring<16, false, true>& meas_upd_ies_o::value_c::meas_characteristics_request_ind() -{ - assert_choice_type(types::meas_characteristics_request_ind, type_, "Value"); - return c.get>(); -} -meas_time_occasion_e& meas_upd_ies_o::value_c::meas_time_occasion() -{ - assert_choice_type(types::meas_time_occasion, type_, "Value"); - return c.get(); -} -const uint32_t& meas_upd_ies_o::value_c::lmf_meas_id() const -{ - assert_choice_type(types::lmf_meas_id, type_, "Value"); - return c.get(); -} -const uint32_t& meas_upd_ies_o::value_c::ran_meas_id() const -{ - assert_choice_type(types::ran_meas_id, type_, "Value"); - return c.get(); -} -const srscfg_s& meas_upd_ies_o::value_c::srscfg() const -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -const trp_meas_upd_list_l& meas_upd_ies_o::value_c::trp_meas_upd_list() const -{ - assert_choice_type(types::trp_meas_upd_list, type_, "Value"); - return c.get(); -} -const fixed_bitstring<16, false, true>& meas_upd_ies_o::value_c::meas_characteristics_request_ind() const -{ - assert_choice_type(types::meas_characteristics_request_ind, type_, "Value"); - return c.get>(); -} -const meas_time_occasion_e& meas_upd_ies_o::value_c::meas_time_occasion() const -{ - assert_choice_type(types::meas_time_occasion, type_, "Value"); - return c.get(); -} -void meas_upd_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::lmf_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::ran_meas_id: - j.write_int("INTEGER (1..65536,...)", c.get()); - break; - case types::srscfg: - j.write_fieldname("SRSConfiguration"); - c.get().to_json(j); - break; - case types::trp_meas_upd_list: - j.start_array("TRP-MeasurementUpdateList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::meas_characteristics_request_ind: - j.write_str("BIT STRING", c.get>().to_string()); - break; - case types::meas_time_occasion: - j.write_str("MeasurementTimeOccasion", c.get().to_string()); - break; - default: - log_invalid_choice_id(type_, "meas_upd_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE meas_upd_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(pack_integer(bref, c.get(), (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::srscfg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_meas_upd_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - case types::meas_characteristics_request_ind: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::meas_time_occasion: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_upd_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_upd_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::lmf_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::ran_meas_id: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - case types::srscfg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_meas_upd_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - case types::meas_characteristics_request_ind: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::meas_time_occasion: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "meas_upd_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* meas_upd_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"INTEGER (1..65536,...)", - "INTEGER (1..65536,...)", - "SRSConfiguration", - "TRP-MeasurementUpdateList", - "BIT STRING", - "MeasurementTimeOccasion"}; - return convert_enum_idx(names, 6, value, "meas_upd_ies_o::value_c::types"); -} - -// OTDOAInformationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t otdoa_info_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool otdoa_info_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e otdoa_info_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -otdoa_info_fail_ies_o::value_c otdoa_info_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e otdoa_info_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void otdoa_info_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "otdoa_info_fail_ies_o::value_c"); - } -} -cause_c& otdoa_info_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& otdoa_info_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& otdoa_info_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& otdoa_info_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void otdoa_info_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "otdoa_info_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE otdoa_info_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "otdoa_info_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "otdoa_info_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* otdoa_info_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "otdoa_info_fail_ies_o::value_c::types"); -} - -// OTDOAInformationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t otdoa_info_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {8, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool otdoa_info_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {8, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e otdoa_info_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 8: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -otdoa_info_resp_ies_o::value_c otdoa_info_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 8: - ret.set(value_c::types::otdoa_cells); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e otdoa_info_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 8: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void otdoa_info_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::otdoa_cells: - c = otdoa_cells_l{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "otdoa_info_resp_ies_o::value_c"); - } -} -otdoa_cells_l& otdoa_info_resp_ies_o::value_c::otdoa_cells() -{ - assert_choice_type(types::otdoa_cells, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& otdoa_info_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const otdoa_cells_l& otdoa_info_resp_ies_o::value_c::otdoa_cells() const -{ - assert_choice_type(types::otdoa_cells, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& otdoa_info_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void otdoa_info_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::otdoa_cells: - j.start_array("OTDOACells"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "otdoa_info_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE otdoa_info_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::otdoa_cells: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 3840, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "otdoa_info_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::otdoa_cells: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 3840, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "otdoa_info_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* otdoa_info_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"OTDOACells", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "otdoa_info_resp_ies_o::value_c::types"); -} - -// PositioningActivationFailureIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_activation_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool positioning_activation_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_activation_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_activation_fail_ies_o::value_c positioning_activation_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_activation_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_activation_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_activation_fail_ies_o::value_c"); - } -} -cause_c& positioning_activation_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& positioning_activation_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& positioning_activation_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& positioning_activation_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void positioning_activation_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_activation_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_activation_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_activation_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "positioning_activation_fail_ies_o::value_c::types"); -} - -// PositioningActivationRequestIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_activation_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {44, 45}; - return map_enum_number(names, 2, idx, "id"); -} -bool positioning_activation_request_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {44, 45}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_activation_request_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 44: - return crit_e::reject; - case 45: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_activation_request_ies_o::value_c positioning_activation_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 44: - ret.set(value_c::types::srs_type); - break; - case 45: - ret.set(value_c::types::activation_time); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_activation_request_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 44: - return presence_e::mandatory; - case 45: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_activation_request_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::srs_type: - c = srs_type_c{}; - break; - case types::activation_time: - c = fixed_bitstring<64, false, true>{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_activation_request_ies_o::value_c"); - } -} -srs_type_c& positioning_activation_request_ies_o::value_c::srs_type() -{ - assert_choice_type(types::srs_type, type_, "Value"); - return c.get(); -} -fixed_bitstring<64, false, true>& positioning_activation_request_ies_o::value_c::activation_time() -{ - assert_choice_type(types::activation_time, type_, "Value"); - return c.get>(); -} -const srs_type_c& positioning_activation_request_ies_o::value_c::srs_type() const -{ - assert_choice_type(types::srs_type, type_, "Value"); - return c.get(); -} -const fixed_bitstring<64, false, true>& positioning_activation_request_ies_o::value_c::activation_time() const -{ - assert_choice_type(types::activation_time, type_, "Value"); - return c.get>(); -} -void positioning_activation_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::srs_type: - j.write_fieldname("SRSType"); - c.get().to_json(j); - break; - case types::activation_time: - j.write_str("BIT STRING", c.get>().to_string()); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_request_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_activation_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::srs_type: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::activation_time: - HANDLE_CODE((c.get>().pack(bref))); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_request_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_activation_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::srs_type: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::activation_time: - HANDLE_CODE((c.get>().unpack(bref))); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_request_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_activation_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"SRSType", "BIT STRING"}; - return convert_enum_idx(names, 2, value, "positioning_activation_request_ies_o::value_c::types"); -} - -// PositioningActivationResponseIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_activation_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {1, 49, 50}; - return map_enum_number(names, 3, idx, "id"); -} -bool positioning_activation_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {1, 49, 50}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_activation_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 1: - return crit_e::ignore; - case 49: - return crit_e::ignore; - case 50: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_activation_resp_ies_o::value_c positioning_activation_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - case 49: - ret.set(value_c::types::sys_frame_num); - break; - case 50: - ret.set(value_c::types::slot_num); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_activation_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 1: - return presence_e::optional; - case 49: - return presence_e::optional; - case 50: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_activation_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::sys_frame_num: - c = uint16_t{}; - break; - case types::slot_num: - c = uint8_t{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_activation_resp_ies_o::value_c"); - } -} -crit_diagnostics_s& positioning_activation_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -uint16_t& positioning_activation_resp_ies_o::value_c::sys_frame_num() -{ - assert_choice_type(types::sys_frame_num, type_, "Value"); - return c.get(); -} -uint8_t& positioning_activation_resp_ies_o::value_c::slot_num() -{ - assert_choice_type(types::slot_num, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& positioning_activation_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const uint16_t& positioning_activation_resp_ies_o::value_c::sys_frame_num() const -{ - assert_choice_type(types::sys_frame_num, type_, "Value"); - return c.get(); -} -const uint8_t& positioning_activation_resp_ies_o::value_c::slot_num() const -{ - assert_choice_type(types::slot_num, type_, "Value"); - return c.get(); -} -void positioning_activation_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - case types::sys_frame_num: - j.write_int("INTEGER (0..1023)", c.get()); - break; - case types::slot_num: - j.write_int("INTEGER (0..79)", c.get()); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_activation_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sys_frame_num: - HANDLE_CODE(pack_integer(bref, c.get(), (uint16_t)0u, (uint16_t)1023u, false, true)); - break; - case types::slot_num: - HANDLE_CODE(pack_integer(bref, c.get(), (uint8_t)0u, (uint8_t)79u, false, true)); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_activation_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sys_frame_num: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint16_t)0u, (uint16_t)1023u, false, true)); - break; - case types::slot_num: - HANDLE_CODE(unpack_integer(c.get(), bref, (uint8_t)0u, (uint8_t)79u, false, true)); - break; - default: - log_invalid_choice_id(type_, "positioning_activation_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_activation_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"CriticalityDiagnostics", "INTEGER (0..1023)", "INTEGER (0..79)"}; - return convert_enum_idx(names, 3, value, "positioning_activation_resp_ies_o::value_c::types"); -} - -// PositioningInformationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_info_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool positioning_info_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_info_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_info_fail_ies_o::value_c positioning_info_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_info_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_info_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_info_fail_ies_o::value_c"); - } -} -cause_c& positioning_info_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& positioning_info_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& positioning_info_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& positioning_info_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void positioning_info_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "positioning_info_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_info_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_info_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "positioning_info_fail_ies_o::value_c::types"); -} - -// PositioningInformationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_info_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {12, 73, 90, 99}; - return map_enum_number(names, 4, idx, "id"); -} -bool positioning_info_request_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {12, 73, 90, 99}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_info_request_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 12: - return crit_e::ignore; - case 73: - return crit_e::ignore; - case 90: - return crit_e::ignore; - case 99: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_info_request_ies_o::value_c positioning_info_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 12: - ret.set(value_c::types::requested_srs_tx_characteristics); - break; - case 73: - ret.set(value_c::types::ue_report_info); - break; - case 90: - ret.set(value_c::types::ue_teg_info_request); - break; - case 99: - ret.set(value_c::types::ue_teg_report_periodicity); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_info_request_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 12: - return presence_e::optional; - case 73: - return presence_e::optional; - case 90: - return presence_e::optional; - case 99: - return presence_e::conditional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_info_request_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::requested_srs_tx_characteristics: - c = requested_srs_tx_characteristics_s{}; - break; - case types::ue_report_info: - c = ue_report_info_s{}; - break; - case types::ue_teg_info_request: - c = ue_teg_info_request_e{}; - break; - case types::ue_teg_report_periodicity: - c = ue_teg_report_periodicity_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_info_request_ies_o::value_c"); - } -} -requested_srs_tx_characteristics_s& positioning_info_request_ies_o::value_c::requested_srs_tx_characteristics() -{ - assert_choice_type(types::requested_srs_tx_characteristics, type_, "Value"); - return c.get(); -} -ue_report_info_s& positioning_info_request_ies_o::value_c::ue_report_info() -{ - assert_choice_type(types::ue_report_info, type_, "Value"); - return c.get(); -} -ue_teg_info_request_e& positioning_info_request_ies_o::value_c::ue_teg_info_request() -{ - assert_choice_type(types::ue_teg_info_request, type_, "Value"); - return c.get(); -} -ue_teg_report_periodicity_e& positioning_info_request_ies_o::value_c::ue_teg_report_periodicity() -{ - assert_choice_type(types::ue_teg_report_periodicity, type_, "Value"); - return c.get(); -} -const requested_srs_tx_characteristics_s& -positioning_info_request_ies_o::value_c::requested_srs_tx_characteristics() const -{ - assert_choice_type(types::requested_srs_tx_characteristics, type_, "Value"); - return c.get(); -} -const ue_report_info_s& positioning_info_request_ies_o::value_c::ue_report_info() const -{ - assert_choice_type(types::ue_report_info, type_, "Value"); - return c.get(); -} -const ue_teg_info_request_e& positioning_info_request_ies_o::value_c::ue_teg_info_request() const -{ - assert_choice_type(types::ue_teg_info_request, type_, "Value"); - return c.get(); -} -const ue_teg_report_periodicity_e& positioning_info_request_ies_o::value_c::ue_teg_report_periodicity() const -{ - assert_choice_type(types::ue_teg_report_periodicity, type_, "Value"); - return c.get(); -} -void positioning_info_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::requested_srs_tx_characteristics: - j.write_fieldname("RequestedSRSTransmissionCharacteristics"); - c.get().to_json(j); - break; - case types::ue_report_info: - j.write_fieldname("UEReportingInformation"); - c.get().to_json(j); - break; - case types::ue_teg_info_request: - j.write_str("UE-TEG-Info-Request", c.get().to_string()); - break; - case types::ue_teg_report_periodicity: - j.write_str("UE-TEG-ReportingPeriodicity", c.get().to_string()); - break; - default: - log_invalid_choice_id(type_, "positioning_info_request_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_info_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::requested_srs_tx_characteristics: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ue_report_info: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ue_teg_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ue_teg_report_periodicity: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_request_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::requested_srs_tx_characteristics: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ue_report_info: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ue_teg_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ue_teg_report_periodicity: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_request_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_info_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"RequestedSRSTransmissionCharacteristics", - "UEReportingInformation", - "UE-TEG-Info-Request", - "UE-TEG-ReportingPeriodicity"}; - return convert_enum_idx(names, 4, value, "positioning_info_request_ies_o::value_c::types"); -} - -// PositioningInformationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_info_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {26, 54, 1, 81}; - return map_enum_number(names, 4, idx, "id"); -} -bool positioning_info_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {26, 54, 1, 81}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_info_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 26: - return crit_e::ignore; - case 54: - return crit_e::ignore; - case 1: - return crit_e::ignore; - case 81: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_info_resp_ies_o::value_c positioning_info_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 26: - ret.set(value_c::types::srscfg); - break; - case 54: - ret.set(value_c::types::sfn_initisation_time); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - case 81: - ret.set(value_c::types::ue_tx_teg_assoc_list); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_info_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 26: - return presence_e::optional; - case 54: - return presence_e::optional; - case 1: - return presence_e::optional; - case 81: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_info_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::srscfg: - c = srscfg_s{}; - break; - case types::sfn_initisation_time: - c = fixed_bitstring<64, false, true>{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::ue_tx_teg_assoc_list: - c = ue_tx_teg_assoc_list_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_info_resp_ies_o::value_c"); - } -} -srscfg_s& positioning_info_resp_ies_o::value_c::srscfg() -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -fixed_bitstring<64, false, true>& positioning_info_resp_ies_o::value_c::sfn_initisation_time() -{ - assert_choice_type(types::sfn_initisation_time, type_, "Value"); - return c.get>(); -} -crit_diagnostics_s& positioning_info_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -ue_tx_teg_assoc_list_l& positioning_info_resp_ies_o::value_c::ue_tx_teg_assoc_list() -{ - assert_choice_type(types::ue_tx_teg_assoc_list, type_, "Value"); - return c.get(); -} -const srscfg_s& positioning_info_resp_ies_o::value_c::srscfg() const -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -const fixed_bitstring<64, false, true>& positioning_info_resp_ies_o::value_c::sfn_initisation_time() const -{ - assert_choice_type(types::sfn_initisation_time, type_, "Value"); - return c.get>(); -} -const crit_diagnostics_s& positioning_info_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const ue_tx_teg_assoc_list_l& positioning_info_resp_ies_o::value_c::ue_tx_teg_assoc_list() const -{ - assert_choice_type(types::ue_tx_teg_assoc_list, type_, "Value"); - return c.get(); -} -void positioning_info_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::srscfg: - j.write_fieldname("SRSConfiguration"); - c.get().to_json(j); - break; - case types::sfn_initisation_time: - j.write_str("BIT STRING", c.get>().to_string()); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - case types::ue_tx_teg_assoc_list: - j.start_array("UETxTEGAssociationList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "positioning_info_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_info_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::srscfg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::ue_tx_teg_assoc_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 256, true)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::srscfg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::ue_tx_teg_assoc_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 256, true)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_info_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"SRSConfiguration", "BIT STRING", "CriticalityDiagnostics", "UETxTEGAssociationList"}; - return convert_enum_idx(names, 4, value, "positioning_info_resp_ies_o::value_c::types"); -} - -// PositioningInformationUpdate-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_info_upd_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {26, 54, 81, 106}; - return map_enum_number(names, 4, idx, "id"); -} -bool positioning_info_upd_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {26, 54, 81, 106}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e positioning_info_upd_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 26: - return crit_e::ignore; - case 54: - return crit_e::ignore; - case 81: - return crit_e::ignore; - case 106: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -positioning_info_upd_ies_o::value_c positioning_info_upd_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 26: - ret.set(value_c::types::srscfg); - break; - case 54: - ret.set(value_c::types::sfn_initisation_time); - break; - case 81: - ret.set(value_c::types::ue_tx_teg_assoc_list); - break; - case 106: - ret.set(value_c::types::srs_tx_status); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_info_upd_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 26: - return presence_e::optional; - case 54: - return presence_e::optional; - case 81: - return presence_e::optional; - case 106: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void positioning_info_upd_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::srscfg: - c = srscfg_s{}; - break; - case types::sfn_initisation_time: - c = fixed_bitstring<64, false, true>{}; - break; - case types::ue_tx_teg_assoc_list: - c = ue_tx_teg_assoc_list_l{}; - break; - case types::srs_tx_status: - c = srs_tx_status_e{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "positioning_info_upd_ies_o::value_c"); - } -} -srscfg_s& positioning_info_upd_ies_o::value_c::srscfg() -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -fixed_bitstring<64, false, true>& positioning_info_upd_ies_o::value_c::sfn_initisation_time() -{ - assert_choice_type(types::sfn_initisation_time, type_, "Value"); - return c.get>(); -} -ue_tx_teg_assoc_list_l& positioning_info_upd_ies_o::value_c::ue_tx_teg_assoc_list() -{ - assert_choice_type(types::ue_tx_teg_assoc_list, type_, "Value"); - return c.get(); -} -srs_tx_status_e& positioning_info_upd_ies_o::value_c::srs_tx_status() -{ - assert_choice_type(types::srs_tx_status, type_, "Value"); - return c.get(); -} -const srscfg_s& positioning_info_upd_ies_o::value_c::srscfg() const -{ - assert_choice_type(types::srscfg, type_, "Value"); - return c.get(); -} -const fixed_bitstring<64, false, true>& positioning_info_upd_ies_o::value_c::sfn_initisation_time() const -{ - assert_choice_type(types::sfn_initisation_time, type_, "Value"); - return c.get>(); -} -const ue_tx_teg_assoc_list_l& positioning_info_upd_ies_o::value_c::ue_tx_teg_assoc_list() const -{ - assert_choice_type(types::ue_tx_teg_assoc_list, type_, "Value"); - return c.get(); -} -const srs_tx_status_e& positioning_info_upd_ies_o::value_c::srs_tx_status() const -{ - assert_choice_type(types::srs_tx_status, type_, "Value"); - return c.get(); -} -void positioning_info_upd_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::srscfg: - j.write_fieldname("SRSConfiguration"); - c.get().to_json(j); - break; - case types::sfn_initisation_time: - j.write_str("BIT STRING", c.get>().to_string()); - break; - case types::ue_tx_teg_assoc_list: - j.start_array("UETxTEGAssociationList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::srs_tx_status: - j.write_str("SRSTransmissionStatus", "stopped"); - break; - default: - log_invalid_choice_id(type_, "positioning_info_upd_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE positioning_info_upd_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::srscfg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().pack(bref))); - break; - case types::ue_tx_teg_assoc_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 256, true)); - break; - case types::srs_tx_status: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_upd_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_upd_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::srscfg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::sfn_initisation_time: - HANDLE_CODE((c.get>().unpack(bref))); - break; - case types::ue_tx_teg_assoc_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 256, true)); - break; - case types::srs_tx_status: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "positioning_info_upd_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* positioning_info_upd_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"SRSConfiguration", "BIT STRING", "UETxTEGAssociationList", "SRSTransmissionStatus"}; - return convert_enum_idx(names, 4, value, "positioning_info_upd_ies_o::value_c::types"); -} - -// PRSConfigurationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t prs_cfg_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool prs_cfg_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e prs_cfg_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -prs_cfg_fail_ies_o::value_c prs_cfg_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e prs_cfg_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void prs_cfg_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_cfg_fail_ies_o::value_c"); - } -} -cause_c& prs_cfg_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& prs_cfg_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& prs_cfg_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& prs_cfg_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void prs_cfg_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE prs_cfg_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* prs_cfg_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "prs_cfg_fail_ies_o::value_c::types"); -} - -// PRSConfigurationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t prs_cfg_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {89, 66}; - return map_enum_number(names, 2, idx, "id"); -} -bool prs_cfg_request_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {89, 66}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e prs_cfg_request_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 89: - return crit_e::reject; - case 66: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -prs_cfg_request_ies_o::value_c prs_cfg_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 89: - ret.set(value_c::types::prs_cfg_request_type); - break; - case 66: - ret.set(value_c::types::prstrp_list); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e prs_cfg_request_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 89: - return presence_e::mandatory; - case 66: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void prs_cfg_request_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::prs_cfg_request_type: - c = prs_cfg_request_type_e{}; - break; - case types::prstrp_list: - c = prstrp_list_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_cfg_request_ies_o::value_c"); - } -} -prs_cfg_request_type_e& prs_cfg_request_ies_o::value_c::prs_cfg_request_type() -{ - assert_choice_type(types::prs_cfg_request_type, type_, "Value"); - return c.get(); -} -prstrp_list_l& prs_cfg_request_ies_o::value_c::prstrp_list() -{ - assert_choice_type(types::prstrp_list, type_, "Value"); - return c.get(); -} -const prs_cfg_request_type_e& prs_cfg_request_ies_o::value_c::prs_cfg_request_type() const -{ - assert_choice_type(types::prs_cfg_request_type, type_, "Value"); - return c.get(); -} -const prstrp_list_l& prs_cfg_request_ies_o::value_c::prstrp_list() const -{ - assert_choice_type(types::prstrp_list, type_, "Value"); - return c.get(); -} -void prs_cfg_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::prs_cfg_request_type: - j.write_str("PRSConfigRequestType", c.get().to_string()); - break; - case types::prstrp_list: - j.start_array("PRSTRPList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_request_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE prs_cfg_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::prs_cfg_request_type: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prstrp_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 65535, true)); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_request_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::prs_cfg_request_type: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prstrp_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 65535, true)); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_request_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* prs_cfg_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"PRSConfigRequestType", "PRSTRPList"}; - return convert_enum_idx(names, 2, value, "prs_cfg_request_ies_o::value_c::types"); -} - -// PRSConfigurationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t prs_cfg_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {67, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool prs_cfg_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {67, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e prs_cfg_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 67: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -prs_cfg_resp_ies_o::value_c prs_cfg_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 67: - ret.set(value_c::types::prs_tx_trp_list); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e prs_cfg_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 67: - return presence_e::optional; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void prs_cfg_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::prs_tx_trp_list: - c = prs_tx_trp_list_l{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "prs_cfg_resp_ies_o::value_c"); - } -} -prs_tx_trp_list_l& prs_cfg_resp_ies_o::value_c::prs_tx_trp_list() -{ - assert_choice_type(types::prs_tx_trp_list, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& prs_cfg_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const prs_tx_trp_list_l& prs_cfg_resp_ies_o::value_c::prs_tx_trp_list() const -{ - assert_choice_type(types::prs_tx_trp_list, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& prs_cfg_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void prs_cfg_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::prs_tx_trp_list: - j.start_array("PRSTransmissionTRPList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE prs_cfg_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::prs_tx_trp_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 65535, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::prs_tx_trp_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 65535, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "prs_cfg_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* prs_cfg_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"PRSTransmissionTRPList", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "prs_cfg_resp_ies_o::value_c::types"); -} - -// TRPInformationFailure-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t trp_info_fail_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {0, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool trp_info_fail_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {0, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_info_fail_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_info_fail_ies_o::value_c trp_info_fail_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 0: - ret.set(value_c::types::cause); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_info_fail_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 0: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void trp_info_fail_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::cause: - c = cause_c{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_fail_ies_o::value_c"); - } -} -cause_c& trp_info_fail_ies_o::value_c::cause() -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& trp_info_fail_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const cause_c& trp_info_fail_ies_o::value_c::cause() const -{ - assert_choice_type(types::cause, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& trp_info_fail_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void trp_info_fail_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::cause: - j.write_fieldname("Cause"); - c.get().to_json(j); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_info_fail_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_info_fail_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_fail_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_fail_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::cause: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_fail_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_info_fail_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"Cause", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "trp_info_fail_ies_o::value_c::types"); -} - -// TRPInformationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t trp_info_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {47, 29}; - return map_enum_number(names, 2, idx, "id"); -} -bool trp_info_request_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {47, 29}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_info_request_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 47: - return crit_e::ignore; - case 29: - return crit_e::reject; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_info_request_ies_o::value_c trp_info_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 47: - ret.set(value_c::types::trp_list); - break; - case 29: - ret.set(value_c::types::trp_info_type_list_trp_req); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_info_request_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 47: - return presence_e::optional; - case 29: - return presence_e::mandatory; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void trp_info_request_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::trp_list: - c = trp_list_l{}; - break; - case types::trp_info_type_list_trp_req: - c = trp_info_type_list_trp_req_l{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_request_ies_o::value_c"); - } -} -trp_list_l& trp_info_request_ies_o::value_c::trp_list() -{ - assert_choice_type(types::trp_list, type_, "Value"); - return c.get(); -} -trp_info_type_list_trp_req_l& trp_info_request_ies_o::value_c::trp_info_type_list_trp_req() -{ - assert_choice_type(types::trp_info_type_list_trp_req, type_, "Value"); - return c.get(); -} -const trp_list_l& trp_info_request_ies_o::value_c::trp_list() const -{ - assert_choice_type(types::trp_list, type_, "Value"); - return c.get(); -} -const trp_info_type_list_trp_req_l& trp_info_request_ies_o::value_c::trp_info_type_list_trp_req() const -{ - assert_choice_type(types::trp_info_type_list_trp_req, type_, "Value"); - return c.get(); -} -void trp_info_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::trp_list: - j.start_array("TRPList"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::trp_info_type_list_trp_req: - j.start_array("TRPInformationTypeListTRPReq"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - default: - log_invalid_choice_id(type_, "trp_info_request_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_info_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::trp_list: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 65535, true)); - break; - case types::trp_info_type_list_trp_req: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 64, true)); - break; - default: - log_invalid_choice_id(type_, "trp_info_request_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::trp_list: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 65535, true)); - break; - case types::trp_info_type_list_trp_req: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 64, true)); - break; - default: - log_invalid_choice_id(type_, "trp_info_request_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_info_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"TRPList", "TRPInformationTypeListTRPReq"}; - return convert_enum_idx(names, 2, value, "trp_info_request_ies_o::value_c::types"); -} - -// TRPInformationResponse-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t trp_info_resp_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {30, 1}; - return map_enum_number(names, 2, idx, "id"); -} -bool trp_info_resp_ies_o::is_id_valid(const uint32_t& id) -{ - static const uint32_t names[] = {30, 1}; - for (const auto& o : names) { - if (o == id) { - return true; - } - } - return false; -} -crit_e trp_info_resp_ies_o::get_crit(const uint32_t& id) -{ - switch (id) { - case 30: - return crit_e::ignore; - case 1: - return crit_e::ignore; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} -trp_info_resp_ies_o::value_c trp_info_resp_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - switch (id) { - case 30: - ret.set(value_c::types::trp_info_list_trp_resp); - break; - case 1: - ret.set(value_c::types::crit_diagnostics); - break; - default: - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e trp_info_resp_ies_o::get_presence(const uint32_t& id) -{ - switch (id) { - case 30: - return presence_e::mandatory; - case 1: - return presence_e::optional; - default: - asn1::log_error("The id={} is not recognized", id); - } - return {}; -} - -// Value ::= OPEN TYPE -void trp_info_resp_ies_o::value_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::trp_info_list_trp_resp: - c = trp_info_list_trp_resp_l{}; - break; - case types::crit_diagnostics: - c = crit_diagnostics_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "trp_info_resp_ies_o::value_c"); - } -} -trp_info_list_trp_resp_l& trp_info_resp_ies_o::value_c::trp_info_list_trp_resp() -{ - assert_choice_type(types::trp_info_list_trp_resp, type_, "Value"); - return c.get(); -} -crit_diagnostics_s& trp_info_resp_ies_o::value_c::crit_diagnostics() -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -const trp_info_list_trp_resp_l& trp_info_resp_ies_o::value_c::trp_info_list_trp_resp() const -{ - assert_choice_type(types::trp_info_list_trp_resp, type_, "Value"); - return c.get(); -} -const crit_diagnostics_s& trp_info_resp_ies_o::value_c::crit_diagnostics() const -{ - assert_choice_type(types::crit_diagnostics, type_, "Value"); - return c.get(); -} -void trp_info_resp_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::trp_info_list_trp_resp: - j.start_array("TRPInformationListTRPResp"); - for (const auto& e1 : c.get()) { - e1.to_json(j); - } - j.end_array(); - break; - case types::crit_diagnostics: - j.write_fieldname("CriticalityDiagnostics"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "trp_info_resp_ies_o::value_c"); - } - j.end_obj(); -} -SRSASN_CODE trp_info_resp_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::trp_info_list_trp_resp: - HANDLE_CODE(pack_dyn_seq_of(bref, c.get(), 1, 65535, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_resp_ies_o::value_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_resp_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::trp_info_list_trp_resp: - HANDLE_CODE(unpack_dyn_seq_of(c.get(), bref, 1, 65535, true)); - break; - case types::crit_diagnostics: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "trp_info_resp_ies_o::value_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* trp_info_resp_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"TRPInformationListTRPResp", "CriticalityDiagnostics"}; - return convert_enum_idx(names, 2, value, "trp_info_resp_ies_o::value_c::types"); -} - -// MeasurementPreconfigurationRequired-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t meas_precfg_required_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {87}; - return map_enum_number(names, 1, idx, "id"); -} -bool meas_precfg_required_ies_o::is_id_valid(const uint32_t& id) -{ - return 87 == id; -} -crit_e meas_precfg_required_ies_o::get_crit(const uint32_t& id) -{ - if (id == 87) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -meas_precfg_required_ies_o::value_c meas_precfg_required_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 87) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e meas_precfg_required_ies_o::get_presence(const uint32_t& id) -{ - if (id == 87) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void meas_precfg_required_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("TRP-PRS-Information-List"); - for (const auto& e1 : c) { - e1.to_json(j); - } - j.end_array(); - j.end_obj(); -} -SRSASN_CODE meas_precfg_required_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, c, 1, 256, true)); - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_precfg_required_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(c, bref, 1, 256, true)); - return SRSASN_SUCCESS; -} - -const char* meas_precfg_required_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"TRP-PRS-Information-List"}; - return convert_enum_idx(names, 1, value, "meas_precfg_required_ies_o::value_c::types"); -} - -// OTDOAInformationRequest-IEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t otdoa_info_request_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {9}; - return map_enum_number(names, 1, idx, "id"); -} -bool otdoa_info_request_ies_o::is_id_valid(const uint32_t& id) -{ - return 9 == id; -} -crit_e otdoa_info_request_ies_o::get_crit(const uint32_t& id) -{ - if (id == 9) { - return crit_e::reject; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -otdoa_info_request_ies_o::value_c otdoa_info_request_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 9) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e otdoa_info_request_ies_o::get_presence(const uint32_t& id) -{ - if (id == 9) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void otdoa_info_request_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.start_array("OTDOA-Information-Type"); - for (const auto& e1 : c) { - e1.to_json(j); - } - j.end_array(); - j.end_obj(); -} -SRSASN_CODE otdoa_info_request_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, c, 1, 63, true)); - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_request_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(c, bref, 1, 63, true)); - return SRSASN_SUCCESS; -} - -const char* otdoa_info_request_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"OTDOA-Information-Type"}; - return convert_enum_idx(names, 1, value, "otdoa_info_request_ies_o::value_c::types"); -} - -// PositioningDeactivationIEs ::= OBJECT SET OF NRPPA-PROTOCOL-IES -uint32_t positioning_deactivation_ies_o::idx_to_id(uint32_t idx) -{ - static const uint32_t names[] = {53}; - return map_enum_number(names, 1, idx, "id"); -} -bool positioning_deactivation_ies_o::is_id_valid(const uint32_t& id) -{ - return 53 == id; -} -crit_e positioning_deactivation_ies_o::get_crit(const uint32_t& id) -{ - if (id == 53) { - return crit_e::ignore; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} -positioning_deactivation_ies_o::value_c positioning_deactivation_ies_o::get_value(const uint32_t& id) -{ - value_c ret{}; - if (id != 53) { - asn1::log_error("The id={} is not recognized", id); - } - return ret; -} -presence_e positioning_deactivation_ies_o::get_presence(const uint32_t& id) -{ - if (id == 53) { - return presence_e::mandatory; - } - asn1::log_error("The id={} is not recognized", id); - return {}; -} - -// Value ::= OPEN TYPE -void positioning_deactivation_ies_o::value_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_fieldname("AbortTransmission"); - c.to_json(j); - j.end_obj(); -} -SRSASN_CODE positioning_deactivation_ies_o::value_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(c.pack(bref)); - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_deactivation_ies_o::value_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(c.unpack(bref)); - return SRSASN_SUCCESS; -} - -const char* positioning_deactivation_ies_o::value_c::types_opts::to_string() const -{ - static const char* names[] = {"AbortTransmission"}; - return convert_enum_idx(names, 1, value, "positioning_deactivation_ies_o::value_c::types"); -} - -SRSASN_CODE private_ie_container_empty_l::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - pack_length(bref, nof_ies, 1u, 65535u, true); - - return SRSASN_SUCCESS; -} -SRSASN_CODE private_ie_container_empty_l::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 1u, 65535u, true); - if (nof_ies > 0) { - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void private_ie_container_empty_l::to_json(json_writer& j) const -{ - j.start_obj(); - j.end_obj(); -} - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -template struct asn1::protocol_ie_field_s; - -SRSASN_CODE assist_info_ctrl_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += assist_info_present ? 1 : 0; - nof_ies += broadcast_present ? 1 : 0; - nof_ies += positioning_broadcast_cells_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (assist_info_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)23, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(assist_info.pack(bref)); - } - if (broadcast_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)24, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(broadcast.pack(bref)); - } - if (positioning_broadcast_cells_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)38, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, positioning_broadcast_cells, 1, 16384, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_ctrl_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 23: { - assist_info_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(assist_info.unpack(bref)); - break; - } - case 24: { - broadcast_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(broadcast.unpack(bref)); - break; - } - case 38: { - positioning_broadcast_cells_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(positioning_broadcast_cells, bref, 1, 16384, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void assist_info_ctrl_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (assist_info_present) { - j.write_int("id", 23); - j.write_str("criticality", "reject"); - assist_info.to_json(j); - } - if (broadcast_present) { - j.write_int("id", 24); - j.write_str("criticality", "reject"); - j.write_str("Value", broadcast.to_string()); - } - if (positioning_broadcast_cells_present) { - j.write_int("id", 38); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : positioning_broadcast_cells) { - e1.to_json(j); - } - j.end_array(); - } - j.end_obj(); -} - -SRSASN_CODE assist_info_feedback_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += assist_info_fail_list_present ? 1 : 0; - nof_ies += positioning_broadcast_cells_present ? 1 : 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (assist_info_fail_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)25, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, assist_info_fail_list, 1, 32, true)); - } - if (positioning_broadcast_cells_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)38, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, positioning_broadcast_cells, 1, 16384, true)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE assist_info_feedback_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 25: { - assist_info_fail_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(assist_info_fail_list, bref, 1, 32, true)); - break; - } - case 38: { - positioning_broadcast_cells_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(positioning_broadcast_cells, bref, 1, 16384, true)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void assist_info_feedback_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (assist_info_fail_list_present) { - j.write_int("id", 25); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : assist_info_fail_list) { - e1.to_json(j); - } - j.end_array(); - } - if (positioning_broadcast_cells_present) { - j.write_int("id", 38); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : positioning_broadcast_cells) { - e1.to_json(j); - } - j.end_array(); - } - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE e_c_id_meas_fail_ind_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 3; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)2, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)6, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_fail_ind_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 3; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 2: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 6: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void e_c_id_meas_fail_ind_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 2); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_ue_meas_id); - j.write_int("id", 6); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_ue_meas_id); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - j.end_obj(); -} - -SRSASN_CODE e_c_id_meas_initiation_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)2, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_initiation_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 2: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void e_c_id_meas_initiation_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 2); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_ue_meas_id); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE e_c_id_meas_initiation_request_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 3; - nof_ies += meas_periodicity_present ? 1 : 0; - nof_ies += other_rat_meas_quantities_present ? 1 : 0; - nof_ies += wlan_meas_quantities_present ? 1 : 0; - nof_ies += meas_periodicity_nr_ao_a_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)2, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)3, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(report_characteristics.pack(bref)); - } - if (meas_periodicity_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)4, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity.pack(bref)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)5, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, meas_quantities, 1, 64, true)); - } - if (other_rat_meas_quantities_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)15, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, other_rat_meas_quantities, 0, 64, true)); - } - if (wlan_meas_quantities_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)19, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, wlan_meas_quantities, 0, 64, true)); - } - if (meas_periodicity_nr_ao_a_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)105, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity_nr_ao_a.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_initiation_request_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 3; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 2: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 3: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(report_characteristics.unpack(bref)); - break; - } - case 4: { - meas_periodicity_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity.unpack(bref)); - break; - } - case 5: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(meas_quantities, bref, 1, 64, true)); - break; - } - case 15: { - other_rat_meas_quantities_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(other_rat_meas_quantities, bref, 0, 64, true)); - break; - } - case 19: { - wlan_meas_quantities_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(wlan_meas_quantities, bref, 0, 64, true)); - break; - } - case 105: { - meas_periodicity_nr_ao_a_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity_nr_ao_a.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void e_c_id_meas_initiation_request_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 2); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_ue_meas_id); - j.write_int("id", 3); - j.write_str("criticality", "reject"); - j.write_str("Value", report_characteristics.to_string()); - if (meas_periodicity_present) { - j.write_int("id", 4); - j.write_str("criticality", "reject"); - j.write_str("Value", meas_periodicity.to_string()); - } - j.write_int("id", 5); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : meas_quantities) { - e1.to_json(j); - } - j.end_array(); - if (other_rat_meas_quantities_present) { - j.write_int("id", 15); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : other_rat_meas_quantities) { - e1.to_json(j); - } - j.end_array(); - } - if (wlan_meas_quantities_present) { - j.write_int("id", 19); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : wlan_meas_quantities) { - e1.to_json(j); - } - j.end_array(); - } - if (meas_periodicity_nr_ao_a_present) { - j.write_int("id", 105); - j.write_str("criticality", "reject"); - j.write_str("Value", meas_periodicity_nr_ao_a.to_string()); - } - j.end_obj(); -} - -SRSASN_CODE e_c_id_meas_initiation_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - nof_ies += e_c_id_meas_result_present ? 1 : 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - nof_ies += cell_portion_id_present ? 1 : 0; - nof_ies += other_rat_meas_result_present ? 1 : 0; - nof_ies += wlan_meas_result_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)2, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)6, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - if (e_c_id_meas_result_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)7, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(e_c_id_meas_result.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - if (cell_portion_id_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)14, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, cell_portion_id, (uint16_t)0u, (uint16_t)4095u, true, true)); - } - if (other_rat_meas_result_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)17, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, other_rat_meas_result, 1, 64, true)); - } - if (wlan_meas_result_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)21, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, wlan_meas_result, 1, 64, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_initiation_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 2: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 6: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 7: { - e_c_id_meas_result_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(e_c_id_meas_result.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - case 14: { - cell_portion_id_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(cell_portion_id, bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - } - case 17: { - other_rat_meas_result_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(other_rat_meas_result, bref, 1, 64, true)); - break; - } - case 21: { - wlan_meas_result_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(wlan_meas_result, bref, 1, 64, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void e_c_id_meas_initiation_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 2); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_ue_meas_id); - j.write_int("id", 6); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_ue_meas_id); - if (e_c_id_meas_result_present) { - j.write_int("id", 7); - j.write_str("criticality", "ignore"); - e_c_id_meas_result.to_json(j); - } - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - if (cell_portion_id_present) { - j.write_int("id", 14); - j.write_str("criticality", "ignore"); - j.write_int("Value", cell_portion_id); - } - if (other_rat_meas_result_present) { - j.write_int("id", 17); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : other_rat_meas_result) { - e1.to_json(j); - } - j.end_array(); - } - if (wlan_meas_result_present) { - j.write_int("id", 21); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : wlan_meas_result) { - e1.to_json(j); - } - j.end_array(); - } - j.end_obj(); -} - -SRSASN_CODE e_c_id_meas_report_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 3; - nof_ies += cell_portion_id_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)2, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)6, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)7, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(e_c_id_meas_result.pack(bref)); - } - if (cell_portion_id_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)14, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, cell_portion_id, (uint16_t)0u, (uint16_t)4095u, true, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_report_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 3; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 2: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 6: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 7: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(e_c_id_meas_result.unpack(bref)); - break; - } - case 14: { - cell_portion_id_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(cell_portion_id, bref, (uint16_t)0u, (uint16_t)4095u, true, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void e_c_id_meas_report_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 2); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_ue_meas_id); - j.write_int("id", 6); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_ue_meas_id); - j.write_int("id", 7); - j.write_str("criticality", "ignore"); - e_c_id_meas_result.to_json(j); - if (cell_portion_id_present) { - j.write_int("id", 14); - j.write_str("criticality", "ignore"); - j.write_int("Value", cell_portion_id); - } - j.end_obj(); -} - -SRSASN_CODE e_c_id_meas_termination_cmd_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)2, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)6, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_ue_meas_id, (uint8_t)1u, (uint8_t)15u, true, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE e_c_id_meas_termination_cmd_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 2: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - case 6: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_ue_meas_id, bref, (uint8_t)1u, (uint8_t)15u, true, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void e_c_id_meas_termination_cmd_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 2); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_ue_meas_id); - j.write_int("id", 6); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_ue_meas_id); - j.end_obj(); -} - -SRSASN_CODE error_ind_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += cause_present ? 1 : 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (cause_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE error_ind_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - cause_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void error_ind_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (cause_present) { - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - } - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE meas_abort_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)40, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_abort_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 40: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_abort_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 40); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_meas_id); - j.end_obj(); -} - -SRSASN_CODE meas_activation_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += prs_meass_info_list_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)98, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(request_type.pack(bref)); - } - if (prs_meass_info_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)88, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, prs_meass_info_list, 1, 4, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_activation_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 98: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(request_type.unpack(bref)); - break; - } - case 88: { - prs_meass_info_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(prs_meass_info_list, bref, 1, 4, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_activation_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 98); - j.write_str("criticality", "reject"); - j.write_str("Value", request_type.to_string()); - if (prs_meass_info_list_present) { - j.write_int("id", 88); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : prs_meass_info_list) { - e1.to_json(j); - } - j.end_array(); - } - j.end_obj(); -} - -SRSASN_CODE meas_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE meas_fail_ind_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 3; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)40, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_fail_ind_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 3; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 40: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_fail_ind_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 40); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_meas_id); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - j.end_obj(); -} - -SRSASN_CODE meas_precfg_confirm_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)97, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(precfg_result.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_precfg_confirm_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 97: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(precfg_result.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_precfg_confirm_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 97); - j.write_str("criticality", "ignore"); - j.write_str("Value", precfg_result.to_string()); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE meas_precfg_refuse_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_precfg_refuse_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_precfg_refuse_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE meas_report_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 3; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)40, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)43, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_meas_report_list, 1, 64, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_report_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 3; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 40: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 43: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_meas_report_list, bref, 1, 64, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_report_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 40); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_meas_id); - j.write_int("id", 43); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : trp_meas_report_list) { - e1.to_json(j); - } - j.end_array(); - j.end_obj(); -} - -SRSASN_CODE meas_request_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 4; - nof_ies += meas_periodicity_present ? 1 : 0; - nof_ies += sfn_initisation_time_present ? 1 : 0; - nof_ies += srscfg_present ? 1 : 0; - nof_ies += meas_beam_info_request_present ? 1 : 0; - nof_ies += sys_frame_num_present ? 1 : 0; - nof_ies += slot_num_present ? 1 : 0; - nof_ies += meas_periodicity_extended_present ? 1 : 0; - nof_ies += resp_time_present ? 1 : 0; - nof_ies += meas_characteristics_request_ind_present ? 1 : 0; - nof_ies += meas_time_occasion_present ? 1 : 0; - nof_ies += meas_amount_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)41, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_meas_request_list, 1, 64, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)3, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(report_characteristics.pack(bref)); - } - if (meas_periodicity_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)4, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity.pack(bref)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)52, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_meas_quantities, 1, 16384, true)); - } - if (sfn_initisation_time_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)54, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(sfn_initisation_time.pack(bref)); - } - if (srscfg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)26, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.pack(bref)); - } - if (meas_beam_info_request_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)31, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_beam_info_request.pack(bref)); - } - if (sys_frame_num_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)49, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, sys_frame_num, (uint16_t)0u, (uint16_t)1023u, false, true)); - } - if (slot_num_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)50, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, slot_num, (uint8_t)0u, (uint8_t)79u, false, true)); - } - if (meas_periodicity_extended_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)64, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity_extended.pack(bref)); - } - if (resp_time_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)72, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(resp_time.pack(bref)); - } - if (meas_characteristics_request_ind_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)92, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_characteristics_request_ind.pack(bref)); - } - if (meas_time_occasion_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)91, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_time_occasion.pack(bref)); - } - if (meas_amount_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)95, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_amount.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_request_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 4; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 41: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_meas_request_list, bref, 1, 64, true)); - break; - } - case 3: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(report_characteristics.unpack(bref)); - break; - } - case 4: { - meas_periodicity_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity.unpack(bref)); - break; - } - case 52: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_meas_quantities, bref, 1, 16384, true)); - break; - } - case 54: { - sfn_initisation_time_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(sfn_initisation_time.unpack(bref)); - break; - } - case 26: { - srscfg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.unpack(bref)); - break; - } - case 31: { - meas_beam_info_request_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_beam_info_request.unpack(bref)); - break; - } - case 49: { - sys_frame_num_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(sys_frame_num, bref, (uint16_t)0u, (uint16_t)1023u, false, true)); - break; - } - case 50: { - slot_num_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(slot_num, bref, (uint8_t)0u, (uint8_t)79u, false, true)); - break; - } - case 64: { - meas_periodicity_extended_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_periodicity_extended.unpack(bref)); - break; - } - case 72: { - resp_time_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(resp_time.unpack(bref)); - break; - } - case 92: { - meas_characteristics_request_ind_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_characteristics_request_ind.unpack(bref)); - break; - } - case 91: { - meas_time_occasion_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_time_occasion.unpack(bref)); - break; - } - case 95: { - meas_amount_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_amount.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_request_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 41); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : trp_meas_request_list) { - e1.to_json(j); - } - j.end_array(); - j.write_int("id", 3); - j.write_str("criticality", "reject"); - j.write_str("Value", report_characteristics.to_string()); - if (meas_periodicity_present) { - j.write_int("id", 4); - j.write_str("criticality", "reject"); - j.write_str("Value", meas_periodicity.to_string()); - } - j.write_int("id", 52); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : trp_meas_quantities) { - e1.to_json(j); - } - j.end_array(); - if (sfn_initisation_time_present) { - j.write_int("id", 54); - j.write_str("criticality", "ignore"); - j.write_str("Value", sfn_initisation_time.to_string()); - } - if (srscfg_present) { - j.write_int("id", 26); - j.write_str("criticality", "ignore"); - srscfg.to_json(j); - } - if (meas_beam_info_request_present) { - j.write_int("id", 31); - j.write_str("criticality", "ignore"); - j.write_str("Value", "true"); - } - if (sys_frame_num_present) { - j.write_int("id", 49); - j.write_str("criticality", "ignore"); - j.write_int("Value", sys_frame_num); - } - if (slot_num_present) { - j.write_int("id", 50); - j.write_str("criticality", "ignore"); - j.write_int("Value", slot_num); - } - if (meas_periodicity_extended_present) { - j.write_int("id", 64); - j.write_str("criticality", "reject"); - j.write_str("Value", meas_periodicity_extended.to_string()); - } - if (resp_time_present) { - j.write_int("id", 72); - j.write_str("criticality", "ignore"); - resp_time.to_json(j); - } - if (meas_characteristics_request_ind_present) { - j.write_int("id", 92); - j.write_str("criticality", "ignore"); - j.write_str("Value", meas_characteristics_request_ind.to_string()); - } - if (meas_time_occasion_present) { - j.write_int("id", 91); - j.write_str("criticality", "ignore"); - j.write_str("Value", meas_time_occasion.to_string()); - } - if (meas_amount_present) { - j.write_int("id", 95); - j.write_str("criticality", "ignore"); - j.write_str("Value", meas_amount.to_string()); - } - j.end_obj(); -} - -SRSASN_CODE meas_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - nof_ies += trp_meas_resp_list_present ? 1 : 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)40, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - if (trp_meas_resp_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)42, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_meas_resp_list, 1, 64, true)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 40: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 42: { - trp_meas_resp_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_meas_resp_list, bref, 1, 64, true)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 40); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_meas_id); - if (trp_meas_resp_list_present) { - j.write_int("id", 42); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : trp_meas_resp_list) { - e1.to_json(j); - } - j.end_array(); - } - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE meas_upd_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - nof_ies += srscfg_present ? 1 : 0; - nof_ies += trp_meas_upd_list_present ? 1 : 0; - nof_ies += meas_characteristics_request_ind_present ? 1 : 0; - nof_ies += meas_time_occasion_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)39, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, lmf_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)40, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, ran_meas_id, (uint32_t)1u, (uint32_t)65536u, true, true)); - } - if (srscfg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)26, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.pack(bref)); - } - if (trp_meas_upd_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)70, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_meas_upd_list, 1, 64, true)); - } - if (meas_characteristics_request_ind_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)92, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_characteristics_request_ind.pack(bref)); - } - if (meas_time_occasion_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)91, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_time_occasion.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE meas_upd_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 39: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(lmf_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 40: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(ran_meas_id, bref, (uint32_t)1u, (uint32_t)65536u, true, true)); - break; - } - case 26: { - srscfg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.unpack(bref)); - break; - } - case 70: { - trp_meas_upd_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_meas_upd_list, bref, 1, 64, true)); - break; - } - case 92: { - meas_characteristics_request_ind_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_characteristics_request_ind.unpack(bref)); - break; - } - case 91: { - meas_time_occasion_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(meas_time_occasion.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void meas_upd_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 39); - j.write_str("criticality", "reject"); - j.write_int("Value", lmf_meas_id); - j.write_int("id", 40); - j.write_str("criticality", "reject"); - j.write_int("Value", ran_meas_id); - if (srscfg_present) { - j.write_int("id", 26); - j.write_str("criticality", "ignore"); - srscfg.to_json(j); - } - if (trp_meas_upd_list_present) { - j.write_int("id", 70); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : trp_meas_upd_list) { - e1.to_json(j); - } - j.end_array(); - } - if (meas_characteristics_request_ind_present) { - j.write_int("id", 92); - j.write_str("criticality", "ignore"); - j.write_str("Value", meas_characteristics_request_ind.to_string()); - } - if (meas_time_occasion_present) { - j.write_int("id", 91); - j.write_str("criticality", "ignore"); - j.write_str("Value", meas_time_occasion.to_string()); - } - j.end_obj(); -} - -SRSASN_CODE otdoa_info_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void otdoa_info_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE otdoa_info_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)8, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, otdoa_cells, 1, 3840, true)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE otdoa_info_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 8: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(otdoa_cells, bref, 1, 3840, true)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void otdoa_info_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 8); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : otdoa_cells) { - e1.to_json(j); - } - j.end_array(); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE positioning_activation_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_activation_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void positioning_activation_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE positioning_activation_request_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += activation_time_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)44, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_type.pack(bref)); - } - if (activation_time_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)45, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(activation_time.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_activation_request_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 44: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_type.unpack(bref)); - break; - } - case 45: { - activation_time_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(activation_time.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void positioning_activation_request_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 44); - j.write_str("criticality", "reject"); - srs_type.to_json(j); - if (activation_time_present) { - j.write_int("id", 45); - j.write_str("criticality", "ignore"); - j.write_str("Value", activation_time.to_string()); - } - j.end_obj(); -} - -SRSASN_CODE positioning_activation_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - nof_ies += sys_frame_num_present ? 1 : 0; - nof_ies += slot_num_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - if (sys_frame_num_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)49, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, sys_frame_num, (uint16_t)0u, (uint16_t)1023u, false, true)); - } - if (slot_num_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)50, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_integer(bref, slot_num, (uint8_t)0u, (uint8_t)79u, false, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_activation_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - case 49: { - sys_frame_num_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(sys_frame_num, bref, (uint16_t)0u, (uint16_t)1023u, false, true)); - break; - } - case 50: { - slot_num_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_integer(slot_num, bref, (uint8_t)0u, (uint8_t)79u, false, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void positioning_activation_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - if (sys_frame_num_present) { - j.write_int("id", 49); - j.write_str("criticality", "ignore"); - j.write_int("Value", sys_frame_num); - } - if (slot_num_present) { - j.write_int("id", 50); - j.write_str("criticality", "ignore"); - j.write_int("Value", slot_num); - } - j.end_obj(); -} - -SRSASN_CODE positioning_info_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void positioning_info_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE positioning_info_request_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += requested_srs_tx_characteristics_present ? 1 : 0; - nof_ies += ue_report_info_present ? 1 : 0; - nof_ies += ue_teg_info_request_present ? 1 : 0; - nof_ies += ue_teg_report_periodicity_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (requested_srs_tx_characteristics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)12, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(requested_srs_tx_characteristics.pack(bref)); - } - if (ue_report_info_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)73, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(ue_report_info.pack(bref)); - } - if (ue_teg_info_request_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)90, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(ue_teg_info_request.pack(bref)); - } - if (ue_teg_report_periodicity_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)99, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(ue_teg_report_periodicity.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_request_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 12: { - requested_srs_tx_characteristics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(requested_srs_tx_characteristics.unpack(bref)); - break; - } - case 73: { - ue_report_info_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(ue_report_info.unpack(bref)); - break; - } - case 90: { - ue_teg_info_request_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(ue_teg_info_request.unpack(bref)); - break; - } - case 99: { - ue_teg_report_periodicity_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(ue_teg_report_periodicity.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void positioning_info_request_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (requested_srs_tx_characteristics_present) { - j.write_int("id", 12); - j.write_str("criticality", "ignore"); - requested_srs_tx_characteristics.to_json(j); - } - if (ue_report_info_present) { - j.write_int("id", 73); - j.write_str("criticality", "ignore"); - ue_report_info.to_json(j); - } - if (ue_teg_info_request_present) { - j.write_int("id", 90); - j.write_str("criticality", "ignore"); - j.write_str("Value", ue_teg_info_request.to_string()); - } - if (ue_teg_report_periodicity_present) { - j.write_int("id", 99); - j.write_str("criticality", "reject"); - j.write_str("Value", ue_teg_report_periodicity.to_string()); - } - j.end_obj(); -} - -SRSASN_CODE positioning_info_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += srscfg_present ? 1 : 0; - nof_ies += sfn_initisation_time_present ? 1 : 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - nof_ies += ue_tx_teg_assoc_list_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (srscfg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)26, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.pack(bref)); - } - if (sfn_initisation_time_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)54, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(sfn_initisation_time.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - if (ue_tx_teg_assoc_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)81, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, ue_tx_teg_assoc_list, 1, 256, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 26: { - srscfg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.unpack(bref)); - break; - } - case 54: { - sfn_initisation_time_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(sfn_initisation_time.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - case 81: { - ue_tx_teg_assoc_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(ue_tx_teg_assoc_list, bref, 1, 256, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void positioning_info_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (srscfg_present) { - j.write_int("id", 26); - j.write_str("criticality", "ignore"); - srscfg.to_json(j); - } - if (sfn_initisation_time_present) { - j.write_int("id", 54); - j.write_str("criticality", "ignore"); - j.write_str("Value", sfn_initisation_time.to_string()); - } - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - if (ue_tx_teg_assoc_list_present) { - j.write_int("id", 81); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : ue_tx_teg_assoc_list) { - e1.to_json(j); - } - j.end_array(); - } - j.end_obj(); -} - -SRSASN_CODE positioning_info_upd_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += srscfg_present ? 1 : 0; - nof_ies += sfn_initisation_time_present ? 1 : 0; - nof_ies += ue_tx_teg_assoc_list_present ? 1 : 0; - nof_ies += srs_tx_status_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (srscfg_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)26, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.pack(bref)); - } - if (sfn_initisation_time_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)54, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(sfn_initisation_time.pack(bref)); - } - if (ue_tx_teg_assoc_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)81, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, ue_tx_teg_assoc_list, 1, 256, true)); - } - if (srs_tx_status_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)106, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_tx_status.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE positioning_info_upd_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 26: { - srscfg_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srscfg.unpack(bref)); - break; - } - case 54: { - sfn_initisation_time_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(sfn_initisation_time.unpack(bref)); - break; - } - case 81: { - ue_tx_teg_assoc_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(ue_tx_teg_assoc_list, bref, 1, 256, true)); - break; - } - case 106: { - srs_tx_status_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(srs_tx_status.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void positioning_info_upd_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (srscfg_present) { - j.write_int("id", 26); - j.write_str("criticality", "ignore"); - srscfg.to_json(j); - } - if (sfn_initisation_time_present) { - j.write_int("id", 54); - j.write_str("criticality", "ignore"); - j.write_str("Value", sfn_initisation_time.to_string()); - } - if (ue_tx_teg_assoc_list_present) { - j.write_int("id", 81); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : ue_tx_teg_assoc_list) { - e1.to_json(j); - } - j.end_array(); - } - if (srs_tx_status_present) { - j.write_int("id", 106); - j.write_str("criticality", "ignore"); - j.write_str("Value", "stopped"); - } - j.end_obj(); -} - -SRSASN_CODE prs_cfg_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void prs_cfg_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE prs_cfg_request_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 2; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)89, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(prs_cfg_request_type.pack(bref)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)66, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, prstrp_list, 1, 65535, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_request_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 2; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 89: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(prs_cfg_request_type.unpack(bref)); - break; - } - case 66: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(prstrp_list, bref, 1, 65535, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void prs_cfg_request_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 89); - j.write_str("criticality", "reject"); - j.write_str("Value", prs_cfg_request_type.to_string()); - j.write_int("id", 66); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : prstrp_list) { - e1.to_json(j); - } - j.end_array(); - j.end_obj(); -} - -SRSASN_CODE prs_cfg_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 0; - nof_ies += prs_tx_trp_list_present ? 1 : 0; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (prs_tx_trp_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)67, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, prs_tx_trp_list, 1, 65535, true)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE prs_cfg_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 67: { - prs_tx_trp_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(prs_tx_trp_list, bref, 1, 65535, true)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - - return SRSASN_SUCCESS; -} -void prs_cfg_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (prs_tx_trp_list_present) { - j.write_int("id", 67); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : prs_tx_trp_list) { - e1.to_json(j); - } - j.end_array(); - } - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE trp_info_fail_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)0, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.pack(bref)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_fail_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 0: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(cause.unpack(bref)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void trp_info_fail_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 0); - j.write_str("criticality", "ignore"); - cause.to_json(j); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -SRSASN_CODE trp_info_request_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += trp_list_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - if (trp_list_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)47, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_list, 1, 65535, true)); - } - { - HANDLE_CODE(pack_integer(bref, (uint32_t)29, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::reject}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_info_type_list_trp_req, 1, 64, true)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_request_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 47: { - trp_list_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_list, bref, 1, 65535, true)); - break; - } - case 29: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_info_type_list_trp_req, bref, 1, 64, true)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void trp_info_request_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - if (trp_list_present) { - j.write_int("id", 47); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : trp_list) { - e1.to_json(j); - } - j.end_array(); - } - j.write_int("id", 29); - j.write_str("criticality", "reject"); - j.start_array("Value"); - for (const auto& e1 : trp_info_type_list_trp_req) { - e1.to_json(j); - } - j.end_array(); - j.end_obj(); -} - -SRSASN_CODE trp_info_resp_ies_container::pack(bit_ref& bref) const -{ - uint32_t nof_ies = 1; - nof_ies += crit_diagnostics_present ? 1 : 0; - pack_length(bref, nof_ies, 0u, 65535u, true); - - { - HANDLE_CODE(pack_integer(bref, (uint32_t)30, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(pack_dyn_seq_of(bref, trp_info_list_trp_resp, 1, 65535, true)); - } - if (crit_diagnostics_present) { - HANDLE_CODE(pack_integer(bref, (uint32_t)1, (uint32_t)0u, (uint32_t)65535u, false, true)); - HANDLE_CODE(crit_e{crit_e::ignore}.pack(bref)); - varlength_field_pack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE trp_info_resp_ies_container::unpack(cbit_ref& bref) -{ - uint32_t nof_ies = 0; - unpack_length(nof_ies, bref, 0u, 65535u, true); - - uint32_t nof_mandatory_ies = 1; - - for (; nof_ies > 0; --nof_ies) { - uint32_t id; - HANDLE_CODE(unpack_integer(id, bref, (uint32_t)0u, (uint32_t)65535u, false, true)); - crit_e crit; - HANDLE_CODE(crit.unpack(bref)); - - switch (id) { - case 30: { - nof_mandatory_ies--; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(unpack_dyn_seq_of(trp_info_list_trp_resp, bref, 1, 65535, true)); - break; - } - case 1: { - crit_diagnostics_present = true; - varlength_field_unpack_guard varlen_scope(bref, true); - HANDLE_CODE(crit_diagnostics.unpack(bref)); - break; - } - default: - asn1::log_error("Unpacked object ID={} is not recognized\n", id); - return SRSASN_ERROR_DECODE_FAIL; - } - } - if (nof_mandatory_ies > 0) { - asn1::log_error("Mandatory fields are missing\n"); - - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} -void trp_info_resp_ies_container::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("id", 30); - j.write_str("criticality", "ignore"); - j.start_array("Value"); - for (const auto& e1 : trp_info_list_trp_resp) { - e1.to_json(j); - } - j.end_array(); - if (crit_diagnostics_present) { - j.write_int("id", 1); - j.write_str("criticality", "ignore"); - crit_diagnostics.to_json(j); - } - j.end_obj(); -} - -// PrivateMessage ::= SEQUENCE -SRSASN_CODE private_msg_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(private_ies.pack(bref)); - - bref.align_bytes_zero(); - - return SRSASN_SUCCESS; -} -SRSASN_CODE private_msg_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(private_ies.unpack(bref)); - - bref.align_bytes(); - - return SRSASN_SUCCESS; -} -void private_msg_s::to_json(json_writer& j) const -{ - j.start_array(); - j.start_obj(); - j.start_obj("PrivateMessage"); - j.write_fieldname("privateIEs"); - private_ies.to_json(j); - j.end_obj(); - j.end_obj(); - j.end_array(); -} - -// NRPPA-ELEMENTARY-PROCEDURES ::= OBJECT SET OF NRPPA-ELEMENTARY-PROCEDURE -uint16_t nr_ppa_elem_procs_o::idx_to_proc_code(uint32_t idx) -{ - static const uint16_t names[] = {2, 6, 9, 11, 16, 17, 19, 20, 3, 4, 5, 0, 1, 7, 8, 10, 12, 13, 14, 15, 18, 21}; - return map_enum_number(names, 22, idx, "proc_code"); -} -bool nr_ppa_elem_procs_o::is_proc_code_valid(const uint16_t& proc_code) -{ - static const uint16_t names[] = {2, 6, 9, 11, 16, 17, 19, 20, 3, 4, 5, 0, 1, 7, 8, 10, 12, 13, 14, 15, 18, 21}; - for (const auto& o : names) { - if (o == proc_code) { - return true; - } - } - return false; -} -nr_ppa_elem_procs_o::init_msg_c nr_ppa_elem_procs_o::get_init_msg(const uint16_t& proc_code) -{ - init_msg_c ret{}; - switch (proc_code) { - case 2: - ret.set(init_msg_c::types::e_c_id_meas_initiation_request); - break; - case 6: - ret.set(init_msg_c::types::otdoa_info_request); - break; - case 9: - ret.set(init_msg_c::types::positioning_info_request); - break; - case 11: - ret.set(init_msg_c::types::meas_request); - break; - case 16: - ret.set(init_msg_c::types::trp_info_request); - break; - case 17: - ret.set(init_msg_c::types::positioning_activation_request); - break; - case 19: - ret.set(init_msg_c::types::prs_cfg_request); - break; - case 20: - ret.set(init_msg_c::types::meas_precfg_required); - break; - case 3: - ret.set(init_msg_c::types::e_c_id_meas_fail_ind); - break; - case 4: - ret.set(init_msg_c::types::e_c_id_meas_report); - break; - case 5: - ret.set(init_msg_c::types::e_c_id_meas_termination_cmd); - break; - case 0: - ret.set(init_msg_c::types::error_ind); - break; - case 1: - ret.set(init_msg_c::types::private_msg); - break; - case 7: - ret.set(init_msg_c::types::assist_info_ctrl); - break; - case 8: - ret.set(init_msg_c::types::assist_info_feedback); - break; - case 10: - ret.set(init_msg_c::types::positioning_info_upd); - break; - case 12: - ret.set(init_msg_c::types::meas_report); - break; - case 13: - ret.set(init_msg_c::types::meas_upd); - break; - case 14: - ret.set(init_msg_c::types::meas_abort); - break; - case 15: - ret.set(init_msg_c::types::meas_fail_ind); - break; - case 18: - ret.set(init_msg_c::types::positioning_deactivation); - break; - case 21: - ret.set(init_msg_c::types::meas_activation); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -nr_ppa_elem_procs_o::successful_outcome_c nr_ppa_elem_procs_o::get_successful_outcome(const uint16_t& proc_code) -{ - successful_outcome_c ret{}; - switch (proc_code) { - case 2: - ret.set(successful_outcome_c::types::e_c_id_meas_initiation_resp); - break; - case 6: - ret.set(successful_outcome_c::types::otdoa_info_resp); - break; - case 9: - ret.set(successful_outcome_c::types::positioning_info_resp); - break; - case 11: - ret.set(successful_outcome_c::types::meas_resp); - break; - case 16: - ret.set(successful_outcome_c::types::trp_info_resp); - break; - case 17: - ret.set(successful_outcome_c::types::positioning_activation_resp); - break; - case 19: - ret.set(successful_outcome_c::types::prs_cfg_resp); - break; - case 20: - ret.set(successful_outcome_c::types::meas_precfg_confirm); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -nr_ppa_elem_procs_o::unsuccessful_outcome_c nr_ppa_elem_procs_o::get_unsuccessful_outcome(const uint16_t& proc_code) -{ - unsuccessful_outcome_c ret{}; - switch (proc_code) { - case 2: - ret.set(unsuccessful_outcome_c::types::e_c_id_meas_initiation_fail); - break; - case 6: - ret.set(unsuccessful_outcome_c::types::otdoa_info_fail); - break; - case 9: - ret.set(unsuccessful_outcome_c::types::positioning_info_fail); - break; - case 11: - ret.set(unsuccessful_outcome_c::types::meas_fail); - break; - case 16: - ret.set(unsuccessful_outcome_c::types::trp_info_fail); - break; - case 17: - ret.set(unsuccessful_outcome_c::types::positioning_activation_fail); - break; - case 19: - ret.set(unsuccessful_outcome_c::types::prs_cfg_fail); - break; - case 20: - ret.set(unsuccessful_outcome_c::types::meas_precfg_refuse); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -crit_e nr_ppa_elem_procs_o::get_crit(const uint16_t& proc_code) -{ - switch (proc_code) { - case 2: - return crit_e::reject; - case 6: - return crit_e::reject; - case 9: - return crit_e::reject; - case 11: - return crit_e::reject; - case 16: - return crit_e::reject; - case 17: - return crit_e::reject; - case 19: - return crit_e::reject; - case 20: - return crit_e::reject; - case 3: - return crit_e::ignore; - case 4: - return crit_e::ignore; - case 5: - return crit_e::reject; - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - case 7: - return crit_e::reject; - case 8: - return crit_e::reject; - case 10: - return crit_e::ignore; - case 12: - return crit_e::ignore; - case 13: - return crit_e::ignore; - case 14: - return crit_e::ignore; - case 15: - return crit_e::ignore; - case 18: - return crit_e::ignore; - case 21: - return crit_e::ignore; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return {}; -} - -// InitiatingMessage ::= OPEN TYPE -void nr_ppa_elem_procs_o::init_msg_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_initiation_request: - c = e_c_id_meas_initiation_request_s{}; - break; - case types::otdoa_info_request: - c = otdoa_info_request_s{}; - break; - case types::positioning_info_request: - c = positioning_info_request_s{}; - break; - case types::meas_request: - c = meas_request_s{}; - break; - case types::trp_info_request: - c = trp_info_request_s{}; - break; - case types::positioning_activation_request: - c = positioning_activation_request_s{}; - break; - case types::prs_cfg_request: - c = prs_cfg_request_s{}; - break; - case types::meas_precfg_required: - c = meas_precfg_required_s{}; - break; - case types::e_c_id_meas_fail_ind: - c = e_c_id_meas_fail_ind_s{}; - break; - case types::e_c_id_meas_report: - c = e_c_id_meas_report_s{}; - break; - case types::e_c_id_meas_termination_cmd: - c = e_c_id_meas_termination_cmd_s{}; - break; - case types::error_ind: - c = error_ind_s{}; - break; - case types::private_msg: - c = private_msg_s{}; - break; - case types::assist_info_ctrl: - c = assist_info_ctrl_s{}; - break; - case types::assist_info_feedback: - c = assist_info_feedback_s{}; - break; - case types::positioning_info_upd: - c = positioning_info_upd_s{}; - break; - case types::meas_report: - c = meas_report_s{}; - break; - case types::meas_upd: - c = meas_upd_s{}; - break; - case types::meas_abort: - c = meas_abort_s{}; - break; - case types::meas_fail_ind: - c = meas_fail_ind_s{}; - break; - case types::positioning_deactivation: - c = positioning_deactivation_s{}; - break; - case types::meas_activation: - c = meas_activation_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::init_msg_c"); - } -} -e_c_id_meas_initiation_request_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_initiation_request() -{ - assert_choice_type(types::e_c_id_meas_initiation_request, type_, "InitiatingMessage"); - return c.get(); -} -otdoa_info_request_s& nr_ppa_elem_procs_o::init_msg_c::otdoa_info_request() -{ - assert_choice_type(types::otdoa_info_request, type_, "InitiatingMessage"); - return c.get(); -} -positioning_info_request_s& nr_ppa_elem_procs_o::init_msg_c::positioning_info_request() -{ - assert_choice_type(types::positioning_info_request, type_, "InitiatingMessage"); - return c.get(); -} -meas_request_s& nr_ppa_elem_procs_o::init_msg_c::meas_request() -{ - assert_choice_type(types::meas_request, type_, "InitiatingMessage"); - return c.get(); -} -trp_info_request_s& nr_ppa_elem_procs_o::init_msg_c::trp_info_request() -{ - assert_choice_type(types::trp_info_request, type_, "InitiatingMessage"); - return c.get(); -} -positioning_activation_request_s& nr_ppa_elem_procs_o::init_msg_c::positioning_activation_request() -{ - assert_choice_type(types::positioning_activation_request, type_, "InitiatingMessage"); - return c.get(); -} -prs_cfg_request_s& nr_ppa_elem_procs_o::init_msg_c::prs_cfg_request() -{ - assert_choice_type(types::prs_cfg_request, type_, "InitiatingMessage"); - return c.get(); -} -meas_precfg_required_s& nr_ppa_elem_procs_o::init_msg_c::meas_precfg_required() -{ - assert_choice_type(types::meas_precfg_required, type_, "InitiatingMessage"); - return c.get(); -} -e_c_id_meas_fail_ind_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_fail_ind() -{ - assert_choice_type(types::e_c_id_meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -e_c_id_meas_report_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_report() -{ - assert_choice_type(types::e_c_id_meas_report, type_, "InitiatingMessage"); - return c.get(); -} -e_c_id_meas_termination_cmd_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_termination_cmd() -{ - assert_choice_type(types::e_c_id_meas_termination_cmd, type_, "InitiatingMessage"); - return c.get(); -} -error_ind_s& nr_ppa_elem_procs_o::init_msg_c::error_ind() -{ - assert_choice_type(types::error_ind, type_, "InitiatingMessage"); - return c.get(); -} -private_msg_s& nr_ppa_elem_procs_o::init_msg_c::private_msg() -{ - assert_choice_type(types::private_msg, type_, "InitiatingMessage"); - return c.get(); -} -assist_info_ctrl_s& nr_ppa_elem_procs_o::init_msg_c::assist_info_ctrl() -{ - assert_choice_type(types::assist_info_ctrl, type_, "InitiatingMessage"); - return c.get(); -} -assist_info_feedback_s& nr_ppa_elem_procs_o::init_msg_c::assist_info_feedback() -{ - assert_choice_type(types::assist_info_feedback, type_, "InitiatingMessage"); - return c.get(); -} -positioning_info_upd_s& nr_ppa_elem_procs_o::init_msg_c::positioning_info_upd() -{ - assert_choice_type(types::positioning_info_upd, type_, "InitiatingMessage"); - return c.get(); -} -meas_report_s& nr_ppa_elem_procs_o::init_msg_c::meas_report() -{ - assert_choice_type(types::meas_report, type_, "InitiatingMessage"); - return c.get(); -} -meas_upd_s& nr_ppa_elem_procs_o::init_msg_c::meas_upd() -{ - assert_choice_type(types::meas_upd, type_, "InitiatingMessage"); - return c.get(); -} -meas_abort_s& nr_ppa_elem_procs_o::init_msg_c::meas_abort() -{ - assert_choice_type(types::meas_abort, type_, "InitiatingMessage"); - return c.get(); -} -meas_fail_ind_s& nr_ppa_elem_procs_o::init_msg_c::meas_fail_ind() -{ - assert_choice_type(types::meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -positioning_deactivation_s& nr_ppa_elem_procs_o::init_msg_c::positioning_deactivation() -{ - assert_choice_type(types::positioning_deactivation, type_, "InitiatingMessage"); - return c.get(); -} -meas_activation_s& nr_ppa_elem_procs_o::init_msg_c::meas_activation() -{ - assert_choice_type(types::meas_activation, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_initiation_request_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_initiation_request() const -{ - assert_choice_type(types::e_c_id_meas_initiation_request, type_, "InitiatingMessage"); - return c.get(); -} -const otdoa_info_request_s& nr_ppa_elem_procs_o::init_msg_c::otdoa_info_request() const -{ - assert_choice_type(types::otdoa_info_request, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_info_request_s& nr_ppa_elem_procs_o::init_msg_c::positioning_info_request() const -{ - assert_choice_type(types::positioning_info_request, type_, "InitiatingMessage"); - return c.get(); -} -const meas_request_s& nr_ppa_elem_procs_o::init_msg_c::meas_request() const -{ - assert_choice_type(types::meas_request, type_, "InitiatingMessage"); - return c.get(); -} -const trp_info_request_s& nr_ppa_elem_procs_o::init_msg_c::trp_info_request() const -{ - assert_choice_type(types::trp_info_request, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_activation_request_s& nr_ppa_elem_procs_o::init_msg_c::positioning_activation_request() const -{ - assert_choice_type(types::positioning_activation_request, type_, "InitiatingMessage"); - return c.get(); -} -const prs_cfg_request_s& nr_ppa_elem_procs_o::init_msg_c::prs_cfg_request() const -{ - assert_choice_type(types::prs_cfg_request, type_, "InitiatingMessage"); - return c.get(); -} -const meas_precfg_required_s& nr_ppa_elem_procs_o::init_msg_c::meas_precfg_required() const -{ - assert_choice_type(types::meas_precfg_required, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_fail_ind_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_fail_ind() const -{ - assert_choice_type(types::e_c_id_meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_report_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_report() const -{ - assert_choice_type(types::e_c_id_meas_report, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_termination_cmd_s& nr_ppa_elem_procs_o::init_msg_c::e_c_id_meas_termination_cmd() const -{ - assert_choice_type(types::e_c_id_meas_termination_cmd, type_, "InitiatingMessage"); - return c.get(); -} -const error_ind_s& nr_ppa_elem_procs_o::init_msg_c::error_ind() const -{ - assert_choice_type(types::error_ind, type_, "InitiatingMessage"); - return c.get(); -} -const private_msg_s& nr_ppa_elem_procs_o::init_msg_c::private_msg() const -{ - assert_choice_type(types::private_msg, type_, "InitiatingMessage"); - return c.get(); -} -const assist_info_ctrl_s& nr_ppa_elem_procs_o::init_msg_c::assist_info_ctrl() const -{ - assert_choice_type(types::assist_info_ctrl, type_, "InitiatingMessage"); - return c.get(); -} -const assist_info_feedback_s& nr_ppa_elem_procs_o::init_msg_c::assist_info_feedback() const -{ - assert_choice_type(types::assist_info_feedback, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_info_upd_s& nr_ppa_elem_procs_o::init_msg_c::positioning_info_upd() const -{ - assert_choice_type(types::positioning_info_upd, type_, "InitiatingMessage"); - return c.get(); -} -const meas_report_s& nr_ppa_elem_procs_o::init_msg_c::meas_report() const -{ - assert_choice_type(types::meas_report, type_, "InitiatingMessage"); - return c.get(); -} -const meas_upd_s& nr_ppa_elem_procs_o::init_msg_c::meas_upd() const -{ - assert_choice_type(types::meas_upd, type_, "InitiatingMessage"); - return c.get(); -} -const meas_abort_s& nr_ppa_elem_procs_o::init_msg_c::meas_abort() const -{ - assert_choice_type(types::meas_abort, type_, "InitiatingMessage"); - return c.get(); -} -const meas_fail_ind_s& nr_ppa_elem_procs_o::init_msg_c::meas_fail_ind() const -{ - assert_choice_type(types::meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_deactivation_s& nr_ppa_elem_procs_o::init_msg_c::positioning_deactivation() const -{ - assert_choice_type(types::positioning_deactivation, type_, "InitiatingMessage"); - return c.get(); -} -const meas_activation_s& nr_ppa_elem_procs_o::init_msg_c::meas_activation() const -{ - assert_choice_type(types::meas_activation, type_, "InitiatingMessage"); - return c.get(); -} -void nr_ppa_elem_procs_o::init_msg_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_initiation_request: - j.write_fieldname("E-CIDMeasurementInitiationRequest"); - c.get().to_json(j); - break; - case types::otdoa_info_request: - j.write_fieldname("OTDOAInformationRequest"); - c.get().to_json(j); - break; - case types::positioning_info_request: - j.write_fieldname("PositioningInformationRequest"); - c.get().to_json(j); - break; - case types::meas_request: - j.write_fieldname("MeasurementRequest"); - c.get().to_json(j); - break; - case types::trp_info_request: - j.write_fieldname("TRPInformationRequest"); - c.get().to_json(j); - break; - case types::positioning_activation_request: - j.write_fieldname("PositioningActivationRequest"); - c.get().to_json(j); - break; - case types::prs_cfg_request: - j.write_fieldname("PRSConfigurationRequest"); - c.get().to_json(j); - break; - case types::meas_precfg_required: - j.write_fieldname("MeasurementPreconfigurationRequired"); - c.get().to_json(j); - break; - case types::e_c_id_meas_fail_ind: - j.write_fieldname("E-CIDMeasurementFailureIndication"); - c.get().to_json(j); - break; - case types::e_c_id_meas_report: - j.write_fieldname("E-CIDMeasurementReport"); - c.get().to_json(j); - break; - case types::e_c_id_meas_termination_cmd: - j.write_fieldname("E-CIDMeasurementTerminationCommand"); - c.get().to_json(j); - break; - case types::error_ind: - j.write_fieldname("ErrorIndication"); - c.get().to_json(j); - break; - case types::private_msg: - j.write_fieldname("PrivateMessage"); - c.get().to_json(j); - break; - case types::assist_info_ctrl: - j.write_fieldname("AssistanceInformationControl"); - c.get().to_json(j); - break; - case types::assist_info_feedback: - j.write_fieldname("AssistanceInformationFeedback"); - c.get().to_json(j); - break; - case types::positioning_info_upd: - j.write_fieldname("PositioningInformationUpdate"); - c.get().to_json(j); - break; - case types::meas_report: - j.write_fieldname("MeasurementReport"); - c.get().to_json(j); - break; - case types::meas_upd: - j.write_fieldname("MeasurementUpdate"); - c.get().to_json(j); - break; - case types::meas_abort: - j.write_fieldname("MeasurementAbort"); - c.get().to_json(j); - break; - case types::meas_fail_ind: - j.write_fieldname("MeasurementFailureIndication"); - c.get().to_json(j); - break; - case types::positioning_deactivation: - j.write_fieldname("PositioningDeactivation"); - c.get().to_json(j); - break; - case types::meas_activation: - j.write_fieldname("MeasurementActivation"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::init_msg_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_o::init_msg_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::otdoa_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_activation_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_precfg_required: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::e_c_id_meas_fail_ind: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::e_c_id_meas_report: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::e_c_id_meas_termination_cmd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::error_ind: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::private_msg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::assist_info_ctrl: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::assist_info_feedback: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_upd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_report: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_upd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_abort: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_fail_ind: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_deactivation: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_activation: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::init_msg_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_o::init_msg_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::otdoa_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_activation_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_precfg_required: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::e_c_id_meas_fail_ind: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::e_c_id_meas_report: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::e_c_id_meas_termination_cmd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::error_ind: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::private_msg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::assist_info_ctrl: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::assist_info_feedback: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_upd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_report: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_upd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_abort: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_fail_ind: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_deactivation: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_activation: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::init_msg_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_o::init_msg_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementInitiationRequest", - "OTDOAInformationRequest", - "PositioningInformationRequest", - "MeasurementRequest", - "TRPInformationRequest", - "PositioningActivationRequest", - "PRSConfigurationRequest", - "MeasurementPreconfigurationRequired", - "E-CIDMeasurementFailureIndication", - "E-CIDMeasurementReport", - "E-CIDMeasurementTerminationCommand", - "ErrorIndication", - "PrivateMessage", - "AssistanceInformationControl", - "AssistanceInformationFeedback", - "PositioningInformationUpdate", - "MeasurementReport", - "MeasurementUpdate", - "MeasurementAbort", - "MeasurementFailureIndication", - "PositioningDeactivation", - "MeasurementActivation"}; - return convert_enum_idx(names, 22, value, "nr_ppa_elem_procs_o::init_msg_c::types"); -} - -// SuccessfulOutcome ::= OPEN TYPE -void nr_ppa_elem_procs_o::successful_outcome_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_initiation_resp: - c = e_c_id_meas_initiation_resp_s{}; - break; - case types::otdoa_info_resp: - c = otdoa_info_resp_s{}; - break; - case types::positioning_info_resp: - c = positioning_info_resp_s{}; - break; - case types::meas_resp: - c = meas_resp_s{}; - break; - case types::trp_info_resp: - c = trp_info_resp_s{}; - break; - case types::positioning_activation_resp: - c = positioning_activation_resp_s{}; - break; - case types::prs_cfg_resp: - c = prs_cfg_resp_s{}; - break; - case types::meas_precfg_confirm: - c = meas_precfg_confirm_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::successful_outcome_c"); - } -} -e_c_id_meas_initiation_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::e_c_id_meas_initiation_resp() -{ - assert_choice_type(types::e_c_id_meas_initiation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -otdoa_info_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::otdoa_info_resp() -{ - assert_choice_type(types::otdoa_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -positioning_info_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::positioning_info_resp() -{ - assert_choice_type(types::positioning_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -meas_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::meas_resp() -{ - assert_choice_type(types::meas_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -trp_info_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::trp_info_resp() -{ - assert_choice_type(types::trp_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -positioning_activation_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::positioning_activation_resp() -{ - assert_choice_type(types::positioning_activation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -prs_cfg_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::prs_cfg_resp() -{ - assert_choice_type(types::prs_cfg_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -meas_precfg_confirm_s& nr_ppa_elem_procs_o::successful_outcome_c::meas_precfg_confirm() -{ - assert_choice_type(types::meas_precfg_confirm, type_, "SuccessfulOutcome"); - return c.get(); -} -const e_c_id_meas_initiation_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::e_c_id_meas_initiation_resp() const -{ - assert_choice_type(types::e_c_id_meas_initiation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const otdoa_info_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::otdoa_info_resp() const -{ - assert_choice_type(types::otdoa_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const positioning_info_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::positioning_info_resp() const -{ - assert_choice_type(types::positioning_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const meas_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::meas_resp() const -{ - assert_choice_type(types::meas_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const trp_info_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::trp_info_resp() const -{ - assert_choice_type(types::trp_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const positioning_activation_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::positioning_activation_resp() const -{ - assert_choice_type(types::positioning_activation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const prs_cfg_resp_s& nr_ppa_elem_procs_o::successful_outcome_c::prs_cfg_resp() const -{ - assert_choice_type(types::prs_cfg_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const meas_precfg_confirm_s& nr_ppa_elem_procs_o::successful_outcome_c::meas_precfg_confirm() const -{ - assert_choice_type(types::meas_precfg_confirm, type_, "SuccessfulOutcome"); - return c.get(); -} -void nr_ppa_elem_procs_o::successful_outcome_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_initiation_resp: - j.write_fieldname("E-CIDMeasurementInitiationResponse"); - c.get().to_json(j); - break; - case types::otdoa_info_resp: - j.write_fieldname("OTDOAInformationResponse"); - c.get().to_json(j); - break; - case types::positioning_info_resp: - j.write_fieldname("PositioningInformationResponse"); - c.get().to_json(j); - break; - case types::meas_resp: - j.write_fieldname("MeasurementResponse"); - c.get().to_json(j); - break; - case types::trp_info_resp: - j.write_fieldname("TRPInformationResponse"); - c.get().to_json(j); - break; - case types::positioning_activation_resp: - j.write_fieldname("PositioningActivationResponse"); - c.get().to_json(j); - break; - case types::prs_cfg_resp: - j.write_fieldname("PRSConfigurationResponse"); - c.get().to_json(j); - break; - case types::meas_precfg_confirm: - j.write_fieldname("MeasurementPreconfigurationConfirm"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::successful_outcome_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_o::successful_outcome_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::otdoa_info_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_info_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_activation_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_precfg_confirm: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::successful_outcome_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_o::successful_outcome_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::otdoa_info_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_info_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_activation_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_precfg_confirm: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::successful_outcome_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_o::successful_outcome_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementInitiationResponse", - "OTDOAInformationResponse", - "PositioningInformationResponse", - "MeasurementResponse", - "TRPInformationResponse", - "PositioningActivationResponse", - "PRSConfigurationResponse", - "MeasurementPreconfigurationConfirm"}; - return convert_enum_idx(names, 8, value, "nr_ppa_elem_procs_o::successful_outcome_c::types"); -} - -// UnsuccessfulOutcome ::= OPEN TYPE -void nr_ppa_elem_procs_o::unsuccessful_outcome_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_initiation_fail: - c = e_c_id_meas_initiation_fail_s{}; - break; - case types::otdoa_info_fail: - c = otdoa_info_fail_s{}; - break; - case types::positioning_info_fail: - c = positioning_info_fail_s{}; - break; - case types::meas_fail: - c = meas_fail_s{}; - break; - case types::trp_info_fail: - c = trp_info_fail_s{}; - break; - case types::positioning_activation_fail: - c = positioning_activation_fail_s{}; - break; - case types::prs_cfg_fail: - c = prs_cfg_fail_s{}; - break; - case types::meas_precfg_refuse: - c = meas_precfg_refuse_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::unsuccessful_outcome_c"); - } -} -e_c_id_meas_initiation_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::e_c_id_meas_initiation_fail() -{ - assert_choice_type(types::e_c_id_meas_initiation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -otdoa_info_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::otdoa_info_fail() -{ - assert_choice_type(types::otdoa_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -positioning_info_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::positioning_info_fail() -{ - assert_choice_type(types::positioning_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -meas_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::meas_fail() -{ - assert_choice_type(types::meas_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -trp_info_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::trp_info_fail() -{ - assert_choice_type(types::trp_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -positioning_activation_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::positioning_activation_fail() -{ - assert_choice_type(types::positioning_activation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -prs_cfg_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::prs_cfg_fail() -{ - assert_choice_type(types::prs_cfg_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -meas_precfg_refuse_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::meas_precfg_refuse() -{ - assert_choice_type(types::meas_precfg_refuse, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const e_c_id_meas_initiation_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::e_c_id_meas_initiation_fail() const -{ - assert_choice_type(types::e_c_id_meas_initiation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const otdoa_info_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::otdoa_info_fail() const -{ - assert_choice_type(types::otdoa_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const positioning_info_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::positioning_info_fail() const -{ - assert_choice_type(types::positioning_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const meas_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::meas_fail() const -{ - assert_choice_type(types::meas_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const trp_info_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::trp_info_fail() const -{ - assert_choice_type(types::trp_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const positioning_activation_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::positioning_activation_fail() const -{ - assert_choice_type(types::positioning_activation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const prs_cfg_fail_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::prs_cfg_fail() const -{ - assert_choice_type(types::prs_cfg_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const meas_precfg_refuse_s& nr_ppa_elem_procs_o::unsuccessful_outcome_c::meas_precfg_refuse() const -{ - assert_choice_type(types::meas_precfg_refuse, type_, "UnsuccessfulOutcome"); - return c.get(); -} -void nr_ppa_elem_procs_o::unsuccessful_outcome_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_initiation_fail: - j.write_fieldname("E-CIDMeasurementInitiationFailure"); - c.get().to_json(j); - break; - case types::otdoa_info_fail: - j.write_fieldname("OTDOAInformationFailure"); - c.get().to_json(j); - break; - case types::positioning_info_fail: - j.write_fieldname("PositioningInformationFailure"); - c.get().to_json(j); - break; - case types::meas_fail: - j.write_fieldname("MeasurementFailure"); - c.get().to_json(j); - break; - case types::trp_info_fail: - j.write_fieldname("TRPInformationFailure"); - c.get().to_json(j); - break; - case types::positioning_activation_fail: - j.write_fieldname("PositioningActivationFailure"); - c.get().to_json(j); - break; - case types::prs_cfg_fail: - j.write_fieldname("PRSConfigurationFailure"); - c.get().to_json(j); - break; - case types::meas_precfg_refuse: - j.write_fieldname("MeasurementPreconfigurationRefuse"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::unsuccessful_outcome_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_o::unsuccessful_outcome_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::otdoa_info_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_info_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_activation_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_precfg_refuse: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::unsuccessful_outcome_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_o::unsuccessful_outcome_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::otdoa_info_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_info_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_activation_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_precfg_refuse: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_o::unsuccessful_outcome_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_o::unsuccessful_outcome_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementInitiationFailure", - "OTDOAInformationFailure", - "PositioningInformationFailure", - "MeasurementFailure", - "TRPInformationFailure", - "PositioningActivationFailure", - "PRSConfigurationFailure", - "MeasurementPreconfigurationRefuse"}; - return convert_enum_idx(names, 8, value, "nr_ppa_elem_procs_o::unsuccessful_outcome_c::types"); -} - -// InitiatingMessage ::= SEQUENCE{{NRPPA-ELEMENTARY-PROCEDURE}} -SRSASN_CODE init_msg_s::pack(bit_ref& bref) const -{ - HANDLE_CODE(pack_integer(bref, proc_code, (uint16_t)0u, (uint16_t)255u, false, true)); - warn_assert(crit != nr_ppa_elem_procs_o::get_crit(proc_code), __func__, __LINE__); - HANDLE_CODE(crit.pack(bref)); - HANDLE_CODE(pack_integer(bref, nrppatransaction_id, (uint16_t)0u, (uint16_t)32767u, false, true)); - HANDLE_CODE(value.pack(bref)); - - return SRSASN_SUCCESS; -} -SRSASN_CODE init_msg_s::unpack(cbit_ref& bref) -{ - HANDLE_CODE(unpack_integer(proc_code, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(crit.unpack(bref)); - HANDLE_CODE(unpack_integer(nrppatransaction_id, bref, (uint16_t)0u, (uint16_t)32767u, false, true)); - value = nr_ppa_elem_procs_o::get_init_msg(proc_code); - HANDLE_CODE(value.unpack(bref)); - - return SRSASN_SUCCESS; -} -void init_msg_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("procedureCode", proc_code); - j.write_str("criticality", crit.to_string()); - j.write_int("nrppatransactionID", nrppatransaction_id); - j.write_fieldname("value"); - value.to_json(j); - j.end_obj(); -} -bool init_msg_s::load_info_obj(const uint16_t& proc_code_) -{ - if (not nr_ppa_elem_procs_o::is_proc_code_valid(proc_code_)) { - return false; - } - proc_code = proc_code_; - crit = nr_ppa_elem_procs_o::get_crit(proc_code); - value = nr_ppa_elem_procs_o::get_init_msg(proc_code); - return value.type().value != nr_ppa_elem_procs_o::init_msg_c::types_opts::nulltype; -} - -// SuccessfulOutcome ::= SEQUENCE{{NRPPA-ELEMENTARY-PROCEDURE}} -SRSASN_CODE successful_outcome_s::pack(bit_ref& bref) const -{ - HANDLE_CODE(pack_integer(bref, proc_code, (uint16_t)0u, (uint16_t)255u, false, true)); - warn_assert(crit != nr_ppa_elem_procs_o::get_crit(proc_code), __func__, __LINE__); - HANDLE_CODE(crit.pack(bref)); - HANDLE_CODE(pack_integer(bref, nrppatransaction_id, (uint16_t)0u, (uint16_t)32767u, false, true)); - HANDLE_CODE(value.pack(bref)); - - return SRSASN_SUCCESS; -} -SRSASN_CODE successful_outcome_s::unpack(cbit_ref& bref) -{ - HANDLE_CODE(unpack_integer(proc_code, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(crit.unpack(bref)); - HANDLE_CODE(unpack_integer(nrppatransaction_id, bref, (uint16_t)0u, (uint16_t)32767u, false, true)); - value = nr_ppa_elem_procs_o::get_successful_outcome(proc_code); - HANDLE_CODE(value.unpack(bref)); - - return SRSASN_SUCCESS; -} -void successful_outcome_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("procedureCode", proc_code); - j.write_str("criticality", crit.to_string()); - j.write_int("nrppatransactionID", nrppatransaction_id); - j.write_fieldname("value"); - value.to_json(j); - j.end_obj(); -} -bool successful_outcome_s::load_info_obj(const uint16_t& proc_code_) -{ - if (not nr_ppa_elem_procs_o::is_proc_code_valid(proc_code_)) { - return false; - } - proc_code = proc_code_; - crit = nr_ppa_elem_procs_o::get_crit(proc_code); - value = nr_ppa_elem_procs_o::get_successful_outcome(proc_code); - return value.type().value != nr_ppa_elem_procs_o::successful_outcome_c::types_opts::nulltype; -} - -// UnsuccessfulOutcome ::= SEQUENCE{{NRPPA-ELEMENTARY-PROCEDURE}} -SRSASN_CODE unsuccessful_outcome_s::pack(bit_ref& bref) const -{ - HANDLE_CODE(pack_integer(bref, proc_code, (uint16_t)0u, (uint16_t)255u, false, true)); - warn_assert(crit != nr_ppa_elem_procs_o::get_crit(proc_code), __func__, __LINE__); - HANDLE_CODE(crit.pack(bref)); - HANDLE_CODE(pack_integer(bref, nrppatransaction_id, (uint16_t)0u, (uint16_t)32767u, false, true)); - HANDLE_CODE(value.pack(bref)); - - return SRSASN_SUCCESS; -} -SRSASN_CODE unsuccessful_outcome_s::unpack(cbit_ref& bref) -{ - HANDLE_CODE(unpack_integer(proc_code, bref, (uint16_t)0u, (uint16_t)255u, false, true)); - HANDLE_CODE(crit.unpack(bref)); - HANDLE_CODE(unpack_integer(nrppatransaction_id, bref, (uint16_t)0u, (uint16_t)32767u, false, true)); - value = nr_ppa_elem_procs_o::get_unsuccessful_outcome(proc_code); - HANDLE_CODE(value.unpack(bref)); - - return SRSASN_SUCCESS; -} -void unsuccessful_outcome_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("procedureCode", proc_code); - j.write_str("criticality", crit.to_string()); - j.write_int("nrppatransactionID", nrppatransaction_id); - j.write_fieldname("value"); - value.to_json(j); - j.end_obj(); -} -bool unsuccessful_outcome_s::load_info_obj(const uint16_t& proc_code_) -{ - if (not nr_ppa_elem_procs_o::is_proc_code_valid(proc_code_)) { - return false; - } - proc_code = proc_code_; - crit = nr_ppa_elem_procs_o::get_crit(proc_code); - value = nr_ppa_elem_procs_o::get_unsuccessful_outcome(proc_code); - return value.type().value != nr_ppa_elem_procs_o::unsuccessful_outcome_c::types_opts::nulltype; -} - -// NRPPA-ELEMENTARY-PROCEDURES-CLASS-1 ::= OBJECT SET OF NRPPA-ELEMENTARY-PROCEDURE -uint16_t nr_ppa_elem_procs_class_1_o::idx_to_proc_code(uint32_t idx) -{ - static const uint16_t names[] = {2, 6, 9, 11, 16, 17, 19, 20}; - return map_enum_number(names, 8, idx, "proc_code"); -} -bool nr_ppa_elem_procs_class_1_o::is_proc_code_valid(const uint16_t& proc_code) -{ - static const uint16_t names[] = {2, 6, 9, 11, 16, 17, 19, 20}; - for (const auto& o : names) { - if (o == proc_code) { - return true; - } - } - return false; -} -nr_ppa_elem_procs_class_1_o::init_msg_c nr_ppa_elem_procs_class_1_o::get_init_msg(const uint16_t& proc_code) -{ - init_msg_c ret{}; - switch (proc_code) { - case 2: - ret.set(init_msg_c::types::e_c_id_meas_initiation_request); - break; - case 6: - ret.set(init_msg_c::types::otdoa_info_request); - break; - case 9: - ret.set(init_msg_c::types::positioning_info_request); - break; - case 11: - ret.set(init_msg_c::types::meas_request); - break; - case 16: - ret.set(init_msg_c::types::trp_info_request); - break; - case 17: - ret.set(init_msg_c::types::positioning_activation_request); - break; - case 19: - ret.set(init_msg_c::types::prs_cfg_request); - break; - case 20: - ret.set(init_msg_c::types::meas_precfg_required); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -nr_ppa_elem_procs_class_1_o::successful_outcome_c -nr_ppa_elem_procs_class_1_o::get_successful_outcome(const uint16_t& proc_code) -{ - successful_outcome_c ret{}; - switch (proc_code) { - case 2: - ret.set(successful_outcome_c::types::e_c_id_meas_initiation_resp); - break; - case 6: - ret.set(successful_outcome_c::types::otdoa_info_resp); - break; - case 9: - ret.set(successful_outcome_c::types::positioning_info_resp); - break; - case 11: - ret.set(successful_outcome_c::types::meas_resp); - break; - case 16: - ret.set(successful_outcome_c::types::trp_info_resp); - break; - case 17: - ret.set(successful_outcome_c::types::positioning_activation_resp); - break; - case 19: - ret.set(successful_outcome_c::types::prs_cfg_resp); - break; - case 20: - ret.set(successful_outcome_c::types::meas_precfg_confirm); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c -nr_ppa_elem_procs_class_1_o::get_unsuccessful_outcome(const uint16_t& proc_code) -{ - unsuccessful_outcome_c ret{}; - switch (proc_code) { - case 2: - ret.set(unsuccessful_outcome_c::types::e_c_id_meas_initiation_fail); - break; - case 6: - ret.set(unsuccessful_outcome_c::types::otdoa_info_fail); - break; - case 9: - ret.set(unsuccessful_outcome_c::types::positioning_info_fail); - break; - case 11: - ret.set(unsuccessful_outcome_c::types::meas_fail); - break; - case 16: - ret.set(unsuccessful_outcome_c::types::trp_info_fail); - break; - case 17: - ret.set(unsuccessful_outcome_c::types::positioning_activation_fail); - break; - case 19: - ret.set(unsuccessful_outcome_c::types::prs_cfg_fail); - break; - case 20: - ret.set(unsuccessful_outcome_c::types::meas_precfg_refuse); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -crit_e nr_ppa_elem_procs_class_1_o::get_crit(const uint16_t& proc_code) -{ - switch (proc_code) { - case 2: - return crit_e::reject; - case 6: - return crit_e::reject; - case 9: - return crit_e::reject; - case 11: - return crit_e::reject; - case 16: - return crit_e::reject; - case 17: - return crit_e::reject; - case 19: - return crit_e::reject; - case 20: - return crit_e::reject; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return {}; -} - -// InitiatingMessage ::= OPEN TYPE -void nr_ppa_elem_procs_class_1_o::init_msg_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_initiation_request: - c = e_c_id_meas_initiation_request_s{}; - break; - case types::otdoa_info_request: - c = otdoa_info_request_s{}; - break; - case types::positioning_info_request: - c = positioning_info_request_s{}; - break; - case types::meas_request: - c = meas_request_s{}; - break; - case types::trp_info_request: - c = trp_info_request_s{}; - break; - case types::positioning_activation_request: - c = positioning_activation_request_s{}; - break; - case types::prs_cfg_request: - c = prs_cfg_request_s{}; - break; - case types::meas_precfg_required: - c = meas_precfg_required_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::init_msg_c"); - } -} -e_c_id_meas_initiation_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::e_c_id_meas_initiation_request() -{ - assert_choice_type(types::e_c_id_meas_initiation_request, type_, "InitiatingMessage"); - return c.get(); -} -otdoa_info_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::otdoa_info_request() -{ - assert_choice_type(types::otdoa_info_request, type_, "InitiatingMessage"); - return c.get(); -} -positioning_info_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::positioning_info_request() -{ - assert_choice_type(types::positioning_info_request, type_, "InitiatingMessage"); - return c.get(); -} -meas_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::meas_request() -{ - assert_choice_type(types::meas_request, type_, "InitiatingMessage"); - return c.get(); -} -trp_info_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::trp_info_request() -{ - assert_choice_type(types::trp_info_request, type_, "InitiatingMessage"); - return c.get(); -} -positioning_activation_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::positioning_activation_request() -{ - assert_choice_type(types::positioning_activation_request, type_, "InitiatingMessage"); - return c.get(); -} -prs_cfg_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::prs_cfg_request() -{ - assert_choice_type(types::prs_cfg_request, type_, "InitiatingMessage"); - return c.get(); -} -meas_precfg_required_s& nr_ppa_elem_procs_class_1_o::init_msg_c::meas_precfg_required() -{ - assert_choice_type(types::meas_precfg_required, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_initiation_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::e_c_id_meas_initiation_request() const -{ - assert_choice_type(types::e_c_id_meas_initiation_request, type_, "InitiatingMessage"); - return c.get(); -} -const otdoa_info_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::otdoa_info_request() const -{ - assert_choice_type(types::otdoa_info_request, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_info_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::positioning_info_request() const -{ - assert_choice_type(types::positioning_info_request, type_, "InitiatingMessage"); - return c.get(); -} -const meas_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::meas_request() const -{ - assert_choice_type(types::meas_request, type_, "InitiatingMessage"); - return c.get(); -} -const trp_info_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::trp_info_request() const -{ - assert_choice_type(types::trp_info_request, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_activation_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::positioning_activation_request() const -{ - assert_choice_type(types::positioning_activation_request, type_, "InitiatingMessage"); - return c.get(); -} -const prs_cfg_request_s& nr_ppa_elem_procs_class_1_o::init_msg_c::prs_cfg_request() const -{ - assert_choice_type(types::prs_cfg_request, type_, "InitiatingMessage"); - return c.get(); -} -const meas_precfg_required_s& nr_ppa_elem_procs_class_1_o::init_msg_c::meas_precfg_required() const -{ - assert_choice_type(types::meas_precfg_required, type_, "InitiatingMessage"); - return c.get(); -} -void nr_ppa_elem_procs_class_1_o::init_msg_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_initiation_request: - j.write_fieldname("E-CIDMeasurementInitiationRequest"); - c.get().to_json(j); - break; - case types::otdoa_info_request: - j.write_fieldname("OTDOAInformationRequest"); - c.get().to_json(j); - break; - case types::positioning_info_request: - j.write_fieldname("PositioningInformationRequest"); - c.get().to_json(j); - break; - case types::meas_request: - j.write_fieldname("MeasurementRequest"); - c.get().to_json(j); - break; - case types::trp_info_request: - j.write_fieldname("TRPInformationRequest"); - c.get().to_json(j); - break; - case types::positioning_activation_request: - j.write_fieldname("PositioningActivationRequest"); - c.get().to_json(j); - break; - case types::prs_cfg_request: - j.write_fieldname("PRSConfigurationRequest"); - c.get().to_json(j); - break; - case types::meas_precfg_required: - j.write_fieldname("MeasurementPreconfigurationRequired"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::init_msg_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_class_1_o::init_msg_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::otdoa_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_info_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_activation_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_request: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_precfg_required: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::init_msg_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_class_1_o::init_msg_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::otdoa_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_info_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_activation_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_request: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_precfg_required: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::init_msg_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_class_1_o::init_msg_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementInitiationRequest", - "OTDOAInformationRequest", - "PositioningInformationRequest", - "MeasurementRequest", - "TRPInformationRequest", - "PositioningActivationRequest", - "PRSConfigurationRequest", - "MeasurementPreconfigurationRequired"}; - return convert_enum_idx(names, 8, value, "nr_ppa_elem_procs_class_1_o::init_msg_c::types"); -} - -// SuccessfulOutcome ::= OPEN TYPE -void nr_ppa_elem_procs_class_1_o::successful_outcome_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_initiation_resp: - c = e_c_id_meas_initiation_resp_s{}; - break; - case types::otdoa_info_resp: - c = otdoa_info_resp_s{}; - break; - case types::positioning_info_resp: - c = positioning_info_resp_s{}; - break; - case types::meas_resp: - c = meas_resp_s{}; - break; - case types::trp_info_resp: - c = trp_info_resp_s{}; - break; - case types::positioning_activation_resp: - c = positioning_activation_resp_s{}; - break; - case types::prs_cfg_resp: - c = prs_cfg_resp_s{}; - break; - case types::meas_precfg_confirm: - c = meas_precfg_confirm_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::successful_outcome_c"); - } -} -e_c_id_meas_initiation_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::e_c_id_meas_initiation_resp() -{ - assert_choice_type(types::e_c_id_meas_initiation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -otdoa_info_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::otdoa_info_resp() -{ - assert_choice_type(types::otdoa_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -positioning_info_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::positioning_info_resp() -{ - assert_choice_type(types::positioning_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -meas_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::meas_resp() -{ - assert_choice_type(types::meas_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -trp_info_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::trp_info_resp() -{ - assert_choice_type(types::trp_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -positioning_activation_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::positioning_activation_resp() -{ - assert_choice_type(types::positioning_activation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -prs_cfg_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::prs_cfg_resp() -{ - assert_choice_type(types::prs_cfg_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -meas_precfg_confirm_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::meas_precfg_confirm() -{ - assert_choice_type(types::meas_precfg_confirm, type_, "SuccessfulOutcome"); - return c.get(); -} -const e_c_id_meas_initiation_resp_s& -nr_ppa_elem_procs_class_1_o::successful_outcome_c::e_c_id_meas_initiation_resp() const -{ - assert_choice_type(types::e_c_id_meas_initiation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const otdoa_info_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::otdoa_info_resp() const -{ - assert_choice_type(types::otdoa_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const positioning_info_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::positioning_info_resp() const -{ - assert_choice_type(types::positioning_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const meas_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::meas_resp() const -{ - assert_choice_type(types::meas_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const trp_info_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::trp_info_resp() const -{ - assert_choice_type(types::trp_info_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const positioning_activation_resp_s& -nr_ppa_elem_procs_class_1_o::successful_outcome_c::positioning_activation_resp() const -{ - assert_choice_type(types::positioning_activation_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const prs_cfg_resp_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::prs_cfg_resp() const -{ - assert_choice_type(types::prs_cfg_resp, type_, "SuccessfulOutcome"); - return c.get(); -} -const meas_precfg_confirm_s& nr_ppa_elem_procs_class_1_o::successful_outcome_c::meas_precfg_confirm() const -{ - assert_choice_type(types::meas_precfg_confirm, type_, "SuccessfulOutcome"); - return c.get(); -} -void nr_ppa_elem_procs_class_1_o::successful_outcome_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_initiation_resp: - j.write_fieldname("E-CIDMeasurementInitiationResponse"); - c.get().to_json(j); - break; - case types::otdoa_info_resp: - j.write_fieldname("OTDOAInformationResponse"); - c.get().to_json(j); - break; - case types::positioning_info_resp: - j.write_fieldname("PositioningInformationResponse"); - c.get().to_json(j); - break; - case types::meas_resp: - j.write_fieldname("MeasurementResponse"); - c.get().to_json(j); - break; - case types::trp_info_resp: - j.write_fieldname("TRPInformationResponse"); - c.get().to_json(j); - break; - case types::positioning_activation_resp: - j.write_fieldname("PositioningActivationResponse"); - c.get().to_json(j); - break; - case types::prs_cfg_resp: - j.write_fieldname("PRSConfigurationResponse"); - c.get().to_json(j); - break; - case types::meas_precfg_confirm: - j.write_fieldname("MeasurementPreconfigurationConfirm"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::successful_outcome_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_class_1_o::successful_outcome_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::otdoa_info_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_info_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_activation_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_resp: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_precfg_confirm: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::successful_outcome_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_class_1_o::successful_outcome_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::otdoa_info_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_info_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_activation_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_resp: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_precfg_confirm: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::successful_outcome_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_class_1_o::successful_outcome_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementInitiationResponse", - "OTDOAInformationResponse", - "PositioningInformationResponse", - "MeasurementResponse", - "TRPInformationResponse", - "PositioningActivationResponse", - "PRSConfigurationResponse", - "MeasurementPreconfigurationConfirm"}; - return convert_enum_idx(names, 8, value, "nr_ppa_elem_procs_class_1_o::successful_outcome_c::types"); -} - -// UnsuccessfulOutcome ::= OPEN TYPE -void nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_initiation_fail: - c = e_c_id_meas_initiation_fail_s{}; - break; - case types::otdoa_info_fail: - c = otdoa_info_fail_s{}; - break; - case types::positioning_info_fail: - c = positioning_info_fail_s{}; - break; - case types::meas_fail: - c = meas_fail_s{}; - break; - case types::trp_info_fail: - c = trp_info_fail_s{}; - break; - case types::positioning_activation_fail: - c = positioning_activation_fail_s{}; - break; - case types::prs_cfg_fail: - c = prs_cfg_fail_s{}; - break; - case types::meas_precfg_refuse: - c = meas_precfg_refuse_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c"); - } -} -e_c_id_meas_initiation_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::e_c_id_meas_initiation_fail() -{ - assert_choice_type(types::e_c_id_meas_initiation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -otdoa_info_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::otdoa_info_fail() -{ - assert_choice_type(types::otdoa_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -positioning_info_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::positioning_info_fail() -{ - assert_choice_type(types::positioning_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -meas_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::meas_fail() -{ - assert_choice_type(types::meas_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -trp_info_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::trp_info_fail() -{ - assert_choice_type(types::trp_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -positioning_activation_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::positioning_activation_fail() -{ - assert_choice_type(types::positioning_activation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -prs_cfg_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::prs_cfg_fail() -{ - assert_choice_type(types::prs_cfg_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -meas_precfg_refuse_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::meas_precfg_refuse() -{ - assert_choice_type(types::meas_precfg_refuse, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const e_c_id_meas_initiation_fail_s& -nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::e_c_id_meas_initiation_fail() const -{ - assert_choice_type(types::e_c_id_meas_initiation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const otdoa_info_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::otdoa_info_fail() const -{ - assert_choice_type(types::otdoa_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const positioning_info_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::positioning_info_fail() const -{ - assert_choice_type(types::positioning_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const meas_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::meas_fail() const -{ - assert_choice_type(types::meas_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const trp_info_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::trp_info_fail() const -{ - assert_choice_type(types::trp_info_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const positioning_activation_fail_s& -nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::positioning_activation_fail() const -{ - assert_choice_type(types::positioning_activation_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const prs_cfg_fail_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::prs_cfg_fail() const -{ - assert_choice_type(types::prs_cfg_fail, type_, "UnsuccessfulOutcome"); - return c.get(); -} -const meas_precfg_refuse_s& nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::meas_precfg_refuse() const -{ - assert_choice_type(types::meas_precfg_refuse, type_, "UnsuccessfulOutcome"); - return c.get(); -} -void nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_initiation_fail: - j.write_fieldname("E-CIDMeasurementInitiationFailure"); - c.get().to_json(j); - break; - case types::otdoa_info_fail: - j.write_fieldname("OTDOAInformationFailure"); - c.get().to_json(j); - break; - case types::positioning_info_fail: - j.write_fieldname("PositioningInformationFailure"); - c.get().to_json(j); - break; - case types::meas_fail: - j.write_fieldname("MeasurementFailure"); - c.get().to_json(j); - break; - case types::trp_info_fail: - j.write_fieldname("TRPInformationFailure"); - c.get().to_json(j); - break; - case types::positioning_activation_fail: - j.write_fieldname("PositioningActivationFailure"); - c.get().to_json(j); - break; - case types::prs_cfg_fail: - j.write_fieldname("PRSConfigurationFailure"); - c.get().to_json(j); - break; - case types::meas_precfg_refuse: - j.write_fieldname("MeasurementPreconfigurationRefuse"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::otdoa_info_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::trp_info_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_activation_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::prs_cfg_fail: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_precfg_refuse: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_initiation_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::otdoa_info_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::trp_info_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_activation_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::prs_cfg_fail: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_precfg_refuse: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementInitiationFailure", - "OTDOAInformationFailure", - "PositioningInformationFailure", - "MeasurementFailure", - "TRPInformationFailure", - "PositioningActivationFailure", - "PRSConfigurationFailure", - "MeasurementPreconfigurationRefuse"}; - return convert_enum_idx(names, 8, value, "nr_ppa_elem_procs_class_1_o::unsuccessful_outcome_c::types"); -} - -// NRPPA-ELEMENTARY-PROCEDURES-CLASS-2 ::= OBJECT SET OF NRPPA-ELEMENTARY-PROCEDURE -uint16_t nr_ppa_elem_procs_class_2_o::idx_to_proc_code(uint32_t idx) -{ - static const uint16_t names[] = {3, 4, 5, 0, 1, 7, 8, 10, 12, 13, 14, 15, 18, 21}; - return map_enum_number(names, 14, idx, "proc_code"); -} -bool nr_ppa_elem_procs_class_2_o::is_proc_code_valid(const uint16_t& proc_code) -{ - static const uint16_t names[] = {3, 4, 5, 0, 1, 7, 8, 10, 12, 13, 14, 15, 18, 21}; - for (const auto& o : names) { - if (o == proc_code) { - return true; - } - } - return false; -} -nr_ppa_elem_procs_class_2_o::init_msg_c nr_ppa_elem_procs_class_2_o::get_init_msg(const uint16_t& proc_code) -{ - init_msg_c ret{}; - switch (proc_code) { - case 3: - ret.set(init_msg_c::types::e_c_id_meas_fail_ind); - break; - case 4: - ret.set(init_msg_c::types::e_c_id_meas_report); - break; - case 5: - ret.set(init_msg_c::types::e_c_id_meas_termination_cmd); - break; - case 0: - ret.set(init_msg_c::types::error_ind); - break; - case 1: - ret.set(init_msg_c::types::private_msg); - break; - case 7: - ret.set(init_msg_c::types::assist_info_ctrl); - break; - case 8: - ret.set(init_msg_c::types::assist_info_feedback); - break; - case 10: - ret.set(init_msg_c::types::positioning_info_upd); - break; - case 12: - ret.set(init_msg_c::types::meas_report); - break; - case 13: - ret.set(init_msg_c::types::meas_upd); - break; - case 14: - ret.set(init_msg_c::types::meas_abort); - break; - case 15: - ret.set(init_msg_c::types::meas_fail_ind); - break; - case 18: - ret.set(init_msg_c::types::positioning_deactivation); - break; - case 21: - ret.set(init_msg_c::types::meas_activation); - break; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -nr_ppa_elem_procs_class_2_o::successful_outcome_c -nr_ppa_elem_procs_class_2_o::get_successful_outcome(const uint16_t& proc_code) -{ - successful_outcome_c ret{}; - switch (proc_code) { - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -nr_ppa_elem_procs_class_2_o::unsuccessful_outcome_c -nr_ppa_elem_procs_class_2_o::get_unsuccessful_outcome(const uint16_t& proc_code) -{ - unsuccessful_outcome_c ret{}; - switch (proc_code) { - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return ret; -} -crit_e nr_ppa_elem_procs_class_2_o::get_crit(const uint16_t& proc_code) -{ - switch (proc_code) { - case 3: - return crit_e::ignore; - case 4: - return crit_e::ignore; - case 5: - return crit_e::reject; - case 0: - return crit_e::ignore; - case 1: - return crit_e::ignore; - case 7: - return crit_e::reject; - case 8: - return crit_e::reject; - case 10: - return crit_e::ignore; - case 12: - return crit_e::ignore; - case 13: - return crit_e::ignore; - case 14: - return crit_e::ignore; - case 15: - return crit_e::ignore; - case 18: - return crit_e::ignore; - case 21: - return crit_e::ignore; - default: - asn1::log_error("The proc_code={} is not recognized", proc_code); - } - return {}; -} - -// InitiatingMessage ::= OPEN TYPE -void nr_ppa_elem_procs_class_2_o::init_msg_c::set(types::options e) -{ - type_ = e; - switch (type_) { - case types::e_c_id_meas_fail_ind: - c = e_c_id_meas_fail_ind_s{}; - break; - case types::e_c_id_meas_report: - c = e_c_id_meas_report_s{}; - break; - case types::e_c_id_meas_termination_cmd: - c = e_c_id_meas_termination_cmd_s{}; - break; - case types::error_ind: - c = error_ind_s{}; - break; - case types::private_msg: - c = private_msg_s{}; - break; - case types::assist_info_ctrl: - c = assist_info_ctrl_s{}; - break; - case types::assist_info_feedback: - c = assist_info_feedback_s{}; - break; - case types::positioning_info_upd: - c = positioning_info_upd_s{}; - break; - case types::meas_report: - c = meas_report_s{}; - break; - case types::meas_upd: - c = meas_upd_s{}; - break; - case types::meas_abort: - c = meas_abort_s{}; - break; - case types::meas_fail_ind: - c = meas_fail_ind_s{}; - break; - case types::positioning_deactivation: - c = positioning_deactivation_s{}; - break; - case types::meas_activation: - c = meas_activation_s{}; - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_2_o::init_msg_c"); - } -} -e_c_id_meas_fail_ind_s& nr_ppa_elem_procs_class_2_o::init_msg_c::e_c_id_meas_fail_ind() -{ - assert_choice_type(types::e_c_id_meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -e_c_id_meas_report_s& nr_ppa_elem_procs_class_2_o::init_msg_c::e_c_id_meas_report() -{ - assert_choice_type(types::e_c_id_meas_report, type_, "InitiatingMessage"); - return c.get(); -} -e_c_id_meas_termination_cmd_s& nr_ppa_elem_procs_class_2_o::init_msg_c::e_c_id_meas_termination_cmd() -{ - assert_choice_type(types::e_c_id_meas_termination_cmd, type_, "InitiatingMessage"); - return c.get(); -} -error_ind_s& nr_ppa_elem_procs_class_2_o::init_msg_c::error_ind() -{ - assert_choice_type(types::error_ind, type_, "InitiatingMessage"); - return c.get(); -} -private_msg_s& nr_ppa_elem_procs_class_2_o::init_msg_c::private_msg() -{ - assert_choice_type(types::private_msg, type_, "InitiatingMessage"); - return c.get(); -} -assist_info_ctrl_s& nr_ppa_elem_procs_class_2_o::init_msg_c::assist_info_ctrl() -{ - assert_choice_type(types::assist_info_ctrl, type_, "InitiatingMessage"); - return c.get(); -} -assist_info_feedback_s& nr_ppa_elem_procs_class_2_o::init_msg_c::assist_info_feedback() -{ - assert_choice_type(types::assist_info_feedback, type_, "InitiatingMessage"); - return c.get(); -} -positioning_info_upd_s& nr_ppa_elem_procs_class_2_o::init_msg_c::positioning_info_upd() -{ - assert_choice_type(types::positioning_info_upd, type_, "InitiatingMessage"); - return c.get(); -} -meas_report_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_report() -{ - assert_choice_type(types::meas_report, type_, "InitiatingMessage"); - return c.get(); -} -meas_upd_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_upd() -{ - assert_choice_type(types::meas_upd, type_, "InitiatingMessage"); - return c.get(); -} -meas_abort_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_abort() -{ - assert_choice_type(types::meas_abort, type_, "InitiatingMessage"); - return c.get(); -} -meas_fail_ind_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_fail_ind() -{ - assert_choice_type(types::meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -positioning_deactivation_s& nr_ppa_elem_procs_class_2_o::init_msg_c::positioning_deactivation() -{ - assert_choice_type(types::positioning_deactivation, type_, "InitiatingMessage"); - return c.get(); -} -meas_activation_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_activation() -{ - assert_choice_type(types::meas_activation, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_fail_ind_s& nr_ppa_elem_procs_class_2_o::init_msg_c::e_c_id_meas_fail_ind() const -{ - assert_choice_type(types::e_c_id_meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_report_s& nr_ppa_elem_procs_class_2_o::init_msg_c::e_c_id_meas_report() const -{ - assert_choice_type(types::e_c_id_meas_report, type_, "InitiatingMessage"); - return c.get(); -} -const e_c_id_meas_termination_cmd_s& nr_ppa_elem_procs_class_2_o::init_msg_c::e_c_id_meas_termination_cmd() const -{ - assert_choice_type(types::e_c_id_meas_termination_cmd, type_, "InitiatingMessage"); - return c.get(); -} -const error_ind_s& nr_ppa_elem_procs_class_2_o::init_msg_c::error_ind() const -{ - assert_choice_type(types::error_ind, type_, "InitiatingMessage"); - return c.get(); -} -const private_msg_s& nr_ppa_elem_procs_class_2_o::init_msg_c::private_msg() const -{ - assert_choice_type(types::private_msg, type_, "InitiatingMessage"); - return c.get(); -} -const assist_info_ctrl_s& nr_ppa_elem_procs_class_2_o::init_msg_c::assist_info_ctrl() const -{ - assert_choice_type(types::assist_info_ctrl, type_, "InitiatingMessage"); - return c.get(); -} -const assist_info_feedback_s& nr_ppa_elem_procs_class_2_o::init_msg_c::assist_info_feedback() const -{ - assert_choice_type(types::assist_info_feedback, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_info_upd_s& nr_ppa_elem_procs_class_2_o::init_msg_c::positioning_info_upd() const -{ - assert_choice_type(types::positioning_info_upd, type_, "InitiatingMessage"); - return c.get(); -} -const meas_report_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_report() const -{ - assert_choice_type(types::meas_report, type_, "InitiatingMessage"); - return c.get(); -} -const meas_upd_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_upd() const -{ - assert_choice_type(types::meas_upd, type_, "InitiatingMessage"); - return c.get(); -} -const meas_abort_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_abort() const -{ - assert_choice_type(types::meas_abort, type_, "InitiatingMessage"); - return c.get(); -} -const meas_fail_ind_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_fail_ind() const -{ - assert_choice_type(types::meas_fail_ind, type_, "InitiatingMessage"); - return c.get(); -} -const positioning_deactivation_s& nr_ppa_elem_procs_class_2_o::init_msg_c::positioning_deactivation() const -{ - assert_choice_type(types::positioning_deactivation, type_, "InitiatingMessage"); - return c.get(); -} -const meas_activation_s& nr_ppa_elem_procs_class_2_o::init_msg_c::meas_activation() const -{ - assert_choice_type(types::meas_activation, type_, "InitiatingMessage"); - return c.get(); -} -void nr_ppa_elem_procs_class_2_o::init_msg_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::e_c_id_meas_fail_ind: - j.write_fieldname("E-CIDMeasurementFailureIndication"); - c.get().to_json(j); - break; - case types::e_c_id_meas_report: - j.write_fieldname("E-CIDMeasurementReport"); - c.get().to_json(j); - break; - case types::e_c_id_meas_termination_cmd: - j.write_fieldname("E-CIDMeasurementTerminationCommand"); - c.get().to_json(j); - break; - case types::error_ind: - j.write_fieldname("ErrorIndication"); - c.get().to_json(j); - break; - case types::private_msg: - j.write_fieldname("PrivateMessage"); - c.get().to_json(j); - break; - case types::assist_info_ctrl: - j.write_fieldname("AssistanceInformationControl"); - c.get().to_json(j); - break; - case types::assist_info_feedback: - j.write_fieldname("AssistanceInformationFeedback"); - c.get().to_json(j); - break; - case types::positioning_info_upd: - j.write_fieldname("PositioningInformationUpdate"); - c.get().to_json(j); - break; - case types::meas_report: - j.write_fieldname("MeasurementReport"); - c.get().to_json(j); - break; - case types::meas_upd: - j.write_fieldname("MeasurementUpdate"); - c.get().to_json(j); - break; - case types::meas_abort: - j.write_fieldname("MeasurementAbort"); - c.get().to_json(j); - break; - case types::meas_fail_ind: - j.write_fieldname("MeasurementFailureIndication"); - c.get().to_json(j); - break; - case types::positioning_deactivation: - j.write_fieldname("PositioningDeactivation"); - c.get().to_json(j); - break; - case types::meas_activation: - j.write_fieldname("MeasurementActivation"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_2_o::init_msg_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_class_2_o::init_msg_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_fail_ind: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::e_c_id_meas_report: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::e_c_id_meas_termination_cmd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::error_ind: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::private_msg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::assist_info_ctrl: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::assist_info_feedback: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_info_upd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_report: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_upd: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_abort: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_fail_ind: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::positioning_deactivation: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::meas_activation: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_2_o::init_msg_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_class_2_o::init_msg_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - switch (type_) { - case types::e_c_id_meas_fail_ind: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::e_c_id_meas_report: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::e_c_id_meas_termination_cmd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::error_ind: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::private_msg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::assist_info_ctrl: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::assist_info_feedback: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_info_upd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_report: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_upd: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_abort: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_fail_ind: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::positioning_deactivation: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::meas_activation: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_elem_procs_class_2_o::init_msg_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_class_2_o::init_msg_c::types_opts::to_string() const -{ - static const char* names[] = {"E-CIDMeasurementFailureIndication", - "E-CIDMeasurementReport", - "E-CIDMeasurementTerminationCommand", - "ErrorIndication", - "PrivateMessage", - "AssistanceInformationControl", - "AssistanceInformationFeedback", - "PositioningInformationUpdate", - "MeasurementReport", - "MeasurementUpdate", - "MeasurementAbort", - "MeasurementFailureIndication", - "PositioningDeactivation", - "MeasurementActivation"}; - return convert_enum_idx(names, 14, value, "nr_ppa_elem_procs_class_2_o::init_msg_c::types"); -} - -// SuccessfulOutcome ::= OPEN TYPE -void nr_ppa_elem_procs_class_2_o::successful_outcome_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_class_2_o::successful_outcome_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_class_2_o::successful_outcome_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_class_2_o::successful_outcome_c::types_opts::to_string() const -{ - static const char* names[] = {}; - return convert_enum_idx(names, 0, value, "nr_ppa_elem_procs_class_2_o::successful_outcome_c::types"); -} - -// UnsuccessfulOutcome ::= OPEN TYPE -void nr_ppa_elem_procs_class_2_o::unsuccessful_outcome_c::to_json(json_writer& j) const -{ - j.start_obj(); - j.end_obj(); -} -SRSASN_CODE nr_ppa_elem_procs_class_2_o::unsuccessful_outcome_c::pack(bit_ref& bref) const -{ - varlength_field_pack_guard varlen_scope(bref, true); - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_elem_procs_class_2_o::unsuccessful_outcome_c::unpack(cbit_ref& bref) -{ - varlength_field_unpack_guard varlen_scope(bref, true); - return SRSASN_SUCCESS; -} - -const char* nr_ppa_elem_procs_class_2_o::unsuccessful_outcome_c::types_opts::to_string() const -{ - static const char* names[] = {}; - return convert_enum_idx(names, 0, value, "nr_ppa_elem_procs_class_2_o::unsuccessful_outcome_c::types"); -} - -// NRPPA-PDU ::= CHOICE -void nr_ppa_pdu_c::destroy_() -{ - switch (type_) { - case types::init_msg: - c.destroy(); - break; - case types::successful_outcome: - c.destroy(); - break; - case types::unsuccessful_outcome: - c.destroy(); - break; - default: - break; - } -} -void nr_ppa_pdu_c::set(types::options e) -{ - destroy_(); - type_ = e; - switch (type_) { - case types::init_msg: - c.init(); - break; - case types::successful_outcome: - c.init(); - break; - case types::unsuccessful_outcome: - c.init(); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_pdu_c"); - } -} -nr_ppa_pdu_c::nr_ppa_pdu_c(const nr_ppa_pdu_c& other) -{ - type_ = other.type(); - switch (type_) { - case types::init_msg: - c.init(other.c.get()); - break; - case types::successful_outcome: - c.init(other.c.get()); - break; - case types::unsuccessful_outcome: - c.init(other.c.get()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_pdu_c"); - } -} -nr_ppa_pdu_c& nr_ppa_pdu_c::operator=(const nr_ppa_pdu_c& other) -{ - if (this == &other) { - return *this; - } - set(other.type()); - switch (type_) { - case types::init_msg: - c.set(other.c.get()); - break; - case types::successful_outcome: - c.set(other.c.get()); - break; - case types::unsuccessful_outcome: - c.set(other.c.get()); - break; - case types::nulltype: - break; - default: - log_invalid_choice_id(type_, "nr_ppa_pdu_c"); - } - - return *this; -} -init_msg_s& nr_ppa_pdu_c::set_init_msg() -{ - set(types::init_msg); - return c.get(); -} -successful_outcome_s& nr_ppa_pdu_c::set_successful_outcome() -{ - set(types::successful_outcome); - return c.get(); -} -unsuccessful_outcome_s& nr_ppa_pdu_c::set_unsuccessful_outcome() -{ - set(types::unsuccessful_outcome); - return c.get(); -} -void nr_ppa_pdu_c::to_json(json_writer& j) const -{ - j.start_obj(); - switch (type_) { - case types::init_msg: - j.write_fieldname("initiatingMessage"); - c.get().to_json(j); - break; - case types::successful_outcome: - j.write_fieldname("successfulOutcome"); - c.get().to_json(j); - break; - case types::unsuccessful_outcome: - j.write_fieldname("unsuccessfulOutcome"); - c.get().to_json(j); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_pdu_c"); - } - j.end_obj(); -} -SRSASN_CODE nr_ppa_pdu_c::pack(bit_ref& bref) const -{ - type_.pack(bref); - switch (type_) { - case types::init_msg: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::successful_outcome: - HANDLE_CODE(c.get().pack(bref)); - break; - case types::unsuccessful_outcome: - HANDLE_CODE(c.get().pack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_pdu_c"); - return SRSASN_ERROR_ENCODE_FAIL; - } - return SRSASN_SUCCESS; -} -SRSASN_CODE nr_ppa_pdu_c::unpack(cbit_ref& bref) -{ - types e; - e.unpack(bref); - set(e); - switch (type_) { - case types::init_msg: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::successful_outcome: - HANDLE_CODE(c.get().unpack(bref)); - break; - case types::unsuccessful_outcome: - HANDLE_CODE(c.get().unpack(bref)); - break; - default: - log_invalid_choice_id(type_, "nr_ppa_pdu_c"); - return SRSASN_ERROR_DECODE_FAIL; - } - return SRSASN_SUCCESS; -} - -const char* nr_ppa_pdu_c::types_opts::to_string() const -{ - static const char* names[] = {"initiatingMessage", "successfulOutcome", "unsuccessfulOutcome"}; - return convert_enum_idx(names, 3, value, "nr_ppa_pdu_c::types"); -} - -// SRSResourceID-Item ::= SEQUENCE -SRSASN_CODE srs_res_id_item_s::pack(bit_ref& bref) const -{ - bref.pack(ext, 1); - HANDLE_CODE(bref.pack(ie_exts_present, 1)); - - HANDLE_CODE(pack_integer(bref, srs_res_id, (uint8_t)0u, (uint8_t)63u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.pack(bref)); - } - - return SRSASN_SUCCESS; -} -SRSASN_CODE srs_res_id_item_s::unpack(cbit_ref& bref) -{ - bref.unpack(ext, 1); - HANDLE_CODE(bref.unpack(ie_exts_present, 1)); - - HANDLE_CODE(unpack_integer(srs_res_id, bref, (uint8_t)0u, (uint8_t)63u, false, true)); - if (ie_exts_present) { - HANDLE_CODE(ie_exts.unpack(bref)); - } - - return SRSASN_SUCCESS; -} -void srs_res_id_item_s::to_json(json_writer& j) const -{ - j.start_obj(); - j.write_int("sRSResourceID", srs_res_id); - if (ie_exts_present) { - j.write_fieldname("iE-Extensions"); - ie_exts.to_json(j); - } - j.end_obj(); -} From 69b1fa5e56825b6ddc468a97ade1aadc23ddac15 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 22 Nov 2024 19:26:29 +0100 Subject: [PATCH 002/227] cu_cp,ngap: refactor nrppa transport message handling --- include/srsran/ngap/ngap.h | 11 +++- include/srsran/ngap/ngap_context.h | 1 + include/srsran/ngap/ngap_nrppa.h | 32 ----------- include/srsran/ran/crit_diagnostics.h | 5 ++ lib/cu_cp/CMakeLists.txt | 1 - lib/cu_cp/adapters/ngap_adapters.h | 10 +++- lib/cu_cp/cu_cp_impl.cpp | 11 +++- lib/cu_cp/cu_cp_impl.h | 42 +++++++------- lib/cu_cp/cu_cp_impl_interface.h | 19 ++++--- ..._ue_associated_nrppa_transport_routine.cpp | 26 --------- ...on_ue_associated_nrppa_transport_routine.h | 23 -------- lib/ngap/CMakeLists.txt | 1 - lib/ngap/ngap_asn1_helpers.h | 42 -------------- lib/ngap/ngap_impl.cpp | 56 ++++--------------- lib/ngap/ngap_impl.h | 1 + ...e_associated_nrppa_transport_procedure.cpp | 28 ---------- ..._ue_associated_nrppa_transport_procedure.h | 27 --------- tests/unittests/cu_cp/cu_cp_nrppa_test.cpp | 39 ------------- tests/unittests/ngap/test_helpers.h | 9 ++- 19 files changed, 84 insertions(+), 300 deletions(-) delete mode 100644 include/srsran/ngap/ngap_nrppa.h delete mode 100644 lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.cpp delete mode 100644 lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.h delete mode 100644 lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.cpp delete mode 100644 lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.h diff --git a/include/srsran/ngap/ngap.h b/include/srsran/ngap/ngap.h index 2f4b184070..13e501e3e3 100644 --- a/include/srsran/ngap/ngap.h +++ b/include/srsran/ngap/ngap.h @@ -14,7 +14,6 @@ #include "srsran/ngap/ngap_context.h" #include "srsran/ngap/ngap_handover.h" #include "srsran/ngap/ngap_init_context_setup.h" -#include "srsran/ngap/ngap_nrppa.h" #include "srsran/ngap/ngap_reset.h" #include "srsran/ngap/ngap_setup.h" #include "srsran/ngap/ngap_ue_radio_capability_management.h" @@ -96,7 +95,7 @@ class ngap_rrc_ue_notifier virtual ~ngap_rrc_ue_notifier() = default; /// \brief Notify about the a new nas pdu. - /// \param [in] nas_pdu The nas pdu. + /// \param[in] nas_pdu The nas pdu. virtual void on_new_pdu(byte_buffer nas_pdu) = 0; /// \brief Get packed packed UE radio access capability info for UE radio capability info indication. @@ -202,8 +201,11 @@ class ngap_cu_cp_notifier virtual async_task on_ngap_handover_request(const ngap_handover_request& request) = 0; + /// \brief Notifies the CU-CP about a DL UE associated NRPPa transport. + virtual void on_dl_ue_associated_nrppa_transport_pdu(ue_index_t ue_index, const byte_buffer& nrppa_pdu) = 0; + /// \brief Notifies the CU-CP about a DL non UE associated NRPPa transport. - virtual void on_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg) = 0; + virtual void on_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) = 0; }; /// Handle NGAP NAS Message procedures as defined in TS 38.413 section 8.6. @@ -255,6 +257,9 @@ class ngap_control_message_handler /// \brief Get the supported PLMNs. virtual const ngap_context_t& get_ngap_context() const = 0; + + /// \brief Handle the reception of a UL NRPPa message. + virtual void handle_ul_ue_associated_nrppa_transport(ue_index_t ue_index, const byte_buffer& nrppa_pdu) = 0; }; /// Interface to control the NGAP. diff --git a/include/srsran/ngap/ngap_context.h b/include/srsran/ngap/ngap_context.h index a83fea3d6d..93d367ddb5 100644 --- a/include/srsran/ngap/ngap_context.h +++ b/include/srsran/ngap/ngap_context.h @@ -29,6 +29,7 @@ struct ngap_context_t { std::vector served_guami_list; 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::string lmf_routing_id; std::vector get_supported_plmns() const { diff --git a/include/srsran/ngap/ngap_nrppa.h b/include/srsran/ngap/ngap_nrppa.h deleted file mode 100644 index bf956d1450..0000000000 --- a/include/srsran/ngap/ngap_nrppa.h +++ /dev/null @@ -1,32 +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/cu_cp/cu_cp_types.h" - -namespace srsran { -namespace srs_cu_cp { - -/// DL/UL UE Associated NRPPA Transport message. -struct ngap_ue_associated_nrppa_transport { - ue_index_t ue_index; - byte_buffer routing_id; - byte_buffer nrppa_pdu; -}; - -/// DL/UL Non UE Associated NRPPA Transport message. -struct ngap_non_ue_associated_nrppa_transport { - byte_buffer routing_id; - byte_buffer nrppa_pdu; -}; - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/include/srsran/ran/crit_diagnostics.h b/include/srsran/ran/crit_diagnostics.h index a5b3b93c21..9129db0f8f 100644 --- a/include/srsran/ran/crit_diagnostics.h +++ b/include/srsran/ran/crit_diagnostics.h @@ -10,6 +10,11 @@ #pragma once +#include +#include +#include +#include + namespace srsran { struct crit_diagnostics_item { diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index 2596487715..8e27cc27e3 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -29,7 +29,6 @@ set(SOURCES ngap_repository.cpp routines/amf_connection_setup_routine.cpp routines/amf_connection_removal_routine.cpp - routines/dl_non_ue_associated_nrppa_transport_routine.cpp routines/initial_context_setup_routine.cpp routines/pdu_session_routine_helpers.cpp routines/pdu_session_resource_setup_routine.cpp diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index 027b3ea657..543aaa70de 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -109,10 +109,16 @@ class ngap_cu_cp_adapter : public ngap_cu_cp_notifier return cu_cp_handler->handle_ue_index_allocation_request(cgi); } - void on_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg) override + void on_dl_ue_associated_nrppa_transport_pdu(ue_index_t ue_index, const byte_buffer& nrppa_pdu) override { srsran_assert(cu_cp_handler != nullptr, "CU-CP NGAP handler must not be nullptr"); - cu_cp_handler->handle_dl_non_ue_associated_nrppa_transport(msg); + cu_cp_handler->handle_dl_ue_associated_nrppa_transport_pdu(ue_index, nrppa_pdu); + } + + void on_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NGAP handler must not be nullptr"); + cu_cp_handler->handle_dl_non_ue_associated_nrppa_transport_pdu(nrppa_pdu); } void on_n2_disconnection() override diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 20205755da..51c7f99491 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -12,7 +12,6 @@ #include "du_processor/du_processor_repository.h" #include "metrics_handler/metrics_handler_impl.h" #include "mobility_manager/mobility_manager_factory.h" -#include "routines/dl_non_ue_associated_nrppa_transport_routine.h" #include "routines/initial_context_setup_routine.h" #include "routines/mobility/inter_cu_handover_target_routine.h" #include "routines/mobility/intra_cu_handover_routine.h" @@ -590,9 +589,15 @@ ue_index_t cu_cp_impl::handle_ue_index_allocation_request(const nr_cell_global_i return ue_mng.add_ue(du_index, cgi.plmn_id); } -void cu_cp_impl::handle_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg) +SRSRAN_WEAK_SYMB void cu_cp_impl::handle_dl_ue_associated_nrppa_transport_pdu(ue_index_t ue_index, + const byte_buffer& nrppa_pdu) { - common_task_sched.schedule_async_task(start_ngap_dl_non_ue_associated_nrppa_transport(msg, logger)); + logger.info("DL UE associated NRPPa messages are not supported"); +} + +void cu_cp_impl::handle_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) +{ + logger.info("DL non UE associated NRPPa messages are not supported"); } void cu_cp_impl::handle_n2_disconnection() diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 4f129af59e..8435980275 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -60,7 +60,7 @@ class cu_cp_impl final : public cu_cp, bool start() override; void stop() override; - // NGAP interface + // NGAP interface. ngap_message_handler* get_ngap_message_handler(const plmn_identity& plmn) override; bool amfs_are_connected() override; @@ -68,7 +68,7 @@ class cu_cp_impl final : public cu_cp, // CU-UP handler void handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) override; - // cu_cp_rrc_ue_interface + // cu_cp_rrc_ue_interface. rrc_ue_reestablishment_context_response handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, ue_index_t ue_index) override; async_task handle_rrc_reestablishment_context_modification_required(ue_index_t ue_index) override; @@ -78,11 +78,11 @@ class cu_cp_impl final : public cu_cp, async_task handle_ue_context_transfer(ue_index_t ue_index, ue_index_t old_ue_index) override; async_task handle_ue_context_release(const cu_cp_ue_context_release_request& request) override; - // cu_cp_ue_context_manipulation_handler + // cu_cp_ue_context_manipulation_handler. async_task handle_handover_reconfiguration_sent(ue_index_t target_ue_index, uint8_t transaction_id) override; void handle_handover_ue_context_push(ue_index_t source_ue_index, ue_index_t target_ue_index) override; - // cu_cp_ngap_handler + // cu_cp_ngap_handler. bool handle_handover_request(ue_index_t ue_index, security::security_context sec_ctxt) override; async_task> handle_new_initial_context_setup_request(const ngap_init_context_setup_request& request) override; @@ -98,33 +98,34 @@ class cu_cp_impl final : public cu_cp, handle_ngap_handover_request(const ngap_handover_request& request) override; async_task handle_new_handover_command(ue_index_t ue_index, byte_buffer command) override; ue_index_t handle_ue_index_allocation_request(const nr_cell_global_id_t& cgi) override; - void handle_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg) override; + void handle_dl_ue_associated_nrppa_transport_pdu(ue_index_t ue_index, const byte_buffer& nrppa_pdu) override; + void handle_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) override; void handle_n2_disconnection() override; - // cu_cp_measurement_handler + // cu_cp_measurement_handler. std::optional handle_measurement_config_request(ue_index_t ue_index, nr_cell_identity nci, std::optional current_meas_config = {}) override; void handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) override; - // cu_cp_measurement_config_handler + // cu_cp_measurement_config_handler. bool handle_cell_config_update_request(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg) override; - // cu_cp_mobility_manager_handler + // cu_cp_mobility_manager_handler. async_task handle_intra_cu_handover_request(const cu_cp_intra_cu_handover_request& request, du_index_t& source_du_index, du_index_t& target_du_index) override; - // cu_cp_ue_removal_handler + // cu_cp_ue_removal_handler. async_task handle_ue_removal_request(ue_index_t ue_index) override; void handle_pending_ue_task_cancellation(ue_index_t ue_index) override; cu_cp_mobility_command_handler& get_mobility_command_handler() override { return *mobility_mng; } metrics_handler& get_metrics_handler() override { return *metrics_hdlr; } - // cu_cp public interface + // cu_cp public interface. cu_cp_f1c_handler& get_f1c_handler() override { return controller->get_f1c_handler(); } cu_cp_e1_handler& get_e1_handler() override { return controller->get_e1_handler(); } cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() override { return *this; } @@ -146,25 +147,28 @@ class cu_cp_impl final : public cu_cp, async_task handle_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) override; - // NGAP UE creation handler + // NGAP UE creation handler. ngap_cu_cp_ue_notifier* handle_new_ngap_ue(ue_index_t ue_index) override; - // cu_cp_task_scheduler_handler + // cu_cp_task_scheduler_handler. bool schedule_ue_task(ue_index_t ue_index, async_task task) override; void on_statistics_report_timer_expired(); cu_cp_configuration cfg; - // logger + // Logger. srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP"); - // Components + // Components. + // UE manager. ue_manager ue_mng; + // Mobility manager. std::unique_ptr mobility_mng; - cell_meas_manager cell_meas_mng; // cell measurement manager + // Cell measurement manager. + cell_meas_manager cell_meas_mng; cu_cp_common_task_scheduler common_task_sched; @@ -174,16 +178,16 @@ class cu_cp_impl final : public cu_cp, // Cell Measurement Manager to mobility manager adapters cell_meas_mobility_manager_adapter cell_meas_ev_notifier; - // E1AP to CU-CP adapter + // E1AP to CU-CP adapter. e1ap_cu_cp_adapter e1ap_ev_notifier; - // NGAP to CU-CP adapters + // NGAP to CU-CP adapters. ngap_cu_cp_adapter ngap_cu_cp_ev_notifier; - // Mobility manager to CU-CP adapter + // Mobility manager to CU-CP adapter. mobility_manager_adapter mobility_manager_ev_notifier; - // RRC DU to CU-CP adapters + // RRC DU to CU-CP adapter. rrc_du_cu_cp_adapter rrc_du_cu_cp_notifier; // DU connections being managed by the CU-CP. diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 7782e7ca5d..9933f3b978 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -58,7 +58,7 @@ class cu_cp_ngap_handler : public cu_cp_ue_context_release_handler, public cu_cp /// \returns Pointer to the NGAP UE notifier. virtual ngap_cu_cp_ue_notifier* handle_new_ngap_ue(ue_index_t ue_index) = 0; - /// \brief Initialize security context by selecting security algorithms and generating K_rrc_enc and K_rrc_int + /// \brief Initialize security context by selecting security algorithms and generating K_rrc_enc and K_rrc_int. /// \param[in] ue_index Index of the UE. /// \param[in] sec_ctxt The received security context. /// \return True if the security context was successfully initialized, false otherwise. @@ -99,11 +99,14 @@ class cu_cp_ngap_handler : public cu_cp_ue_context_release_handler, public cu_cp /// \returns True if the Handover Command was successfully handled, false otherwise. virtual async_task handle_new_handover_command(ue_index_t ue_index, byte_buffer command) = 0; - /// \brief Handles UE index allocation request for N2 handover at target gNB + /// \brief Handles UE index allocation request for N2 handover at target gNB. virtual ue_index_t handle_ue_index_allocation_request(const nr_cell_global_id_t& cgi) = 0; + /// \brief Handles a DL UE associated NRPPa transport. + virtual void handle_dl_ue_associated_nrppa_transport_pdu(ue_index_t ue_index, const byte_buffer& nrppa_pdu) = 0; + /// \brief Handles a DL non UE associated NRPPa transport. - virtual void handle_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg) = 0; + virtual void handle_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) = 0; /// \brief Handle N2 AMF connection drop. virtual void handle_n2_disconnection() = 0; @@ -120,7 +123,7 @@ class cu_cp_e1ap_event_handler : public cu_cp_task_scheduler_handler virtual void handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) = 0; }; -/// Interface used to handle DU specific procedures +/// Interface used to handle DU specific procedures. class cu_cp_du_event_handler { public: @@ -204,7 +207,7 @@ class cu_cp_ue_context_manipulation_handler virtual void handle_handover_ue_context_push(ue_index_t source_ue_index, ue_index_t target_ue_index) = 0; }; -/// Methods used by CU-CP to transfer the RRC UE context e.g. for RRC Reestablishments +/// Methods used by CU-CP to transfer the RRC UE context e.g. for RRC Reestablishments. class cu_cp_rrc_ue_context_transfer_notifier { public: @@ -214,7 +217,7 @@ class cu_cp_rrc_ue_context_transfer_notifier virtual rrc_ue_reestablishment_context_response on_rrc_ue_context_transfer() = 0; }; -/// Interface to handle measurement requests +/// Interface to handle measurement requests. class cu_cp_measurement_handler { public: @@ -233,7 +236,7 @@ class cu_cp_measurement_handler virtual void handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) = 0; }; -/// Interface to handle measurement config update requests +/// Interface to handle measurement config update requests. class cu_cp_measurement_config_handler { public: @@ -259,7 +262,7 @@ class cu_cp_mobility_manager_handler du_index_t& target_du_index) = 0; }; -/// Interface to handle ue removals +/// Interface to handle ue removals. class cu_cp_ue_removal_handler { public: diff --git a/lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.cpp b/lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.cpp deleted file mode 100644 index 2c1336a995..0000000000 --- a/lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.cpp +++ /dev/null @@ -1,26 +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 "dl_non_ue_associated_nrppa_transport_routine.h" - -using namespace srsran; -using namespace srsran::srs_cu_cp; - -SRSRAN_WEAK_SYMB async_task -srsran::srs_cu_cp::start_ngap_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg, - srslog::basic_logger& logger) -{ - logger.error("DL non UE associated NRPPa transport failed. Cause: NRPPa transport messages not supported."); - auto err_function = [](coro_context>& ctx) { - CORO_BEGIN(ctx); - CORO_RETURN(); - }; - return launch_async(std::move(err_function)); -} diff --git a/lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.h b/lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.h deleted file mode 100644 index fda6dd1a81..0000000000 --- a/lib/cu_cp/routines/dl_non_ue_associated_nrppa_transport_routine.h +++ /dev/null @@ -1,23 +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/ngap/ngap_nrppa.h" -#include "srsran/support/async/async_task.h" - -namespace srsran { -namespace srs_cu_cp { - -async_task start_ngap_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg, - srslog::basic_logger& logger); - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/lib/ngap/CMakeLists.txt b/lib/ngap/CMakeLists.txt index 900f16362f..c5564e7d49 100644 --- a/lib/ngap/CMakeLists.txt +++ b/lib/ngap/CMakeLists.txt @@ -25,7 +25,6 @@ set(SOURCES procedures/ngap_handover_preparation_procedure.cpp procedures/ngap_handover_resource_allocation_procedure.cpp procedures/ngap_ue_context_release_procedure.cpp - procedures/ngap_dl_ue_associated_nrppa_transport_procedure.cpp ) diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index e829066bcc..6989339913 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -20,7 +20,6 @@ #include "srsran/ngap/ngap_handover.h" #include "srsran/ngap/ngap_init_context_setup.h" #include "srsran/ngap/ngap_nas.h" -#include "srsran/ngap/ngap_nrppa.h" #include "srsran/ngap/ngap_reset.h" #include "srsran/ngap/ngap_setup.h" #include "srsran/ngap/ngap_types.h" @@ -1117,46 +1116,5 @@ fill_asn1_handover_notify(asn1::ngap::ho_notify_s& asn1_msg, const nr_cell_globa user_loc_info_nr.tai.tac.from_number(tac); } -/// \brief Convert DL UE Associated NRPPa Transport ASN1 struct to common type. -/// \param[out] msg The ngap_ue_associated_nrppa_transport struct to fill. -/// \param[in] asn1_msg The DL UE Associated NRPPa Transport ASN1 struct. -inline void fill_dl_ue_associated_nrppa_transport(ngap_ue_associated_nrppa_transport& msg, - const asn1::ngap::dl_ue_associated_nrppa_transport_s& asn1_msg) -{ - msg.routing_id = asn1_msg->routing_id.copy(); - msg.nrppa_pdu = asn1_msg->nrppa_pdu.copy(); -} - -/// \brief Convert common type UL UE Associated NRPPa Transport struct to ASN.1. -/// \param[out] asn1_msg The DL UE Associated NRPPa Transport ASN1 struct to fill. -/// \param[in] msg The common type ngap_ue_associated_nrppa_transport struct. -inline void fill_ul_ue_associated_nrppa_transport(asn1::ngap::ul_ue_associated_nrppa_transport_s& asn1_msg, - const ngap_ue_associated_nrppa_transport& msg) -{ - asn1_msg->routing_id = msg.routing_id.copy(); - asn1_msg->nrppa_pdu = msg.nrppa_pdu.copy(); -} - -/// \brief Convert DL Non UE Associated NRPPa Transport ASN1 struct to common type. -/// \param[out] msg The ngap_ue_associated_nrppa_transport struct to fill. -/// \param[in] asn1_msg The DL Non UE Associated NRPPa Transport ASN1 struct. -inline void -fill_dl_non_ue_associated_nrppa_transport(ngap_non_ue_associated_nrppa_transport& msg, - const asn1::ngap::dl_non_ue_associated_nrppa_transport_s& asn1_msg) -{ - msg.routing_id = asn1_msg->routing_id.copy(); - msg.nrppa_pdu = asn1_msg->nrppa_pdu.copy(); -} - -/// \brief Convert common type UL Non UE Associated NRPPa Transport struct to ASN.1. -/// \param[out] asn1_msg The DL Non UE Associated NRPPa Transport ASN1 struct to fill. -/// \param[in] msg The common type ngap_ue_associated_nrppa_transport struct. -inline void fill_ul_non_ue_associated_nrppa_transport(asn1::ngap::ul_non_ue_associated_nrppa_transport_s& asn1_msg, - const ngap_non_ue_associated_nrppa_transport& msg) -{ - asn1_msg->routing_id = msg.routing_id.copy(); - asn1_msg->nrppa_pdu = msg.nrppa_pdu.copy(); -} - } // namespace srs_cu_cp } // namespace srsran diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 6834b0b05c..3008a43350 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -16,7 +16,6 @@ #include "procedures/ng_reset_procedure.h" #include "procedures/ng_setup_procedure.h" #include "procedures/ngap_dl_nas_message_transfer_procedure.h" -#include "procedures/ngap_dl_ue_associated_nrppa_transport_procedure.h" #include "procedures/ngap_handover_preparation_procedure.h" #include "procedures/ngap_handover_resource_allocation_procedure.h" #include "procedures/ngap_initial_context_setup_procedure.h" @@ -770,53 +769,16 @@ void ngap_impl::handle_handover_request(const asn1::ngap::ho_request_s& msg) } } -void ngap_impl::handle_dl_ue_associated_nrppa_transport(const asn1::ngap::dl_ue_associated_nrppa_transport_s& msg) +SRSRAN_WEAK_SYMB void +ngap_impl::handle_dl_ue_associated_nrppa_transport(const asn1::ngap::dl_ue_associated_nrppa_transport_s& msg) { - if (!ue_ctxt_list.contains(uint_to_ran_ue_id(msg->ran_ue_ngap_id))) { - logger.warning("ran_ue={} amf_ue={}: Dropping DlUeAssociatedNrppaTransport. UE context does not exist", - msg->ran_ue_ngap_id, - msg->amf_ue_ngap_id); - send_error_indication(*tx_pdu_notifier, logger, {}, {}, ngap_cause_radio_network_t::unknown_local_ue_ngap_id); - return; - } - - ngap_ue_context& ue_ctxt = ue_ctxt_list[uint_to_ran_ue_id(msg->ran_ue_ngap_id)]; - - if (ue_ctxt.release_scheduled) { - ue_ctxt.logger.log_info("Dropping DlUeAssociatedNrppaTransport. UE is already scheduled for release"); - stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, - ue_ctxt.ue_ids.ran_ue_id, - uint_to_amf_ue_id(msg->amf_ue_ngap_id)}); - return; - } - - auto* ue = ue_ctxt.get_cu_cp_ue(); - srsran_assert(ue != nullptr, - "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", - ue_ctxt.ue_ids.ue_index, - ue_ctxt.ue_ids.ran_ue_id, - ue_ctxt.ue_ids.amf_ue_id); - - // Convert to common type. - ngap_ue_associated_nrppa_transport nrppa_transport; - nrppa_transport.ue_index = ue_ctxt.ue_ids.ue_index; - fill_dl_ue_associated_nrppa_transport(nrppa_transport, msg); - - // Start routine. - ue->schedule_async_task( - start_ngap_dl_ue_associated_nrppa_transport(nrppa_transport, cu_cp_notifier, *tx_pdu_notifier, ue_ctxt.logger)); + logger.info("DL UE associated NRPPa messages are not supported"); } -void ngap_impl::handle_dl_non_ue_associated_nrppa_transport( - const asn1::ngap::dl_non_ue_associated_nrppa_transport_s& msg) +SRSRAN_WEAK_SYMB void +ngap_impl::handle_dl_non_ue_associated_nrppa_transport(const asn1::ngap::dl_non_ue_associated_nrppa_transport_s& msg) { - // Convert to common type. - ngap_non_ue_associated_nrppa_transport nrppa_transport; - fill_dl_non_ue_associated_nrppa_transport(nrppa_transport, msg); - - // Forward to CU-CP. - cu_cp_notifier.on_dl_non_ue_associated_nrppa_transport(nrppa_transport); + logger.info("DL non UE associated NRPPa messages are not supported"); } void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) @@ -1026,6 +988,12 @@ void ngap_impl::handle_inter_cu_ho_rrc_recfg_complete(const ue_index_t tx_pdu_notifier->on_new_message(ngap_msg); } +SRSRAN_WEAK_SYMB void ngap_impl::handle_ul_ue_associated_nrppa_transport(ue_index_t ue_index, + const byte_buffer& nrppa_pdu) +{ + logger.info("UL UE associated NRPPa messages are not supported"); +} + void ngap_impl::remove_ue_context(ue_index_t ue_index) { if (!ue_ctxt_list.contains(ue_index)) { diff --git a/lib/ngap/ngap_impl.h b/lib/ngap/ngap_impl.h index 0587ec0ed8..dcf745e950 100644 --- a/lib/ngap/ngap_impl.h +++ b/lib/ngap/ngap_impl.h @@ -66,6 +66,7 @@ class ngap_impl final : public ngap_interface const nr_cell_global_id_t& cgi, const unsigned tac) override; const ngap_context_t& get_ngap_context() const override { return context; }; + void handle_ul_ue_associated_nrppa_transport(ue_index_t ue_index, const byte_buffer& nrppa_pdu) override; // ngap_statistics_handler size_t get_nof_ues() const override { return ue_ctxt_list.size(); } diff --git a/lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.cpp b/lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.cpp deleted file mode 100644 index 7995410512..0000000000 --- a/lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.cpp +++ /dev/null @@ -1,28 +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 "ngap_dl_ue_associated_nrppa_transport_procedure.h" - -using namespace srsran; -using namespace srsran::srs_cu_cp; - -SRSRAN_WEAK_SYMB async_task -srsran::srs_cu_cp::start_ngap_dl_ue_associated_nrppa_transport(const ngap_ue_associated_nrppa_transport& msg, - ngap_cu_cp_notifier& cu_cp_notifier, - ngap_message_notifier& amf_notifier, - ngap_ue_logger& logger) -{ - logger.log_error("DL UE associated NRPPa transport failed. Cause: NRPPa transport messages not supported."); - auto err_function = [](coro_context>& ctx) { - CORO_BEGIN(ctx); - CORO_RETURN(); - }; - return launch_async(std::move(err_function)); -} diff --git a/lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.h b/lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.h deleted file mode 100644 index 8cd8f92e6a..0000000000 --- a/lib/ngap/procedures/ngap_dl_ue_associated_nrppa_transport_procedure.h +++ /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. - * - */ - -#pragma once - -#include "ue_context/ngap_ue_logger.h" -#include "srsran/ngap/ngap.h" -#include "srsran/ngap/ngap_nrppa.h" -#include "srsran/support/async/async_task.h" - -namespace srsran { -namespace srs_cu_cp { - -async_task start_ngap_dl_ue_associated_nrppa_transport(const ngap_ue_associated_nrppa_transport& msg, - ngap_cu_cp_notifier& cu_cp_notifier, - ngap_message_notifier& amf_notifier, - ngap_ue_logger& logger); - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/tests/unittests/cu_cp/cu_cp_nrppa_test.cpp b/tests/unittests/cu_cp/cu_cp_nrppa_test.cpp index a1b52e40ae..3bd5b41f1e 100644 --- a/tests/unittests/cu_cp/cu_cp_nrppa_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_nrppa_test.cpp @@ -65,36 +65,6 @@ class cu_cp_nrppa_test : public cu_cp_test_environment, public ::testing::Test f1ap_message f1ap_pdu; e1ap_message e1ap_pdu; - [[nodiscard]] bool send_dl_ue_associated_nrppa_transport() - { - report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), - "there are still NGAP messages to pop from AMF"); - report_fatal_error_if_not(not this->get_du(du_idx).try_pop_dl_pdu(f1ap_pdu), - "there are still F1AP DL messages to pop from DU"); - report_fatal_error_if_not(not this->get_cu_up(cu_up_idx).try_pop_rx_pdu(e1ap_pdu), - "there are still E1AP messages to pop from CU-UP"); - - // Generate DL UE associated NRPPA transport message. - ngap_message ngap_msg; - ngap_msg.pdu.set_init_msg(); - ngap_msg.pdu.init_msg().load_info_obj(ASN1_NGAP_ID_DL_UE_ASSOCIATED_NRPPA_TRANSPORT); - auto& non_ue_nrppa = ngap_msg.pdu.init_msg().value.dl_ue_associated_nrppa_transport(); - non_ue_nrppa->amf_ue_ngap_id = amf_ue_id_to_uint(ue_ctx->amf_ue_id.value()); - non_ue_nrppa->ran_ue_ngap_id = ran_ue_id_to_uint(ue_ctx->ran_ue_id.value()); - non_ue_nrppa->routing_id = make_byte_buffer("30").value(); - non_ue_nrppa->nrppa_pdu = - make_byte_buffer( - "00060000006c000001000900654c000a000100000a000101000a000102000a000103000a000104000a000105000a000" - "106000a000107000a000108000a000109000a00010a000a00010b000a00010c000a00010d000a00010e000a00010f00" - "0a000110000a000111000a000112000a000113") - .value(); - - // Inject DL UE associated NRPPA transport message. - get_amf().push_tx_pdu(ngap_msg); - - return true; - } - [[nodiscard]] bool send_dl_non_ue_associated_nrppa_transport() { report_fatal_error_if_not(not this->get_amf().try_pop_rx_pdu(ngap_pdu), @@ -124,15 +94,6 @@ class cu_cp_nrppa_test : public cu_cp_test_environment, public ::testing::Test } }; -TEST_F(cu_cp_nrppa_test, when_dl_ue_nrppa_message_received_then_logging_it) -{ - // Inject DL UE associated NRPPA transport message. - ASSERT_TRUE(send_dl_ue_associated_nrppa_transport()); - - // Make sure that no UL UE associated NRPPA transport message is sent to the AMF. - ASSERT_FALSE(this->wait_for_ngap_tx_pdu(ngap_pdu)); -} - TEST_F(cu_cp_nrppa_test, when_dl_non_ue_nrppa_message_received_then_logging_it) { // Inject DL non UE associated NRPPA transport message. diff --git a/tests/unittests/ngap/test_helpers.h b/tests/unittests/ngap/test_helpers.h index a5e3801bc3..fb91fd78e1 100644 --- a/tests/unittests/ngap/test_helpers.h +++ b/tests/unittests/ngap/test_helpers.h @@ -354,9 +354,14 @@ class dummy_ngap_cu_cp_notifier : public ngap_cu_cp_notifier }); } - void on_dl_non_ue_associated_nrppa_transport(const ngap_non_ue_associated_nrppa_transport& msg) override + void on_dl_ue_associated_nrppa_transport_pdu(ue_index_t ue_index, const byte_buffer& nrppa_pdu) override { - logger.error("DL non UE associated NRPPa transport failed. Cause: NRPPa transport messages not supported."); + logger.error("DL UE associated NRPPa transport failed. Cause: NRPPa transport PDUs not supported."); + } + + void on_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) override + { + logger.error("DL non UE associated NRPPa transport failed. Cause: NRPPa transport PDUs not supported."); } ue_index_t last_ue = ue_index_t::invalid; From 32351d29e4df521253d4a7cb34d0d733c2905edc Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 22 Nov 2024 19:27:32 +0100 Subject: [PATCH 003/227] cu_cp,nrppa: add nrppa interface --- include/srsran/nrppa/nrppa.h | 69 ++++++++++++++++++++++++ lib/cu_cp/adapters/nrppa_adapters.h | 72 ++++++++++++++++++++++++++ lib/cu_cp/cu_cp_impl.cpp | 22 +++++++- lib/cu_cp/cu_cp_impl.h | 21 +++++++- lib/cu_cp/cu_cp_impl_interface.h | 20 +++++++ lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp | 1 + lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 7 +++ 7 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 include/srsran/nrppa/nrppa.h create mode 100644 lib/cu_cp/adapters/nrppa_adapters.h diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h new file mode 100644 index 0000000000..777bc454c3 --- /dev/null +++ b/include/srsran/nrppa/nrppa.h @@ -0,0 +1,69 @@ +/* + * + * 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/cu_cp/cu_cp_types.h" +#include "srsran/support/async/async_task.h" + +namespace srsran { +namespace srs_cu_cp { + +/// NRPPA notifier to the CU-CP UE +class nrppa_cu_cp_ue_notifier +{ +public: + virtual ~nrppa_cu_cp_ue_notifier() = default; + + /// \brief Get the UE index of the UE. + virtual ue_index_t get_ue_index() = 0; + + /// \brief Schedule an async task for the UE. + virtual bool schedule_async_task(async_task task) = 0; +}; + +/// Methods used by NRPPa to signal events to the CU-CP. +class nrppa_cu_cp_notifier +{ +public: + virtual ~nrppa_cu_cp_notifier() = default; + + /// \brief Notifies the CU-CP about a new NRPPA UE. + /// \param[in] ue_index The index of the new NRPPA UE. + /// \returns Pointer to the NRPPA UE notifier. + virtual nrppa_cu_cp_ue_notifier* on_new_nrppa_ue(ue_index_t ue_index) = 0; + + /// \brief Notifies about a NRPPa PDU. + /// \param[in] nrppa_pdu The NRPPa PDU. + /// \param[in] ue_index For UE associated messages the index of the UE. + virtual void on_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) = 0; +}; + +/// This interface is used to push NRPPA messages to the NRPPA interface. +class nrppa_message_handler +{ +public: + virtual ~nrppa_message_handler() = default; + + /// Handle the incoming NRPPA message. + virtual void handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) = 0; +}; + +/// Combined entry point for the NRPPA object. +class nrppa_interface : public nrppa_message_handler +{ +public: + virtual ~nrppa_interface() = default; + + virtual nrppa_message_handler& get_nrppa_message_handler() = 0; +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/cu_cp/adapters/nrppa_adapters.h b/lib/cu_cp/adapters/nrppa_adapters.h new file mode 100644 index 0000000000..97bc7ddf25 --- /dev/null +++ b/lib/cu_cp/adapters/nrppa_adapters.h @@ -0,0 +1,72 @@ +/* + * + * 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 "../cu_cp_impl_interface.h" +#include "../ue_manager/cu_cp_ue_impl_interface.h" +#include "srsran/cu_cp/ue_task_scheduler.h" +#include "srsran/nrppa/nrppa.h" + +namespace srsran { +namespace srs_cu_cp { + +/// Adapter between NRPPa and CU-CP +class nrppa_cu_cp_adapter : public nrppa_cu_cp_notifier +{ +public: + nrppa_cu_cp_adapter() = default; + + void connect_cu_cp(cu_cp_nrppa_handler& cu_cp_handler_) { cu_cp_handler = &cu_cp_handler_; } + + nrppa_cu_cp_ue_notifier* on_new_nrppa_ue(ue_index_t ue_index) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NRPPA handler must not be nullptr"); + return cu_cp_handler->handle_new_nrppa_ue(ue_index); + } + + void on_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NRPPA handler must not be nullptr"); + cu_cp_handler->handle_ul_nrppa_pdu(nrppa_pdu, ue_index); + } + +private: + cu_cp_nrppa_handler* cu_cp_handler = nullptr; +}; + +/// Adapter between NRPPA and CU-CP UE +class nrppa_cu_cp_ue_adapter : public nrppa_cu_cp_ue_notifier +{ +public: + nrppa_cu_cp_ue_adapter() = default; + + void connect_ue(cu_cp_ue_impl_interface& ue_) { ue = &ue_; } + + /// \brief Get the UE index of the UE. + ue_index_t get_ue_index() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_ue_index(); + } + + /// \brief Schedule an async task for the UE. + bool schedule_async_task(async_task task) override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_task_sched().schedule_async_task(std::move(task)); + } + +private: + cu_cp_ue_impl_interface* ue = nullptr; +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 51c7f99491..8e61e936cd 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -25,6 +25,7 @@ #include "routines/ue_transaction_info_release_routine.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" +#include "srsran/nrppa/nrppa.h" #include "srsran/rrc/rrc_du.h" #include #include @@ -67,8 +68,11 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : { assert_cu_cp_configuration_valid(cfg); + nrppa_entity = create_nrppa_entity(cfg, nrppa_cu_cp_ev_notifier); + // connect event notifiers to layers - ngap_cu_cp_ev_notifier.connect_cu_cp(*this, paging_handler); + ngap_cu_cp_ev_notifier.connect_cu_cp(get_cu_cp_ngap_handler(), paging_handler); + nrppa_cu_cp_ev_notifier.connect_cu_cp(get_cu_cp_nrppa_handler()); mobility_manager_ev_notifier.connect_cu_cp(get_cu_cp_mobility_manager_handler()); e1ap_ev_notifier.connect_cu_cp(get_cu_cp_e1ap_handler()); rrc_du_cu_cp_notifier.connect_cu_cp(get_cu_cp_measurement_config_handler()); @@ -149,6 +153,12 @@ bool cu_cp_impl::amfs_are_connected() return true; }; +SRSRAN_WEAK_SYMB std::unique_ptr +cu_cp_impl::create_nrppa_entity(const cu_cp_configuration& cu_cp_cfg, nrppa_cu_cp_notifier& cu_cp_notif) +{ + return nullptr; +} + void cu_cp_impl::handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) { if (msg.ue_inactive) { @@ -605,6 +615,16 @@ void cu_cp_impl::handle_n2_disconnection() // TODO } +SRSRAN_WEAK_SYMB nrppa_cu_cp_ue_notifier* cu_cp_impl::handle_new_nrppa_ue(ue_index_t ue_index) +{ + return nullptr; +} + +SRSRAN_WEAK_SYMB void cu_cp_impl::handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) +{ + logger.info("UL NRPPa messages are not supported"); +} + std::optional cu_cp_impl::handle_measurement_config_request(ue_index_t ue_index, nr_cell_identity nci, diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 8435980275..008abc6d7d 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -15,6 +15,7 @@ #include "adapters/e1ap_adapters.h" #include "adapters/mobility_manager_adapters.h" #include "adapters/ngap_adapters.h" +#include "adapters/nrppa_adapters.h" #include "adapters/rrc_du_adapters.h" #include "adapters/rrc_ue_adapters.h" #include "cu_cp_controller/cu_cp_controller.h" @@ -28,6 +29,7 @@ #include "srsran/e2/e2_cu.h" #include "srsran/e2/e2_cu_factory.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" +#include "srsran/nrppa/nrppa.h" #include "srsran/ran/plmn_identity.h" #include #include @@ -65,7 +67,11 @@ class cu_cp_impl final : public cu_cp, bool amfs_are_connected() override; - // CU-UP handler + // NRPPA interface. + std::unique_ptr create_nrppa_entity(const cu_cp_configuration& cu_cp_cfg, + nrppa_cu_cp_notifier& cu_cp_notif); + + // CU-UP handler. void handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) override; // cu_cp_rrc_ue_interface. @@ -102,6 +108,9 @@ class cu_cp_impl final : public cu_cp, void handle_dl_non_ue_associated_nrppa_transport_pdu(const byte_buffer& nrppa_pdu) override; void handle_n2_disconnection() override; + // cu_cp_nrppa_handler. + void handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override; + // cu_cp_measurement_handler. std::optional handle_measurement_config_request(ue_index_t ue_index, @@ -131,6 +140,7 @@ class cu_cp_impl final : public cu_cp, cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() override { return *this; } cu_cp_ng_handler& get_ng_handler() override { return *this; } cu_cp_ngap_handler& get_cu_cp_ngap_handler() override { return *this; } + cu_cp_nrppa_handler& get_cu_cp_nrppa_handler() override { return *this; } cu_cp_command_handler& get_command_handler() override { return *this; } cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() override { return *this; } cu_cp_measurement_handler& get_cu_cp_measurement_handler() override { return *this; } @@ -150,6 +160,9 @@ class cu_cp_impl final : public cu_cp, // NGAP UE creation handler. ngap_cu_cp_ue_notifier* handle_new_ngap_ue(ue_index_t ue_index) override; + // NRPPA UE creation handler. + nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) override; + // cu_cp_task_scheduler_handler. bool schedule_ue_task(ue_index_t ue_index, async_task task) override; @@ -196,6 +209,12 @@ class cu_cp_impl final : public cu_cp, // CU-UP connections being managed by the CU-CP. cu_up_processor_repository cu_up_db; + // NRPPa to CU-CP adapter. + nrppa_cu_cp_adapter nrppa_cu_cp_ev_notifier; + + // NRPPA entity. + std::unique_ptr nrppa_entity; + // Handler of paging messages. paging_message_handler paging_handler; diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 9933f3b978..3d8cbcf5df 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -15,6 +15,7 @@ #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/ngap/ngap.h" +#include "srsran/nrppa/nrppa.h" #include "srsran/rrc/rrc_du.h" #include "srsran/rrc/rrc_ue.h" #include @@ -112,6 +113,23 @@ class cu_cp_ngap_handler : public cu_cp_ue_context_release_handler, public cu_cp virtual void handle_n2_disconnection() = 0; }; +/// Interface for the NRPPa notifier to communicate with the CU-CP. +class cu_cp_nrppa_handler +{ +public: + virtual ~cu_cp_nrppa_handler() = default; + + /// \brief Handle the creation of a new NRPPA UE. This will add the NRPPA adapters to the UE manager. + /// \param[in] ue_index The index of the new NRPPA UE. + /// \returns Pointer to the NRPPA UE notifier. + virtual nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) = 0; + + /// \brief Handle a UL NRPPa PDU. + /// \param[in] msg The NRPPa PDU. + /// \param[in] ue_index For UE associated messages the index of the UE. + virtual void handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) = 0; +}; + /// Handler of E1AP-CU-CP events. class cu_cp_e1ap_event_handler : public cu_cp_task_scheduler_handler { @@ -282,6 +300,7 @@ class cu_cp_impl_interface : public cu_cp_e1ap_event_handler, public cu_cp_measurement_handler, public cu_cp_measurement_config_handler, public cu_cp_ngap_handler, + public cu_cp_nrppa_handler, public cu_cp_ue_context_manipulation_handler, public cu_cp_mobility_manager_handler, public cu_cp_ue_removal_handler @@ -291,6 +310,7 @@ class cu_cp_impl_interface : public cu_cp_e1ap_event_handler, virtual cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() = 0; virtual cu_cp_ngap_handler& get_cu_cp_ngap_handler() = 0; + virtual cu_cp_nrppa_handler& get_cu_cp_nrppa_handler() = 0; virtual cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() = 0; virtual cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() = 0; virtual cu_cp_measurement_handler& get_cu_cp_measurement_handler() = 0; diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp index d003e534c1..2959533b99 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp @@ -50,6 +50,7 @@ cu_cp_ue::cu_cp_ue(ue_index_t ue_index_, rrc_ue_cu_cp_ue_ev_notifier.connect_ue(*this); ngap_cu_cp_ue_ev_notifier.connect_ue(*this); + nrppa_cu_cp_ue_ev_notifier.connect_ue(*this); } /// \brief Update a UE with PCI and/or C-RNTI. diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index 153fd4bb18..27e41a648a 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -11,6 +11,7 @@ #pragma once #include "../adapters/ngap_adapters.h" +#include "../adapters/nrppa_adapters.h" #include "../adapters/rrc_ue_adapters.h" #include "../cell_meas_manager/measurement_context.h" #include "../ue_security_manager/ue_security_manager_impl.h" @@ -108,6 +109,9 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \brief Get the NGAP CU-CP UE notifier of the UE. ngap_cu_cp_ue_notifier& get_ngap_cu_cp_ue_notifier() { return ngap_cu_cp_ue_ev_notifier; } + /// \brief Get the NRPPA CU-CP UE notifier of the UE. + nrppa_cu_cp_ue_notifier& get_nrppa_cu_cp_ue_notifier() { return nrppa_cu_cp_ue_ev_notifier; } + /// \brief Get the RRC UE CU-CP UE notifier of the UE. rrc_ue_cu_cp_ue_notifier& get_rrc_ue_cu_cp_ue_notifier() { return rrc_ue_cu_cp_ue_ev_notifier; } @@ -150,6 +154,9 @@ class cu_cp_ue : public cu_cp_ue_impl_interface ngap_cu_cp_ue_adapter ngap_cu_cp_ue_ev_notifier; ngap_rrc_ue_adapter ngap_rrc_ue_ev_notifier; + // nrppa ue context + nrppa_cu_cp_ue_adapter nrppa_cu_cp_ue_ev_notifier; + // cu-cp ue context rrc_ue_cu_cp_adapter rrc_ue_cu_cp_ev_notifier; cell_meas_manager_ue_context meas_context; From bbad5e6ef8766fbc3551eea6b18b2ccbcbf1517a Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 22 Nov 2024 19:27:48 +0100 Subject: [PATCH 004/227] cu_cp,ngap: add unit test test helpers --- tests/test_doubles/ngap/ngap_test_message_validators.cpp | 7 +++++++ tests/test_doubles/ngap/ngap_test_message_validators.h | 2 ++ tests/unittests/cu_cp/cu_cp_test_environment.cpp | 1 + 3 files changed, 10 insertions(+) diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.cpp b/tests/test_doubles/ngap/ngap_test_message_validators.cpp index cf251d7738..63fb04eb1a 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.cpp +++ b/tests/test_doubles/ngap/ngap_test_message_validators.cpp @@ -119,6 +119,13 @@ bool srsran::test_helpers::is_valid_handover_cancel(const srs_cu_cp::ngap_messag return true; } +bool srsran::test_helpers::is_valid_ul_ue_associated_nrppa_transport(const srs_cu_cp::ngap_message& msg) +{ + TRUE_OR_RETURN(msg.pdu.type() == asn1::ngap::ngap_pdu_c::types_opts::init_msg); + TRUE_OR_RETURN(msg.pdu.init_msg().proc_code == ASN1_NGAP_ID_UL_UE_ASSOCIATED_NRPPA_TRANSPORT); + return true; +} + bool srsran::test_helpers::is_expected_pdu_session_resource_setup_response( const ngap_message& ngap_pdu, const std::vector& expected_pdu_sessions_to_setup, diff --git a/tests/test_doubles/ngap/ngap_test_message_validators.h b/tests/test_doubles/ngap/ngap_test_message_validators.h index ccd912e6eb..bfddc0a67e 100644 --- a/tests/test_doubles/ngap/ngap_test_message_validators.h +++ b/tests/test_doubles/ngap/ngap_test_message_validators.h @@ -51,6 +51,8 @@ bool is_valid_handover_required(const srs_cu_cp::ngap_message& msg); bool is_valid_handover_cancel(const srs_cu_cp::ngap_message& msg); +bool is_valid_ul_ue_associated_nrppa_transport(const srs_cu_cp::ngap_message& msg); + // Check if the NGAP PDU contains the expected PDU session setup response. bool is_expected_pdu_session_resource_setup_response( const srs_cu_cp::ngap_message& ngap_pdu, diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index c0a1aef43e..29f180957e 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -62,6 +62,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : // Initialize logging test_logger.set_level(srslog::basic_levels::debug); cu_cp_logger.set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("NRPPA").set_level(srslog::basic_levels::debug); srslog::fetch_basic_logger("PDCP").set_level(srslog::basic_levels::info); srslog::fetch_basic_logger("NGAP").set_hex_dump_max_size(32); srslog::fetch_basic_logger("RRC").set_hex_dump_max_size(32); From e2ca9a6cf733054d3d56f4dbaba8b56fb93ff4b9 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Sun, 24 Nov 2024 21:50:26 +0100 Subject: [PATCH 005/227] cu_cp: forward ue measurements to nrppa --- include/srsran/nrppa/nrppa.h | 16 ++++++++-- .../adapters/cell_meas_manager_adapters.h | 18 +++++++++++ .../cell_meas_manager_impl.cpp | 10 ++++++- .../cell_meas_manager_impl.h | 12 ++++++++ lib/cu_cp/cu_cp_impl.cpp | 12 ++++++-- lib/cu_cp/cu_cp_impl.h | 11 +++++-- lib/cu_cp/cu_cp_impl_interface.h | 30 +++++++++++++------ .../cell_meas_manager_test_helpers.cpp | 8 ++--- .../cell_meas_manager_test_helpers.h | 20 +++++++++---- 9 files changed, 112 insertions(+), 25 deletions(-) diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h index 777bc454c3..b0f059b138 100644 --- a/include/srsran/nrppa/nrppa.h +++ b/include/srsran/nrppa/nrppa.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/rrc/meas_types.h" #include "srsran/support/async/async_task.h" namespace srsran { @@ -56,13 +57,24 @@ class nrppa_message_handler virtual void handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) = 0; }; +/// This interface is used to push UE measurements to the NRPPA interface. +class nrppa_measurement_handler +{ +public: + virtual ~nrppa_measurement_handler() = default; + + /// Handle the incoming UE measurement. + virtual void handle_ue_measurement(ue_index_t ue_index, const rrc_meas_results& meas_result) = 0; +}; + /// Combined entry point for the NRPPA object. -class nrppa_interface : public nrppa_message_handler +class nrppa_interface : public nrppa_message_handler, public nrppa_measurement_handler { public: virtual ~nrppa_interface() = default; - virtual nrppa_message_handler& get_nrppa_message_handler() = 0; + virtual nrppa_message_handler& get_nrppa_message_handler() = 0; + virtual nrppa_measurement_handler& get_nrppa_measurement_handler() = 0; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/adapters/cell_meas_manager_adapters.h b/lib/cu_cp/adapters/cell_meas_manager_adapters.h index 2902524cf1..194e5345d9 100644 --- a/lib/cu_cp/adapters/cell_meas_manager_adapters.h +++ b/lib/cu_cp/adapters/cell_meas_manager_adapters.h @@ -37,5 +37,23 @@ class cell_meas_mobility_manager_adapter : public cell_meas_mobility_manager_not mobility_manager_measurement_handler* handler = nullptr; }; +/// Adapter between cell measurement manager and CU-CP. +class cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier +{ +public: + cell_meas_manager_cu_cp_adapter() = default; + + void connect_cu_cp(cu_cp_positioning_measurement_handler& handler_) { handler = &handler_; } + + void on_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_result) override + { + srsran_assert(handler != nullptr, "Positioning measurement handler must not be nullptr"); + handler->handle_valid_ue_measurement(ue_index, meas_result); + } + +private: + cu_cp_positioning_measurement_handler* handler = nullptr; +}; + } // namespace srs_cu_cp } // namespace srsran 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 bc3c90e2cb..523a7db608 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 @@ -20,8 +20,13 @@ using namespace srs_cu_cp; cell_meas_manager::cell_meas_manager(const cell_meas_manager_cfg& cfg_, cell_meas_mobility_manager_notifier& mobility_mng_notifier_, + cell_meas_manager_cu_cp_notifier& cu_cp_notifier_, ue_manager& ue_mng_) : - cfg(cfg_), mobility_mng_notifier(mobility_mng_notifier_), ue_mng(ue_mng_), logger(srslog::fetch_basic_logger("CU-CP")) + cfg(cfg_), + mobility_mng_notifier(mobility_mng_notifier_), + cu_cp_notifier(cu_cp_notifier_), + ue_mng(ue_mng_), + logger(srslog::fetch_basic_logger("CU-CP")) { srsran_assert(is_valid_configuration(cfg, ssb_freq_to_meas_object), "Invalid cell measurement configuration"); generate_measurement_objects_for_serving_cells(); @@ -200,6 +205,9 @@ void cell_meas_manager::report_measurement(ue_index_t ue_index, const rrc_meas_r auto& meas_ctxt = ue_meas_context.meas_id_to_meas_context.at(meas_results.meas_id); + // Forward measurement to CU-CP. + cu_cp_notifier.on_valid_ue_measurement(ue_index, meas_results); + // Ignore id with periodic measurements. // For meas_id with e.g. A3 event configured: diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index b105a95512..34d7aa7313 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -33,12 +33,23 @@ class cell_meas_mobility_manager_notifier pci_t neighbor_pci) = 0; }; +/// Methods used by cell measurement manager to signal measurement events to the positioning manager. +class cell_meas_manager_cu_cp_notifier +{ +public: + virtual ~cell_meas_manager_cu_cp_notifier() = default; + + /// \brief Notifies about a valid UE measurement. + virtual void on_valid_ue_measurement(ue_index_t ue_index, const rrc_meas_results& meas_result) = 0; +}; + /// Basic cell manager implementation class cell_meas_manager { public: cell_meas_manager(const cell_meas_manager_cfg& cfg_, cell_meas_mobility_manager_notifier& mobility_mng_notifier_, + cell_meas_manager_cu_cp_notifier& cu_cp_notifier_, ue_manager& ue_mng_); ~cell_meas_manager() = default; @@ -57,6 +68,7 @@ class cell_meas_manager cell_meas_manager_cfg cfg; cell_meas_mobility_manager_notifier& mobility_mng_notifier; + cell_meas_manager_cu_cp_notifier& cu_cp_notifier; ue_manager& ue_mng; std::unordered_map diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 8e61e936cd..d1c4171d73 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -27,6 +27,7 @@ #include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/nrppa/nrppa.h" #include "srsran/rrc/rrc_du.h" +#include "srsran/support/compiler.h" #include #include #include @@ -51,7 +52,7 @@ static void assert_cu_cp_configuration_valid(const cu_cp_configuration& cfg) cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : cfg(config_), ue_mng(cfg), - cell_meas_mng(cfg.mobility.meas_manager_config, cell_meas_ev_notifier, ue_mng), + cell_meas_mng(cfg.mobility.meas_manager_config, cell_meas_mobility_notifier, cell_meas_ev_notifier, ue_mng), du_db(du_repository_config{cfg, *this, get_cu_cp_ue_removal_handler(), @@ -76,6 +77,7 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : mobility_manager_ev_notifier.connect_cu_cp(get_cu_cp_mobility_manager_handler()); e1ap_ev_notifier.connect_cu_cp(get_cu_cp_e1ap_handler()); rrc_du_cu_cp_notifier.connect_cu_cp(get_cu_cp_measurement_config_handler()); + cell_meas_ev_notifier.connect_cu_cp(get_cu_cp_positioning_measurement_handler()); ngap_db = std::make_unique( ngap_repository_config{cfg, get_cu_cp_ngap_handler(), paging_handler, srslog::fetch_basic_logger("CU-CP")}); @@ -86,7 +88,7 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : mobility_mng = create_mobility_manager( cfg.mobility.mobility_manager_config, mobility_manager_ev_notifier, *ngap_db, du_db, ue_mng); - cell_meas_ev_notifier.connect_mobility_manager(*mobility_mng); + cell_meas_mobility_notifier.connect_mobility_manager(*mobility_mng); // Start statistics report timer statistics_report_timer = cfg.services.timers->create_unique_timer(*cfg.services.cu_cp_executor); @@ -643,6 +645,12 @@ bool cu_cp_impl::handle_cell_config_update_request(nr_cell_identity nci, const s return cell_meas_mng.update_cell_config(nci, serv_cell_cfg); } +SRSRAN_WEAK_SYMB void cu_cp_impl::handle_valid_ue_measurement(const ue_index_t ue_index, + const rrc_meas_results& meas_results) +{ + logger.info("NRPPa messages are not supported"); +} + async_task cu_cp_impl::handle_intra_cu_handover_request(const cu_cp_intra_cu_handover_request& request, du_index_t& source_du_index, diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 008abc6d7d..68b4f39793 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -121,6 +121,9 @@ class cu_cp_impl final : public cu_cp, // cu_cp_measurement_config_handler. bool handle_cell_config_update_request(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg) override; + // cu_cp_positioning_measurement_handler + void handle_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_results) override; + // cu_cp_mobility_manager_handler. async_task handle_intra_cu_handover_request(const cu_cp_intra_cu_handover_request& request, @@ -145,6 +148,7 @@ class cu_cp_impl final : public cu_cp, cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() override { return *this; } cu_cp_measurement_handler& get_cu_cp_measurement_handler() override { return *this; } cu_cp_measurement_config_handler& get_cu_cp_measurement_config_handler() override { return *this; } + cu_cp_positioning_measurement_handler& get_cu_cp_positioning_measurement_handler() override { return *this; } cu_cp_mobility_manager_handler& get_cu_cp_mobility_manager_handler() override { return *this; } cu_cp_ue_removal_handler& get_cu_cp_ue_removal_handler() override { return *this; } cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() override { return *this; } @@ -188,8 +192,11 @@ class cu_cp_impl final : public cu_cp, // DU repository to Node Manager adapter. du_processor_cu_cp_connection_adapter conn_notifier; - // Cell Measurement Manager to mobility manager adapters - cell_meas_mobility_manager_adapter cell_meas_ev_notifier; + // Cell Measurement Manager to mobility manager adapters. + cell_meas_mobility_manager_adapter cell_meas_mobility_notifier; + + // Cell Measurement Manager to positioning manager adapters. + cell_meas_manager_cu_cp_adapter cell_meas_ev_notifier; // E1AP to CU-CP adapter. e1ap_cu_cp_adapter e1ap_ev_notifier; diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 3d8cbcf5df..d4483083de 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -267,6 +267,16 @@ class cu_cp_measurement_config_handler const serving_cell_meas_config& serv_cell_cfg) = 0; }; +/// Interface to handle measurements for positioning. +class cu_cp_positioning_measurement_handler +{ +public: + virtual ~cu_cp_positioning_measurement_handler() = default; + + /// \brief Handle a valid UE measurement report. + virtual void handle_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_result) = 0; +}; + /// Interface to request handover. class cu_cp_mobility_manager_handler { @@ -299,6 +309,7 @@ class cu_cp_impl_interface : public cu_cp_e1ap_event_handler, public cu_cp_rrc_ue_interface, public cu_cp_measurement_handler, public cu_cp_measurement_config_handler, + public cu_cp_positioning_measurement_handler, public cu_cp_ngap_handler, public cu_cp_nrppa_handler, public cu_cp_ue_context_manipulation_handler, @@ -308,15 +319,16 @@ class cu_cp_impl_interface : public cu_cp_e1ap_event_handler, public: virtual ~cu_cp_impl_interface() = default; - virtual cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() = 0; - virtual cu_cp_ngap_handler& get_cu_cp_ngap_handler() = 0; - virtual cu_cp_nrppa_handler& get_cu_cp_nrppa_handler() = 0; - virtual cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() = 0; - virtual cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() = 0; - virtual cu_cp_measurement_handler& get_cu_cp_measurement_handler() = 0; - virtual cu_cp_measurement_config_handler& get_cu_cp_measurement_config_handler() = 0; - virtual cu_cp_mobility_manager_handler& get_cu_cp_mobility_manager_handler() = 0; - virtual cu_cp_ue_removal_handler& get_cu_cp_ue_removal_handler() = 0; + virtual cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() = 0; + virtual cu_cp_ngap_handler& get_cu_cp_ngap_handler() = 0; + virtual cu_cp_nrppa_handler& get_cu_cp_nrppa_handler() = 0; + virtual cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() = 0; + virtual cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() = 0; + virtual cu_cp_measurement_handler& get_cu_cp_measurement_handler() = 0; + virtual cu_cp_measurement_config_handler& get_cu_cp_measurement_config_handler() = 0; + virtual cu_cp_positioning_measurement_handler& get_cu_cp_positioning_measurement_handler() = 0; + virtual cu_cp_mobility_manager_handler& get_cu_cp_mobility_manager_handler() = 0; + virtual cu_cp_ue_removal_handler& get_cu_cp_ue_removal_handler() = 0; }; } // namespace srs_cu_cp diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp index d156cac51b..05749c3390 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp @@ -38,7 +38,7 @@ cell_meas_manager_test::~cell_meas_manager_test() void cell_meas_manager_test::create_empty_manager() { cell_meas_manager_cfg cfg = {}; - manager = std::make_unique(cfg, mobility_manager, ue_mng); + manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); ASSERT_NE(manager, nullptr); } @@ -141,7 +141,7 @@ void cell_meas_manager_test::create_default_manager() a3_report_cfg = event_trigger_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); - manager = std::make_unique(cfg, mobility_manager, ue_mng); + manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); ASSERT_NE(manager, nullptr); } @@ -222,7 +222,7 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r a3_report_cfg = event_trigger_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); - manager = std::make_unique(cfg, mobility_manager, ue_mng); + manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); ASSERT_NE(manager, nullptr); } @@ -279,7 +279,7 @@ void cell_meas_manager_test::create_manager_without_ncells_and_periodic_report() a3_report_cfg = event_trigger_cfg = {}; cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), a3_report_cfg); - manager = std::make_unique(cfg, mobility_manager, ue_mng); + manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); ASSERT_NE(manager, nullptr); } diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h index 9ab641bf75..58f838e88f 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h @@ -29,6 +29,15 @@ class dummy_mobility_manager : public cell_meas_mobility_manager_notifier } }; +class dummy_cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier +{ +public: + void on_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_result) override + { + fmt::print("on_valid_ue_measurement() called.\n"); + } +}; + /// Fixture class to create cell meas manager object. class cell_meas_manager_test : public ::testing::Test { @@ -48,11 +57,12 @@ class cell_meas_manager_test : public ::testing::Test srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP", false); - std::unique_ptr manager; - dummy_mobility_manager mobility_manager; - manual_task_worker ctrl_worker{128}; - timer_manager timers; - cu_cp_configuration cu_cp_cfg; + std::unique_ptr manager; + dummy_mobility_manager mobility_manager; + dummy_cell_meas_manager_cu_cp_adapter cu_cp_notifier; + manual_task_worker ctrl_worker{128}; + timer_manager timers; + cu_cp_configuration cu_cp_cfg; ue_manager ue_mng{cu_cp_cfg}; }; From d767c38042c30f5c6e0cb0fb4ad0f8fcf05fc47a Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 29 Nov 2024 20:35:18 +0100 Subject: [PATCH 006/227] cu_cp: improve cell meas manager to cu-cp measurement forwarding --- include/srsran/cu_cp/cell_meas_manager_config.h | 6 ++++-- include/srsran/nrppa/nrppa.h | 13 ++++++++++++- lib/cu_cp/adapters/cell_meas_manager_adapters.h | 2 +- .../cell_meas_manager/cell_meas_manager_impl.cpp | 9 ++++++++- .../cell_meas_manager/cell_meas_manager_impl.h | 5 ++++- lib/cu_cp/cu_cp_impl.cpp | 4 ++-- lib/cu_cp/cu_cp_impl.h | 3 ++- lib/cu_cp/cu_cp_impl_interface.h | 3 ++- lib/rrc/rrc_du_impl.cpp | 1 + .../cell_meas_manager_test_helpers.h | 2 +- 10 files changed, 37 insertions(+), 11 deletions(-) diff --git a/include/srsran/cu_cp/cell_meas_manager_config.h b/include/srsran/cu_cp/cell_meas_manager_config.h index 40766fdcd0..82cf23e109 100644 --- a/include/srsran/cu_cp/cell_meas_manager_config.h +++ b/include/srsran/cu_cp/cell_meas_manager_config.h @@ -13,6 +13,7 @@ #include "srsran/ran/band_helper.h" #include "srsran/ran/gnb_id.h" #include "srsran/ran/nr_cgi.h" +#include "srsran/ran/plmn_identity.h" #include "srsran/ran/subcarrier_spacing.h" #include "srsran/rrc/meas_types.h" #include @@ -27,8 +28,9 @@ namespace srs_cu_cp { /// Note that some optional values need to be provided by the DU upon F1Setup. struct serving_cell_meas_config { - nr_cell_identity nci; ///< The NR cell identifier. - unsigned gnb_id_bit_length; ///< gNodeB identifier bit length. + nr_cell_identity nci; ///< The NR cell identifier. + unsigned gnb_id_bit_length; ///< gNodeB identifier bit length. + plmn_identity plmn = plmn_identity::test_value(); ///< PLMN identity. /// If not set in config must be provided by config update after DU attach. std::optional pci; ///< Physical cell identifier. std::optional band; ///< NR band. diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h index b0f059b138..89117a77a1 100644 --- a/include/srsran/nrppa/nrppa.h +++ b/include/srsran/nrppa/nrppa.h @@ -57,6 +57,17 @@ class nrppa_message_handler virtual void handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) = 0; }; +struct cell_measurement_positioning_info { + struct cell_measurement_item_t { + nr_cell_global_id_t nr_cgi; + uint32_t nr_arfcn; + rrc_meas_result_nr meas_result; + }; + + nr_cell_global_id_t serving_cell_id; + std::map cell_measurements; +}; + /// This interface is used to push UE measurements to the NRPPA interface. class nrppa_measurement_handler { @@ -64,7 +75,7 @@ class nrppa_measurement_handler virtual ~nrppa_measurement_handler() = default; /// Handle the incoming UE measurement. - virtual void handle_ue_measurement(ue_index_t ue_index, const rrc_meas_results& meas_result) = 0; + virtual void handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; }; /// Combined entry point for the NRPPA object. diff --git a/lib/cu_cp/adapters/cell_meas_manager_adapters.h b/lib/cu_cp/adapters/cell_meas_manager_adapters.h index 194e5345d9..a2b3318970 100644 --- a/lib/cu_cp/adapters/cell_meas_manager_adapters.h +++ b/lib/cu_cp/adapters/cell_meas_manager_adapters.h @@ -45,7 +45,7 @@ class cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier void connect_cu_cp(cu_cp_positioning_measurement_handler& handler_) { handler = &handler_; } - void on_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_result) override + void on_valid_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override { srsran_assert(handler != nullptr, "Positioning measurement handler must not be nullptr"); handler->handle_valid_ue_measurement(ue_index, meas_result); 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 523a7db608..274c21879f 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 @@ -206,7 +206,7 @@ void cell_meas_manager::report_measurement(ue_index_t ue_index, const rrc_meas_r auto& meas_ctxt = ue_meas_context.meas_id_to_meas_context.at(meas_results.meas_id); // Forward measurement to CU-CP. - cu_cp_notifier.on_valid_ue_measurement(ue_index, meas_results); + send_positioning_measurement(ue_index, meas_results); // Ignore id with periodic measurements. @@ -290,6 +290,7 @@ void cell_meas_manager::update_measurement_object(nr_cell_identity } else { ssb_freq_to_ncis.emplace(ssb_freq, std::vector{nci}); } + nci_to_serving_cell_meas_config.emplace(serving_cell_cfg.nci, serving_cell_cfg); if (ssb_freq_to_meas_object.find(ssb_freq) != ssb_freq_to_meas_object.end()) { // If the measurement object is already present, we ignore the duplicate. @@ -298,3 +299,9 @@ void cell_meas_manager::update_measurement_object(nr_cell_identity } ssb_freq_to_meas_object.emplace(ssb_freq, generate_measurement_object(serving_cell_cfg)); } + +SRSRAN_WEAK_SYMB void cell_meas_manager::send_positioning_measurement(ue_index_t ue_index, + const rrc_meas_results& meas_results) +{ + logger.info("Positioning measurements are not supported"); +} diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index 34d7aa7313..d17b67ecb7 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -40,7 +40,7 @@ class cell_meas_manager_cu_cp_notifier virtual ~cell_meas_manager_cu_cp_notifier() = default; /// \brief Notifies about a valid UE measurement. - virtual void on_valid_ue_measurement(ue_index_t ue_index, const rrc_meas_results& meas_result) = 0; + virtual void on_valid_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; }; /// Basic cell manager implementation @@ -66,6 +66,8 @@ class cell_meas_manager void update_measurement_object(nr_cell_identity nci, const serving_cell_meas_config& serving_cell_cfg); + void send_positioning_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); + cell_meas_manager_cfg cfg; cell_meas_mobility_manager_notifier& mobility_mng_notifier; cell_meas_manager_cu_cp_notifier& cu_cp_notifier; @@ -74,6 +76,7 @@ class cell_meas_manager std::unordered_map ssb_freq_to_meas_object; // unique measurement objects, indexed by SSB frequency. std::unordered_map> ssb_freq_to_ncis; + std::map nci_to_serving_cell_meas_config; srslog::basic_logger& logger; }; diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index d1c4171d73..6aa208f221 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -645,8 +645,8 @@ bool cu_cp_impl::handle_cell_config_update_request(nr_cell_identity nci, const s return cell_meas_mng.update_cell_config(nci, serv_cell_cfg); } -SRSRAN_WEAK_SYMB void cu_cp_impl::handle_valid_ue_measurement(const ue_index_t ue_index, - const rrc_meas_results& meas_results) +SRSRAN_WEAK_SYMB void cu_cp_impl::handle_valid_ue_measurement(const ue_index_t ue_index, + const cell_measurement_positioning_info& meas_result) { logger.info("NRPPa messages are not supported"); } diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 68b4f39793..ffe4453399 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -122,7 +122,8 @@ class cu_cp_impl final : public cu_cp, bool handle_cell_config_update_request(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg) override; // cu_cp_positioning_measurement_handler - void handle_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_results) override; + void handle_valid_ue_measurement(const ue_index_t ue_index, + const cell_measurement_positioning_info& meas_result) override; // cu_cp_mobility_manager_handler. async_task diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index d4483083de..8817f3976f 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -274,7 +274,8 @@ class cu_cp_positioning_measurement_handler virtual ~cu_cp_positioning_measurement_handler() = default; /// \brief Handle a valid UE measurement report. - virtual void handle_valid_ue_measurement(const ue_index_t ue_index, const rrc_meas_results& meas_result) = 0; + virtual void handle_valid_ue_measurement(const ue_index_t ue_index, + const cell_measurement_positioning_info& meas_result) = 0; }; /// Interface to request handover. diff --git a/lib/rrc/rrc_du_impl.cpp b/lib/rrc/rrc_du_impl.cpp index c0a73cbdc5..05796b6cde 100644 --- a/lib/rrc/rrc_du_impl.cpp +++ b/lib/rrc/rrc_du_impl.cpp @@ -68,6 +68,7 @@ bool rrc_du_impl::handle_served_cell_list(const std::vector Date: Fri, 29 Nov 2024 20:35:35 +0100 Subject: [PATCH 007/227] cu_cp: remove unused lookup --- lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp | 2 -- lib/cu_cp/cell_meas_manager/measurement_context.h | 6 ++---- 2 files changed, 2 insertions(+), 6 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 274c21879f..874b0633d5 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 @@ -88,8 +88,6 @@ std::optional cell_meas_manager::get_measurement_config(ue_index_t for (const auto& nci : ssb_freq_to_ncis.at(ssb_freq)) { ue_meas_context.nci_to_meas_obj_id.emplace(nci, meas_obj_to_add.meas_obj_id); } - // add ncis for meas obj id to helper lookup - ue_meas_context.meas_obj_id_to_ncis.emplace(meas_obj_to_add.meas_obj_id, ssb_freq_to_ncis.at(ssb_freq)); if (cell_config.serving_cell_cfg.ssb_arfcn.value() == ssb_freq && cell_config.periodic_report_cfg_id.has_value()) { logger.debug("ue={}: Adding periodic report config for nci={:#x}", ue_index, serving_nci); diff --git a/lib/cu_cp/cell_meas_manager/measurement_context.h b/lib/cu_cp/cell_meas_manager/measurement_context.h index 36985d5a4f..65a0ab9073 100644 --- a/lib/cu_cp/cell_meas_manager/measurement_context.h +++ b/lib/cu_cp/cell_meas_manager/measurement_context.h @@ -78,7 +78,6 @@ class cell_meas_manager_ue_context void clear_meas_obj_ids() { nci_to_meas_obj_id.clear(); - meas_obj_id_to_ncis.clear(); meas_obj_ids.clear(); // Mark zero index as occupied as the first valid meas obj ID is 1. @@ -88,9 +87,8 @@ class cell_meas_manager_ue_context slotted_array meas_ids; // 0 is reserved for invalid meas_id slotted_array meas_obj_ids; // 0 is reserved for invalid meas_obj_id - std::map meas_id_to_meas_context; - std::map nci_to_meas_obj_id; - std::map> meas_obj_id_to_ncis; + std::map meas_id_to_meas_context; + std::map nci_to_meas_obj_id; cell_meas_manager_ue_context() { From 542dbb754f0493aa6abed1d22306ecc347aee919 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 29 Nov 2024 20:55:40 +0100 Subject: [PATCH 008/227] cu_cp,f1ap,rrc: improve unit test helpers --- .../test_doubles/f1ap/f1ap_test_messages.cpp | 8 ++++--- tests/test_doubles/f1ap/f1ap_test_messages.h | 16 ++++++++++--- tests/test_doubles/rrc/CMakeLists.txt | 4 +++- .../rrc/rrc_packed_test_messages.cpp | 24 +++++++++++++++++++ .../rrc/rrc_packed_test_messages.h | 4 ++++ .../cu_cp/cu_cp_test_environment.cpp | 2 +- .../unittests/cu_cp/cu_cp_test_environment.h | 7 ++++-- 7 files changed, 55 insertions(+), 10 deletions(-) diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.cpp b/tests/test_doubles/f1ap/f1ap_test_messages.cpp index 8a07990d83..0ef009f929 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.cpp +++ b/tests/test_doubles/f1ap/f1ap_test_messages.cpp @@ -10,6 +10,7 @@ #include "f1ap_test_messages.h" #include "../pdcp/pdcp_pdu_generator.h" +#include "../rrc/rrc_packed_test_messages.h" #include "srsran/asn1/f1ap/common.h" #include "srsran/asn1/f1ap/f1ap_ies.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents.h" @@ -45,13 +46,14 @@ gnb_du_served_cells_item_s srsran::test_helpers::generate_served_cells_item(cons served_cells_item.served_cell_info.served_plmns.push_back(served_plmn); served_cells_item.served_cell_info.nr_mode_info.set_tdd(); - served_cells_item.served_cell_info.nr_mode_info.tdd().nr_freq_info.nr_arfcn = 626748; + served_cells_item.served_cell_info.nr_mode_info.tdd().nr_freq_info.nr_arfcn = info.nr_arfcn; freq_band_nr_item_s freq_band_nr_item; - freq_band_nr_item.freq_band_ind_nr = 78; + freq_band_nr_item.freq_band_ind_nr = static_cast(info.band); served_cells_item.served_cell_info.nr_mode_info.tdd().nr_freq_info.freq_band_list_nr.push_back(freq_band_nr_item); served_cells_item.served_cell_info.nr_mode_info.tdd().tx_bw.nr_scs.value = nr_scs_opts::scs30; served_cells_item.served_cell_info.nr_mode_info.tdd().tx_bw.nr_nrb.value = nr_nrb_opts::nrb51; - served_cells_item.served_cell_info.meas_timing_cfg.from_string("101105af4084"); + served_cells_item.served_cell_info.meas_timing_cfg = + create_meas_timing_cfg(info.meas_timing_cfg.carrier_freq, info.meas_timing_cfg.scs); served_cells_item.gnb_du_sys_info_present = true; served_cells_item.gnb_du_sys_info.mib_msg.from_string("01c586"); diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.h b/tests/test_doubles/f1ap/f1ap_test_messages.h index ca369d065f..cebb7ae34c 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.h +++ b/tests/test_doubles/f1ap/f1ap_test_messages.h @@ -17,10 +17,12 @@ #include "srsran/asn1/f1ap/f1ap_ies.h" #include "srsran/f1ap/f1ap_ue_id_types.h" #include "srsran/ran/gnb_du_id.h" +#include "srsran/ran/nr_band.h" #include "srsran/ran/nr_cgi.h" #include "srsran/ran/pci.h" #include "srsran/ran/rb_id.h" #include "srsran/ran/rnti.h" +#include "srsran/ran/subcarrier_spacing.h" namespace srsran { @@ -29,9 +31,17 @@ struct f1ap_message; namespace test_helpers { struct served_cell_item_info { - nr_cell_identity nci = nr_cell_identity::create(gnb_id_t{411, 22}, 0U).value(); - pci_t pci = 0; - unsigned tac = 7; + struct meas_timing_config { + uint32_t carrier_freq = 535930; + subcarrier_spacing scs = subcarrier_spacing::kHz30; + }; + + nr_cell_identity nci = nr_cell_identity::create(gnb_id_t{411, 22}, 0U).value(); + pci_t pci = 0; + unsigned tac = 7; + nr_band band = nr_band::n78; + uint32_t nr_arfcn = 626748; + meas_timing_config meas_timing_cfg; }; /// \brief Generate a dummy F1AP Served Cell Item. diff --git a/tests/test_doubles/rrc/CMakeLists.txt b/tests/test_doubles/rrc/CMakeLists.txt index 6656e85d46..1d106327a9 100644 --- a/tests/test_doubles/rrc/CMakeLists.txt +++ b/tests/test_doubles/rrc/CMakeLists.txt @@ -6,6 +6,8 @@ # the distribution. # +include_directories(../../..) + add_library(rrc_test_doubles rrc_test_messages.cpp rrc_test_message_validators.cpp rrc_packed_test_messages.cpp) set_target_properties(rrc_test_doubles PROPERTIES UNITY_BUILD ON) -target_link_libraries(rrc_test_doubles rrc_nr_asn1 srsran_support srslog) +target_link_libraries(rrc_test_doubles rrc_nr_asn1 srsran_rrc srsran_support srslog) diff --git a/tests/test_doubles/rrc/rrc_packed_test_messages.cpp b/tests/test_doubles/rrc/rrc_packed_test_messages.cpp index 63c427045f..0c4fa85e61 100644 --- a/tests/test_doubles/rrc/rrc_packed_test_messages.cpp +++ b/tests/test_doubles/rrc/rrc_packed_test_messages.cpp @@ -9,7 +9,9 @@ */ #include "rrc_packed_test_messages.h" +#include "lib/rrc/ue/rrc_measurement_types_asn1_converters.h" #include "srsran/asn1/rrc_nr/ho_prep_info.h" +#include "srsran/asn1/rrc_nr/meas_timing_cfg.h" using namespace srsran; @@ -26,3 +28,25 @@ byte_buffer srsran::create_ho_prep_info() } return byte_buffer{}; } + +byte_buffer srsran::create_meas_timing_cfg(uint32_t carrier_freq, subcarrier_spacing scs) +{ + asn1::rrc_nr::meas_timing_cfg_s asn1_meas_timing_cfg; + auto& meas_timing_conf = asn1_meas_timing_cfg.crit_exts.set_c1().set_meas_timing_conf(); + asn1::rrc_nr::meas_timing_s meas_timing_item; + meas_timing_item.freq_and_timing_present = true; + meas_timing_item.freq_and_timing.carrier_freq = carrier_freq; + meas_timing_item.freq_and_timing.ssb_subcarrier_spacing = srs_cu_cp::subcarrier_spacing_to_rrc_asn1(scs); + meas_timing_item.freq_and_timing.ssb_meas_timing_cfg.periodicity_and_offset.set_sf10() = 0; + meas_timing_item.freq_and_timing.ssb_meas_timing_cfg.dur = asn1::rrc_nr::ssb_mtc_s::dur_opts::sf5; + + meas_timing_conf.meas_timing.push_back(meas_timing_item); + + // pack. + byte_buffer pdu; + asn1::bit_ref bref{pdu}; + if (asn1_meas_timing_cfg.pack(bref) == asn1::SRSASN_SUCCESS) { + return pdu; + } + return byte_buffer{}; +} diff --git a/tests/test_doubles/rrc/rrc_packed_test_messages.h b/tests/test_doubles/rrc/rrc_packed_test_messages.h index cf800b169a..b8f1b53007 100644 --- a/tests/test_doubles/rrc/rrc_packed_test_messages.h +++ b/tests/test_doubles/rrc/rrc_packed_test_messages.h @@ -15,10 +15,14 @@ /// the RRC ASN.1 headers. #include "srsran/adt/byte_buffer.h" +#include "srsran/ran/subcarrier_spacing.h" namespace srsran { /// Generates a dummy RRC handoverPrepInformation as per TS 38.331. byte_buffer create_ho_prep_info(); +/// \brief Generates a dummy Measurement Timing Configuration. +byte_buffer create_meas_timing_cfg(uint32_t carrier_freq, subcarrier_spacing scs); + } // namespace srsran \ No newline at end of file diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.cpp b/tests/unittests/cu_cp/cu_cp_test_environment.cpp index 29f180957e..9158ba105d 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_environment.cpp @@ -95,7 +95,7 @@ cu_cp_test_environment::cu_cp_test_environment(cu_cp_test_env_params params_) : cu_cp_cfg.f1ap.json_log_enabled = true; // > Mobility config - cu_cp_cfg.mobility.mobility_manager_config.trigger_handover_from_measurements = true; + cu_cp_cfg.mobility.mobility_manager_config.trigger_handover_from_measurements = params.trigger_ho_from_measurements; { // > Meas manager config cell_meas_manager_cfg meas_mng_cfg; diff --git a/tests/unittests/cu_cp/cu_cp_test_environment.h b/tests/unittests/cu_cp/cu_cp_test_environment.h index a1473c0845..bd546c5771 100644 --- a/tests/unittests/cu_cp/cu_cp_test_environment.h +++ b/tests/unittests/cu_cp/cu_cp_test_environment.h @@ -41,11 +41,13 @@ struct cu_cp_test_env_params { 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{}}}}}}}}) : + std::vector{s_nssai_t{slice_service_type{1}, slice_differentiator{}}}}}}}}, + bool trigger_ho_from_measurements_ = true) : max_nof_cu_ups(max_nof_cu_ups_), max_nof_dus(max_nof_dus_), max_nof_ues(max_nof_ues_), - max_nof_drbs_per_ue(max_nof_drbs_per_ue_) + max_nof_drbs_per_ue(max_nof_drbs_per_ue_), + trigger_ho_from_measurements(trigger_ho_from_measurements_) { uint16_t amf_idx = 0; for (const auto& supported_tas : amf_config_) { @@ -58,6 +60,7 @@ struct cu_cp_test_env_params { unsigned max_nof_ues; unsigned max_nof_drbs_per_ue; std::map amf_configs; + bool trigger_ho_from_measurements; }; class cu_cp_test_environment From cfef96e0ea2a39b507d2d9e05e7ddb04c181d2cb Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 29 Nov 2024 20:55:52 +0100 Subject: [PATCH 009/227] cu_cp: improve function name --- lib/cu_cp/adapters/cell_meas_manager_adapters.h | 4 ++-- lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h | 4 ++-- lib/cu_cp/cu_cp_impl.cpp | 4 ++-- lib/cu_cp/cu_cp_impl.h | 3 +-- lib/cu_cp/cu_cp_impl_interface.h | 6 +++--- .../cell_meas_manager/cell_meas_manager_test_helpers.h | 4 ++-- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/cu_cp/adapters/cell_meas_manager_adapters.h b/lib/cu_cp/adapters/cell_meas_manager_adapters.h index a2b3318970..ec9d46d48f 100644 --- a/lib/cu_cp/adapters/cell_meas_manager_adapters.h +++ b/lib/cu_cp/adapters/cell_meas_manager_adapters.h @@ -45,10 +45,10 @@ class cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier void connect_cu_cp(cu_cp_positioning_measurement_handler& handler_) { handler = &handler_; } - void on_valid_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override + void on_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override { srsran_assert(handler != nullptr, "Positioning measurement handler must not be nullptr"); - handler->handle_valid_ue_measurement(ue_index, meas_result); + handler->handle_ue_measurement(ue_index, meas_result); } private: diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index d17b67ecb7..cc8fad4520 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -39,8 +39,8 @@ class cell_meas_manager_cu_cp_notifier public: virtual ~cell_meas_manager_cu_cp_notifier() = default; - /// \brief Notifies about a valid UE measurement. - virtual void on_valid_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; + /// \brief Notifies about a UE measurement. + virtual void on_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; }; /// Basic cell manager implementation diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 6aa208f221..2252cf4b58 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -645,8 +645,8 @@ bool cu_cp_impl::handle_cell_config_update_request(nr_cell_identity nci, const s return cell_meas_mng.update_cell_config(nci, serv_cell_cfg); } -SRSRAN_WEAK_SYMB void cu_cp_impl::handle_valid_ue_measurement(const ue_index_t ue_index, - const cell_measurement_positioning_info& meas_result) +SRSRAN_WEAK_SYMB void cu_cp_impl::handle_ue_measurement(const ue_index_t ue_index, + const cell_measurement_positioning_info& meas_result) { logger.info("NRPPa messages are not supported"); } diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index ffe4453399..de389cfa1b 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -122,8 +122,7 @@ class cu_cp_impl final : public cu_cp, bool handle_cell_config_update_request(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg) override; // cu_cp_positioning_measurement_handler - void handle_valid_ue_measurement(const ue_index_t ue_index, - const cell_measurement_positioning_info& meas_result) override; + void handle_ue_measurement(const ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override; // cu_cp_mobility_manager_handler. async_task diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 8817f3976f..f3c302784f 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -273,9 +273,9 @@ class cu_cp_positioning_measurement_handler public: virtual ~cu_cp_positioning_measurement_handler() = default; - /// \brief Handle a valid UE measurement report. - virtual void handle_valid_ue_measurement(const ue_index_t ue_index, - const cell_measurement_positioning_info& meas_result) = 0; + /// \brief Handle a UE measurement report. + virtual void handle_ue_measurement(const ue_index_t ue_index, + const cell_measurement_positioning_info& meas_result) = 0; }; /// Interface to request handover. diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h index 54c58d0aff..9afc8bbe5e 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h @@ -32,9 +32,9 @@ class dummy_mobility_manager : public cell_meas_mobility_manager_notifier class dummy_cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier { public: - void on_valid_ue_measurement(const ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override + void on_ue_measurement(const ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override { - fmt::print("on_valid_ue_measurement() called.\n"); + fmt::print("on_ue_measurement() called.\n"); } }; From 2509b41c7d160a81f27beca078d6d75b2561d932 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 2 Dec 2024 12:30:06 +0100 Subject: [PATCH 010/227] cu,gnb: make nrppa logger configurable but hidden --- apps/units/o_cu_cp/cu_cp/cu_cp_logger_registrator.h | 4 ++++ .../cu_cp/cu_cp_unit_config_cli11_schema.cpp | 1 + .../o_cu_cp/cu_cp/cu_cp_unit_config_yaml_writer.cpp | 1 + apps/units/o_cu_cp/cu_cp/cu_cp_unit_logger_config.h | 13 +++++++------ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_logger_registrator.h b/apps/units/o_cu_cp/cu_cp/cu_cp_logger_registrator.h index 4e84f9ce30..85e814e449 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_logger_registrator.h +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_logger_registrator.h @@ -40,6 +40,10 @@ inline void register_cu_cp_loggers(const cu_cp_unit_logger_config& log_cfg) ngap_logger.set_level(log_cfg.ngap_level); ngap_logger.set_hex_dump_max_size(log_cfg.hex_max_size); + auto& nrppa_logger = srslog::fetch_basic_logger("NRPPA", false); + nrppa_logger.set_level(log_cfg.nrppa_level); + nrppa_logger.set_hex_dump_max_size(log_cfg.hex_max_size); + auto& sec_logger = srslog::fetch_basic_logger("SEC", false); sec_logger.set_level(log_cfg.sec_level); sec_logger.set_hex_dump_max_size(log_cfg.hex_max_size); diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_cli11_schema.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_cli11_schema.cpp index 70ce396d9f..9c2197efce 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_cli11_schema.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_cli11_schema.cpp @@ -22,6 +22,7 @@ static void configure_cli11_log_args(CLI::App& app, cu_cp_unit_logger_config& lo app_services::add_log_option(app, log_params.pdcp_level, "--pdcp_level", "PDCP log level"); app_services::add_log_option(app, log_params.rrc_level, "--rrc_level", "RRC log level"); app_services::add_log_option(app, log_params.ngap_level, "--ngap_level", "NGAP log level"); + app_services::add_log_option(app, log_params.nrppa_level, "--nrppa_level", "NRPPA log level")->group(""); app_services::add_log_option(app, log_params.f1ap_level, "--f1ap_level", "F1AP log level"); app_services::add_log_option(app, log_params.cu_level, "--cu_level", "Log level for the CU"); app_services::add_log_option(app, log_params.sec_level, "--sec_level", "Security functions log level"); diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_yaml_writer.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_yaml_writer.cpp index 8c508dca24..e4c0da41c3 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_yaml_writer.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_yaml_writer.cpp @@ -255,6 +255,7 @@ static void fill_cu_cp_log_section(YAML::Node node, const cu_cp_unit_logger_conf node["pdcp_level"] = srslog::basic_level_to_string(config.pdcp_level); node["rrc_level"] = srslog::basic_level_to_string(config.rrc_level); node["ngap_level"] = srslog::basic_level_to_string(config.ngap_level); + node["nrppa_level"] = srslog::basic_level_to_string(config.nrppa_level); node["f1ap_level"] = srslog::basic_level_to_string(config.f1ap_level); node["cu_level"] = srslog::basic_level_to_string(config.cu_level); node["sec_level"] = srslog::basic_level_to_string(config.sec_level); diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_logger_config.h b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_logger_config.h index 7132776b6b..de33b64a5e 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_logger_config.h +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_logger_config.h @@ -16,12 +16,13 @@ namespace srsran { /// Configuration of logging functionalities. struct cu_cp_unit_logger_config { - srslog::basic_levels cu_level = srslog::basic_levels::warning; - srslog::basic_levels f1ap_level = srslog::basic_levels::warning; - srslog::basic_levels pdcp_level = srslog::basic_levels::warning; - srslog::basic_levels rrc_level = srslog::basic_levels::warning; - srslog::basic_levels ngap_level = srslog::basic_levels::warning; - srslog::basic_levels sec_level = srslog::basic_levels::warning; + srslog::basic_levels cu_level = srslog::basic_levels::warning; + srslog::basic_levels f1ap_level = srslog::basic_levels::warning; + srslog::basic_levels pdcp_level = srslog::basic_levels::warning; + srslog::basic_levels rrc_level = srslog::basic_levels::warning; + srslog::basic_levels ngap_level = srslog::basic_levels::warning; + srslog::basic_levels nrppa_level = srslog::basic_levels::warning; + srslog::basic_levels sec_level = srslog::basic_levels::warning; /// Maximum number of bytes to write when dumping hex arrays. int hex_max_size = 0; /// Enable JSON generation for the F1AP Tx and Rx PDUs. From e47bc08fe2ad2635ef421ac21ae0e8bbb938e03e Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 2 Dec 2024 12:50:01 +0100 Subject: [PATCH 011/227] cu_cp,nrppa: remove inheritance from interface --- include/srsran/nrppa/nrppa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h index 89117a77a1..e3445651a2 100644 --- a/include/srsran/nrppa/nrppa.h +++ b/include/srsran/nrppa/nrppa.h @@ -79,7 +79,7 @@ class nrppa_measurement_handler }; /// Combined entry point for the NRPPA object. -class nrppa_interface : public nrppa_message_handler, public nrppa_measurement_handler +class nrppa_interface { public: virtual ~nrppa_interface() = default; From ccdbfddd66456cb55ae9562b47e124321cbcdeba Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 2 Dec 2024 12:55:20 +0100 Subject: [PATCH 012/227] cu_cp,ngap: make lmf routing id a byte buffer --- include/srsran/ngap/ngap_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/srsran/ngap/ngap_context.h b/include/srsran/ngap/ngap_context.h index 93d367ddb5..8ec32df64b 100644 --- a/include/srsran/ngap/ngap_context.h +++ b/include/srsran/ngap/ngap_context.h @@ -29,7 +29,7 @@ struct ngap_context_t { std::vector served_guami_list; 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::string lmf_routing_id; + byte_buffer lmf_routing_id; std::vector get_supported_plmns() const { From 030f1fec3c5a96c6675cee17eb8a4ea92bcdb8a8 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 2 Dec 2024 12:19:54 +0100 Subject: [PATCH 013/227] cu_cp: fix build for unused notifier --- lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index cc8fad4520..a284e14446 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -68,10 +68,10 @@ class cell_meas_manager void send_positioning_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); - cell_meas_manager_cfg cfg; - cell_meas_mobility_manager_notifier& mobility_mng_notifier; - cell_meas_manager_cu_cp_notifier& cu_cp_notifier; - ue_manager& ue_mng; + cell_meas_manager_cfg cfg; + cell_meas_mobility_manager_notifier& mobility_mng_notifier; + [[maybe_unused]] cell_meas_manager_cu_cp_notifier& cu_cp_notifier; + ue_manager& ue_mng; std::unordered_map ssb_freq_to_meas_object; // unique measurement objects, indexed by SSB frequency. From 232788b6c564122962d3b2291a5db10caead63ce Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 2 Dec 2024 16:50:38 +0100 Subject: [PATCH 014/227] cu_cp: fix build for gcc --- lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.cpp | 1 + lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h | 8 ++++---- 2 files changed, 5 insertions(+), 4 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 874b0633d5..0635ca2bc0 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 @@ -301,5 +301,6 @@ void cell_meas_manager::update_measurement_object(nr_cell_identity SRSRAN_WEAK_SYMB void cell_meas_manager::send_positioning_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results) { + (void)&cu_cp_notifier; logger.info("Positioning measurements are not supported"); } diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index a284e14446..cc8fad4520 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -68,10 +68,10 @@ class cell_meas_manager void send_positioning_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); - cell_meas_manager_cfg cfg; - cell_meas_mobility_manager_notifier& mobility_mng_notifier; - [[maybe_unused]] cell_meas_manager_cu_cp_notifier& cu_cp_notifier; - ue_manager& ue_mng; + cell_meas_manager_cfg cfg; + cell_meas_mobility_manager_notifier& mobility_mng_notifier; + cell_meas_manager_cu_cp_notifier& cu_cp_notifier; + ue_manager& ue_mng; std::unordered_map ssb_freq_to_meas_object; // unique measurement objects, indexed by SSB frequency. From ae467a069fdb4a65c91d58b17892dbbc6c039894 Mon Sep 17 00:00:00 2001 From: Joaquim Broquetas Date: Mon, 2 Dec 2024 13:29:20 +0100 Subject: [PATCH 015/227] apps,du: allow fractional TA targets, increase max iq_scaling --- apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h | 2 +- .../o_du_high/du_high/du_high_config_cli11_schema.cpp | 2 +- .../split_7_2/helpers/ru_ofh_config_cli11_schema.cpp | 2 +- include/srsran/scheduler/config/scheduler_expert_config.h | 2 +- .../scheduler/config/scheduler_expert_config_factory.h | 2 +- lib/scheduler/ue_context/ta_manager.cpp | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 96145f8f59..2443b28ca9 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -69,7 +69,7 @@ struct du_high_unit_ta_sched_expert_config { /// \remark T_A is defined in TS 38.213, clause 4.2. int ta_cmd_offset_threshold = 1; /// Timing Advance target in units of TA. - int ta_target = 0; + float ta_target = 0.0F; /// UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid. float ta_update_measurement_ul_sinr_threshold = 0.0F; }; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 6301afc936..93da59451f 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -572,7 +572,7 @@ static void configure_cli11_ta_scheduler_expert_args(CLI::App& app, du_high_unit ->check(CLI::Range(-1, 31)); add_option(app, "--ta_target", ta_params.ta_target, "Timing Advance target in units of TA") ->capture_default_str() - ->check(CLI::Range(-30, 30)); + ->check(CLI::Range(-30.0, 30.0)); add_option(app, "--ta_update_measurement_ul_sinr_threshold", ta_params.ta_update_measurement_ul_sinr_threshold, diff --git a/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp b/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp index 925bc01411..b3958d6661 100644 --- a/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp @@ -155,7 +155,7 @@ static void configure_cli11_ru_ofh_base_cell_args(CLI::App& app, ru_ofh_unit_bas ->capture_default_str(); add_option(app, "--iq_scaling", config.iq_scaling, "IQ scaling factor") ->capture_default_str() - ->check(CLI::Range(0.0, 20.0)); + ->check(CLI::Range(0.0, 100.0)); // Callback function for validating that both compression method and bitwidth parameters were specified. auto validate_compression_input = [](CLI::App& cli_app, const std::string& direction) { diff --git a/include/srsran/scheduler/config/scheduler_expert_config.h b/include/srsran/scheduler/config/scheduler_expert_config.h index b8f7f37cae..f8cd678c5d 100644 --- a/include/srsran/scheduler/config/scheduler_expert_config.h +++ b/include/srsran/scheduler/config/scheduler_expert_config.h @@ -84,7 +84,7 @@ struct scheduler_ue_expert_config { /// /// Offsets the target TA measurements so the signal from the UE is kept delayed. This parameter is useful for /// avoiding negative TA when the UE is getting away. - int8_t ta_target; + float ta_target; /// UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid. float ta_update_measurement_ul_sinr_threshold; /// @} diff --git a/include/srsran/scheduler/config/scheduler_expert_config_factory.h b/include/srsran/scheduler/config/scheduler_expert_config_factory.h index 0162ee4af1..2925c3277a 100644 --- a/include/srsran/scheduler/config/scheduler_expert_config_factory.h +++ b/include/srsran/scheduler/config/scheduler_expert_config_factory.h @@ -47,7 +47,7 @@ inline scheduler_expert_config make_default_scheduler_expert_config() cfg.ue.enable_csi_rs_pdsch_multiplexing = true; cfg.ue.ta_measurement_slot_period = 80; cfg.ue.ta_cmd_offset_threshold = 1; - cfg.ue.ta_target = 0; + cfg.ue.ta_target = 0.0F; cfg.ue.ta_update_measurement_ul_sinr_threshold = 0.0F; cfg.log_broadcast_messages = true; diff --git a/lib/scheduler/ue_context/ta_manager.cpp b/lib/scheduler/ue_context/ta_manager.cpp index 852bec0321..6dba0da98a 100644 --- a/lib/scheduler/ue_context/ta_manager.cpp +++ b/lib/scheduler/ue_context/ta_manager.cpp @@ -109,9 +109,9 @@ int64_t ta_manager::compute_avg_n_ta_difference(uint8_t tag_id) unsigned ta_manager::compute_new_t_a(int64_t n_ta_diff) { - return static_cast(std::round(static_cast(n_ta_diff * pow2(to_numerology_value(ul_scs))) / - static_cast(16U * 64))) + - ta_cmd_offset_zero - expert_cfg.ta_target; + return static_cast( + std::round(static_cast(n_ta_diff * pow2(to_numerology_value(ul_scs))) / static_cast(16U * 64) + + static_cast(ta_cmd_offset_zero) - expert_cfg.ta_target)); } void ta_manager::reset_measurements(uint8_t tag_id) From 5917d3c7c07b80b7d38538caf48ff12f065e61c7 Mon Sep 17 00:00:00 2001 From: Pavel Harbanau Date: Mon, 2 Dec 2024 17:52:26 +0000 Subject: [PATCH 016/227] ofh,tests: fix stack-use-after-scope --- .../ofh/ofh_integration_test.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/integrationtests/ofh/ofh_integration_test.cpp b/tests/integrationtests/ofh/ofh_integration_test.cpp index 7e68cb5d11..fc37dc6938 100644 --- a/tests/integrationtests/ofh/ofh_integration_test.cpp +++ b/tests/integrationtests/ofh/ofh_integration_test.cpp @@ -285,13 +285,23 @@ class test_ether_receiver : public ether::receiver notifier = std::ref(notifier_); logger.debug("Test Ethernet receiver started"); } - void stop() override {} + + void stop() override + { + stop_requested.store(true, std::memory_order_relaxed); + + while (is_running.load(std::memory_order_relaxed)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } virtual void push_new_data(span frame) = 0; protected: srslog::basic_logger& logger; std::reference_wrapper notifier; + std::atomic is_running{false}; + std::atomic stop_requested{false}; }; /// Dummy Ethernet receiver that receives data from RU emulator and pushes them to the OFH receiver without using real @@ -306,9 +316,15 @@ class dummy_eth_receiver : public test_ether_receiver void push_new_data(span frame) override { + if (stop_requested.load(std::memory_order_relaxed)) { + return; + } + is_running.store(true, std::memory_order::memory_order_relaxed); + auto exp_buffer = buffer_pool.reserve(); if (!exp_buffer.has_value()) { logger.warning("Dummy Ethernet receiver: no buffer is available for receiving a packet"); + is_running.store(false, std::memory_order::memory_order_relaxed); return; } ether::ethernet_rx_buffer_impl buffer = std::move(exp_buffer.value()); @@ -316,6 +332,7 @@ class dummy_eth_receiver : public test_ether_receiver buffer.resize(frame.size()); notifier.get().on_new_frame(ether::unique_rx_buffer(std::move(buffer))); + is_running.store(false, std::memory_order::memory_order_relaxed); } private: @@ -1122,13 +1139,13 @@ int main(int argc, char** argv) auto dl_rg_pool = create_dl_resource_grid_pool(rg_factory, nof_prb); auto ul_rg_pool = create_ul_resource_grid_pool(rg_factory, nof_prb); + ether::ethernet_rx_buffer_pool buffer_pool(BUFFER_SIZE); worker_manager workers; dummy_rx_symbol_notifier rx_symbol_notifier; dummy_timing_notifier timing_notifier; test_gateway* tx_gateway; test_ether_receiver* eth_receiver; dummy_ru_error_notifier error_notifier; - ether::ethernet_rx_buffer_pool buffer_pool(BUFFER_SIZE); ru_ofh_configuration ru_cfg = generate_ru_config(); ru_ofh_dependencies ru_deps = generate_ru_dependencies( From 60e1df0624625e02c8674893fa8d66d5e2ae6a53 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 2 Dec 2024 19:10:11 +0100 Subject: [PATCH 017/227] gtpu,ngu: log status of reordering timer when SN falls out of Rx window --- lib/gtpu/gtpu_tunnel_ngu_rx_impl.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h b/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h index d93e2071d0..c0d69eea06 100644 --- a/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h +++ b/lib/gtpu/gtpu_tunnel_ngu_rx_impl.h @@ -145,7 +145,11 @@ class gtpu_tunnel_ngu_rx_impl : public gtpu_tunnel_base_rx // Check out-of-window if (!inside_rx_window(sn)) { - logger.log_warning("SN falls out of Rx window. sn={} pdu_len={} {}", sn, pdu_len, st); + logger.log_warning("SN falls out of Rx window. sn={} pdu_len={} {} reordering_timer_running={}", + sn, + pdu_len, + st, + reordering_timer.is_running()); gtpu_rx_sdu_info rx_sdu_info = {std::move(rx_sdu), pdu_session_info.qos_flow_id, sn}; deliver_sdu(rx_sdu_info); return; From f69bfab2f80df7758c1159d228a9d85858d515c6 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 2 Dec 2024 23:17:07 +0100 Subject: [PATCH 018/227] rrc: always pass UE meas report to measurement manager handling implemented in cells measurement manager. this fixes UE measurement handling if only a serving cell without ncells is configured. --- lib/rrc/ue/rrc_ue_message_handlers.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index 36ff40356f..d21f69a564 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -232,11 +232,8 @@ void rrc_ue_impl::handle_measurement_report(const asn1::rrc_nr::meas_report_s& m // Convert asn1 to common type. rrc_meas_results meas_results = asn1_to_measurement_results(msg.crit_exts.meas_report().meas_results, srslog::fetch_basic_logger("RRC")); - // Send measurement results to cell measurement manager only measurements are not empty. - if (meas_results.meas_result_neigh_cells.has_value() and - not meas_results.meas_result_neigh_cells->meas_result_list_nr.empty()) { - measurement_notifier.on_measurement_report(meas_results); - } + // Send measurement results to cell measurement manager. + measurement_notifier.on_measurement_report(meas_results); } void rrc_ue_impl::handle_dl_nas_transport_message(byte_buffer nas_pdu) From 63391ba5c040950ac270b551406bca8ba46fb083 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Tue, 3 Dec 2024 09:55:13 +0100 Subject: [PATCH 019/227] ci: viavi tests high_latency_diagnostics_enabled --- tests/e2e/tests/viavi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/tests/viavi.py b/tests/e2e/tests/viavi.py index 04c45a1ecb..7327baccff 100644 --- a/tests/e2e/tests/viavi.py +++ b/tests/e2e/tests/viavi.py @@ -359,6 +359,7 @@ def _test_viavi( "nof_antennas_dl": 4, "nof_antennas_ul": 1, "rlc_metrics": True, + "enable_high_latency_diagnostics": True, "warning_extra_regex": ( (r"(?!.*" + r")(?!.*".join(test_declaration.warning_allowlist) + r")") if test_declaration.warning_allowlist From d1d505f40edc272770cde5e18ba2de4c7d83c90a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 2 Dec 2024 18:26:02 +0100 Subject: [PATCH 020/227] ci,release: fix variables and inherit false --- .gitlab/ci/release.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.gitlab/ci/release.yml b/.gitlab/ci/release.yml index 0f14bb7549..d87748d559 100644 --- a/.gitlab/ci/release.yml +++ b/.gitlab/ci/release.yml @@ -148,6 +148,7 @@ update private branch: - git config --global filter.lfs.process "git-lfs filter-process --skip" - git config --global user.name "${CODEBOT_USERNAME}" - git config --global user.email "${CODEBOT_LONG_USERNAME}@noreply.gitlab.com" + - git config --global url."https://${PUBLIC_PUSH_TOKEN}@github.com/".insteadOf "git@github.com:" script: - git clone https://${CODEBOT_USERNAME}:${CODEBOT_TOKEN}@gitlab.com/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}.git ${CI_PROJECT_DIR} - cd ${CI_PROJECT_DIR} @@ -283,19 +284,21 @@ publish main: optional: false artifacts: false -publish maltab: +publish matlab: stage: public interruptible: false - variables: - ON_SCHEDULE: "true" - CI_DESCRIPTION: Release - NOTIFY_SLACK: "false" - SRSRAN_REPO_URL: https://${PUBLIC_PUSH_TOKEN}@github.com/${PUBLIC_REPO}.git - SRSRAN_COMMIT: $PUBLIC_BRANCH - DOCKER_BUILDER_VERSION: $DOCKER_BUILDER_VERSION rules: - if: *on_public_push + variables: &matlab_release_var + ON_SCHEDULE: "true" + CI_DESCRIPTION: Release + NOTIFY_SLACK: "false" + SRSRAN_REPO_URL: https://${PUBLIC_PUSH_TOKEN}@github.com/${PUBLIC_REPO}.git + SRSRAN_COMMIT: main + DOCKER_BUILDER_VERSION: $DOCKER_BUILDER_VERSION - if: *on_public_release + variables: + <<: *matlab_release_var needs: - job: publish main - job: builder version From 1f57f67e15d980a7681266bb5a2d6d263cb0cdc2 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Mon, 14 Oct 2024 15:03:18 +0200 Subject: [PATCH 021/227] ci: add testmode for acc100 --- .../e2e/retina_request_test_mode_acc100.yml | 49 ++++++++++ tests/e2e/pyproject.toml | 1 + tests/e2e/tests/test_mode.py | 33 ++++++- .../e2e/tests/test_mode/config_ru_acc100.yml | 95 +++++++++++++++++++ 4 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 .gitlab/ci/e2e/retina_request_test_mode_acc100.yml create mode 100644 tests/e2e/tests/test_mode/config_ru_acc100.yml diff --git a/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml b/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml new file mode 100644 index 0000000000..2f579aa22b --- /dev/null +++ b/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml @@ -0,0 +1,49 @@ +# +# Copyright 2013-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. +# + +- name: srs-gnb + type: gnb + image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + requirements: + arch: amd64 + cpu: + requests: 20 + limits: 20 + memory: + requests: "60G" + limits: "60G" + ephemeral-storage: + requests: "6G" + limits: "6G" + hugepages-1Gi: + requests: 8Gi + limits: 8Gi + resources: + - type: accelerator + model: acc100 + environment: + - PATH: ${PATH}:/builds/softwareradiosystems/srsgnb/build/apps/gnb + shared_files: + - local_path: ${GNB_BINARY_PATH} + remote_path: /usr/local/bin/gnb + is_executable: true + +- name: open5gs + type: 5gc + requirements: + arch: amd64 + cpu: + requests: 1 + memory: + requests: "4G" + ephemeral-storage: + requests: "6G" + limits: "6G" + image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} \ No newline at end of file diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index d7ba705db3..60841ea182 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -38,6 +38,7 @@ markers = [ "zmq_4x4_mimo", "zmq_srsue", "test_mode", + "test_mode_acc100", "test_mode_not_crash", "viavi", "viavi_manual", diff --git a/tests/e2e/tests/test_mode.py b/tests/e2e/tests/test_mode.py index a552faea99..a3fa3c0fed 100644 --- a/tests/e2e/tests/test_mode.py +++ b/tests/e2e/tests/test_mode.py @@ -140,6 +140,24 @@ def test_ue( ) +@mark.test_mode_acc100 +@mark.flaky( + reruns=2, + only_rerun=[_POD_ERROR], +) +def test_ru_acc100( + # Retina + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + # Clients + gnb: GNBStub, +): + """ + Run gnb in test mode ru dummy. + """ + _test_ru(retina_manager, retina_data, gnb, ru_config="config_ru_acc100.yml") + + @mark.test_mode @mark.flaky( reruns=2, @@ -155,7 +173,7 @@ def test_ru( """ Run gnb in test mode ru dummy. """ - _test_ru(retina_manager, retina_data, gnb) + _test_ru(retina_manager, retina_data, gnb, ru_config="config_ru.yml") @mark.test_mode_not_crash @@ -174,7 +192,15 @@ def test_ru_not_crash( Run gnb with sanitizers in test mode ru dummy. It ignores warnings and KOs, so it will fail if the gnb+sanitizer fails """ - _test_ru(retina_manager, retina_data, gnb, gnb_stop_timeout=150, warning_as_errors=False, fail_if_kos=False) + _test_ru( + retina_manager, + retina_data, + gnb, + ru_config="config_ru.yml", + gnb_stop_timeout=150, + warning_as_errors=False, + fail_if_kos=False, + ) # pylint: disable=too-many-arguments,too-many-positional-arguments @@ -185,6 +211,7 @@ def _test_ru( # Clients gnb: GNBStub, # Test + ru_config, nof_ant: int = 4, duration: int = 5 * 60, # Test extra params @@ -209,7 +236,7 @@ def _test_ru( "nof_antennas_ul": nof_ant, }, "templates": { - "cu": str(Path(__file__).joinpath("../test_mode/config_ru.yml").resolve()), + "cu": str(Path(__file__).joinpath(f"../test_mode/{ru_config}").resolve()), "du": tmp_file.name, "ru": tmp_file.name, }, diff --git a/tests/e2e/tests/test_mode/config_ru_acc100.yml b/tests/e2e/tests/test_mode/config_ru_acc100.yml new file mode 100644 index 0000000000..d846f46d06 --- /dev/null +++ b/tests/e2e/tests/test_mode/config_ru_acc100.yml @@ -0,0 +1,95 @@ +# +# 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. +# + +cu_up: + warn_on_drop: False + +buffer_pool: + nof_segments: 1048576 + +cell_cfg: + dl_arfcn: 381500 + band: 39 + channel_bandwidth_MHz: 100 + common_scs: 30 + plmn: "00101" + tac: 7 + pci: 1 + nof_antennas_dl: {{nof_antennas_dl}} + nof_antennas_ul: {{nof_antennas_ul}} + pdsch: + mcs_table: qam256 + pusch: + min_ue_mcs: 27 + mcs_table: qam256 + rv_sequence: 0 + tdd_ul_dl_cfg: + dl_ul_tx_period: 10 + nof_dl_slots: 7 + nof_ul_slots: 2 + csi: + csi_rs_period: 40 + ul_common: + max_ul_grants_per_slot: 64 + max_pucchs_per_slot: 63 + +cells: + - pci: 1 + - pci: 2 + +ru_dummy: + +test_mode: + test_ue: + rnti: 0x1234 + pdsch_active: true + pusch_active: true + ri: 4 + cqi: 15 + nof_ues: 1 + +expert_execution: + affinities: + low_priority_cpus: {{low_priority_cpus}} + {% if ru_timing_cpu %} + ru_timing_cpu: {{ ru_timing_cpu }} + {% endif %} + cell_affinities: + - l1_dl_cpus: {{l1_dl_cpus}} + l1_dl_pinning: mask + l1_ul_cpus: {{l1_ul_cpus}} + l1_ul_pinning: mask + l2_cell_cpus: {{l2_cell_cpus}} + l2_cell_pinning: mask + ru_cpus: {{ru_cpus}} + ru_pinning: mask + - l1_dl_cpus: {{l1_dl_cpus}} + l1_dl_pinning: mask + l1_ul_cpus: {{l1_ul_cpus}} + l1_ul_pinning: mask + l2_cell_cpus: {{l2_cell_cpus}} + l2_cell_pinning: mask + ru_cpus: {{ru_cpus}} + ru_pinning: mask + +hal: + bbdev_hwacc: + hwacc_type: {{ accelerator_model }} + id: {{ accelerator_id }} + pdsch_enc: + nof_hwacc: {{ accelerator_pdsch_enc_nof_hwacc }} + cb_mode: {{ accelerator_cb_mode }} + pusch_dec: + nof_hwacc: {{ accelerator_pusch_dec_nof_hwacc }} + ext_softbuffer: {{ accelerator_ext_softbuffer }} + harq_context_size: {{ accelerator_harq_context_size }} + eal_args: "--lcores {{ lcores_eal_args }} {{ accelerator_extra_eal_args }}" + +expert_phy: + max_proc_delay: 4 + pusch_dec_max_iterations: 2 From f3c9f29428622274197ca18ead16b55e9d01bbc4 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 2 Dec 2024 11:25:23 +0100 Subject: [PATCH 022/227] sched: minor fixes in the fallback scheduler --- .../ue_scheduling/ue_event_manager.cpp | 7 ++-- .../ue_scheduling/ue_fallback_scheduler.cpp | 35 ++++++++++++------- .../ue_scheduling/ue_fallback_scheduler.h | 2 +- .../ue_scheduling/fallback_scheduler_test.cpp | 2 +- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index b2c5f13175..7d458e0a6e 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -83,7 +83,7 @@ class ue_event_manager::ue_dl_buffer_occupancy_manager final : public scheduler_ auto& du_pcell = parent.du_cells[u.get_pcell().cell_index]; if (dl_bo.lcid == LCID_SRB0 or (u.get_pcell().is_in_fallback_mode() and dl_bo.lcid == LCID_SRB1)) { // Signal SRB fallback scheduler with the new SRB0/SRB1 buffer state. - du_pcell.fallback_sched->handle_dl_buffer_state_indication_srb( + du_pcell.fallback_sched->handle_dl_buffer_state_indication( dl_bo.ue_index, dl_bo.lcid == LCID_SRB0, sl, dl_bo.bs); } @@ -537,7 +537,10 @@ void ue_event_manager::handle_uci_indication(const uci_indication& ind) if (pucch_f0f1->sr_detected) { // Handle SR indication. ue_db[ue_cc.ue_index].handle_sr_indication(); - du_cells[ue_cc.cell_index].fallback_sched->handle_sr_indication(ue_cc.ue_index); + + if (ue_cc.is_in_fallback_mode()) { + du_cells[ue_cc.cell_index].fallback_sched->handle_sr_indication(ue_cc.ue_index); + } // Log SR event. du_cells[ue_cc.cell_index].ev_logger->enqueue( diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index f23aabb57c..d934e5bc45 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -95,23 +95,27 @@ void ue_fallback_scheduler::run_slot(cell_resource_allocator& res_alloc) schedule_dl_new_tx_srb1(res_alloc); } -void ue_fallback_scheduler::handle_dl_buffer_state_indication_srb(du_ue_index_t ue_index, - bool is_srb0, - slot_point sl, - unsigned srb_buffer_bytes) +void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_index, + bool is_srb0, + slot_point sl, + unsigned srb_buffer_bytes) { if (not ues.contains(ue_index)) { logger.error("ue_index={} not found in the scheduler", ue_index); return; } + ue& u = ues[ue_index]; + if (not u.get_pcell().is_in_fallback_mode()) { + logger.error("Discarding DL buffer state indication in fallback scheduler. Cause: ue_index={} not in fallback mode", + ue_index); + return; + } auto ue_it = std::find_if( pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_index, is_srb0](const fallback_ue& ue) { return ue.ue_index == ue_index and (not ue.is_srb0.has_value() or ue.is_srb0.value() == is_srb0); }); - ue& u = ues[ue_index]; - if (ue_it != pending_dl_ues_new_tx.end()) { // This case can happen when ConRes indication is received first and then receive Msg4 indication from upper layers. if (not ue_it->is_srb0.has_value()) { @@ -140,11 +144,13 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication_srb(du_ue_index_t void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) { - if (not ues.contains(ue_index)) { - logger.error("ue_index={} not found in the scheduler", ue_index); + if (not ues.contains(ue_index) or not ues[ue_index].get_pcell().is_in_fallback_mode()) { + logger.error("ue_index={} not found in the scheduler or not in fallback", ue_index); return; } auto& u = ues[ue_index]; + + // Mark the start of the conRes timer. u.drx_controller().on_con_res_start(); auto ue_it = std::find_if(pending_dl_ues_new_tx.begin(), @@ -162,8 +168,8 @@ void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) void ue_fallback_scheduler::handle_ul_bsr_indication(du_ue_index_t ue_index, const ul_bsr_indication_message& bsr_ind) { - if (not ues.contains(ue_index)) { - logger.error("ue_index={} not found in the scheduler", ue_index); + if (not ues.contains(ue_index) or not ues[ue_index].get_pcell().is_in_fallback_mode()) { + logger.error("ue_index={} not found in the scheduler or not in fallback", ue_index); return; } @@ -174,21 +180,24 @@ void ue_fallback_scheduler::handle_ul_bsr_indication(du_ue_index_t ue_index, con return lcg_report.lcg_id == srb_lcg_id; }); const unsigned bsr_bytes = srb_lcg_report != bsr_ind.reported_lcgs.end() ? srb_lcg_report->nof_bytes : 0U; + if (bsr_bytes == 0) { + return; + } auto ue_it = std::find(pending_ul_ues.begin(), pending_ul_ues.end(), ue_index); // For UL UEs, we don't keep an internal estimate of the UL traffic, but we rely on the UL logical channel manager for // that task. Thus, compared to the DL case, the only operation that is needed for the UL is the addition of a new UE // to the pending UL UEs list. - if (ue_it == pending_ul_ues.end() and bsr_bytes != 0) { + if (ue_it == pending_ul_ues.end()) { pending_ul_ues.emplace_back(ue_index); } } void ue_fallback_scheduler::handle_sr_indication(du_ue_index_t ue_index) { - if (not ues.contains(ue_index)) { - logger.error("ue_index={} not found in the scheduler", ue_index); + if (not ues.contains(ue_index) or not ues[ue_index].get_pcell().is_in_fallback_mode()) { + logger.error("ue_index={} not found in the scheduler or not in fallback", ue_index); return; } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 7bf5c2852b..f91c0f3081 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -35,7 +35,7 @@ class ue_fallback_scheduler /// \param[in] sl Slot at which the DL Buffer State Indication was received. /// \param[in] srb_buffer_bytes Number of SRB bytes reported by Buffer State Indication. void - handle_dl_buffer_state_indication_srb(du_ue_index_t ue_index, bool is_srb0, slot_point sl, unsigned srb_buffer_bytes); + handle_dl_buffer_state_indication(du_ue_index_t ue_index, bool is_srb0, slot_point sl, unsigned srb_buffer_bytes); /// Handle Contention Resolution indication sent by the MAC. /// \param[in] ue_index UE's DU Index for which Contention Resolution CE needs to be scheduled. diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 539f8d6bbc..772d9e8e3e 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -312,7 +312,7 @@ class base_fallback_tester } // Notify scheduler of DL buffer state. - bench->fallback_sched.handle_dl_buffer_state_indication_srb(ue_idx, is_srb0, sl, buffer_size); + bench->fallback_sched.handle_dl_buffer_state_indication(ue_idx, is_srb0, sl, buffer_size); } void push_buffer_state_to_ul_ue(du_ue_index_t ue_idx, slot_point sl, unsigned buffer_size) From 6dcfdca9eded45a704f3873d6790c0f7df7859ad Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 2 Dec 2024 12:28:56 +0100 Subject: [PATCH 023/227] sched: simplify fallback_scheduler slot indication --- .../ue_scheduling/ue_fallback_scheduler.cpp | 115 ++++++------------ 1 file changed, 39 insertions(+), 76 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index d934e5bc45..ccc3190f25 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1836,85 +1836,42 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) slots_with_no_pdxch_space[(sl - 1).to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = false; last_sl_ind = sl; - // Remove any DL UE that is no longer in fallback mode; this can happen in case of overallocation, or when the GNB - // detects a false NACK from PUCCH. Existing the fallback mode is an indication that the fallback transmission was - // completed successfully. + // Remove any DL UE that is no longer in fallback mode. This happens when the higher layers confirm that the UE has + // successfully received its config. for (auto ue_it = pending_dl_ues_new_tx.begin(); ue_it != pending_dl_ues_new_tx.end();) { if (not ues.contains(ue_it->ue_index)) { + // UE was removed in the meantime. ue_it = pending_dl_ues_new_tx.erase(ue_it); continue; } - // For SRB1, due to segmentation and to pre-allocation, the scheduler might not be able to estimate precisely when - // the UE has received the SRB1 full buffer; we assume the UE has received the full SRB1 buffer data if UE exits - // fallback mode. This is not needed for SRB0, which doesn't allow segmentation. - if ((ue_it->is_srb0.has_value() and not ue_it->is_srb0.value()) and - (not ues[ue_it->ue_index].get_pcell().is_in_fallback_mode())) { + auto& u = ues[ue_it->ue_index]; + if (not u.get_pcell().is_in_fallback_mode()) { + // UE exited fallback. ue_it = pending_dl_ues_new_tx.erase(ue_it); continue; } - ++ue_it; - } - - // Only remove the {UE, HARQ-process} elements that have been retransmitted and positively acked. The rest of the - // elements are potential candidate for retransmissions. - for (auto it_ue_harq = ongoing_ues_ack_retxs.begin(); it_ue_harq != ongoing_ues_ack_retxs.end();) { - if (not ues.contains(it_ue_harq->ue_index)) { - it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); - continue; - } - - // If the SRB1 UE is no longer in fallback mode, it's safe to cancel all ongoing HARQ processes. - // For SRB1, due to segmentation and to pre-allocation, the scheduler might not be able to estimate precisely when - // the UE has received the SRB1 full buffer; we assume the UE has received the full SRB1 buffer data if UE exits - // fallback mode. This is not needed for SRB0, which doesn't allow segmentation. - if ((it_ue_harq->is_srb0.has_value() and not it_ue_harq->is_srb0.value()) and - (not ues[it_ue_harq->ue_index].get_pcell().is_in_fallback_mode())) { - it_ue_harq->h_dl->cancel_retxs(); - it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); - continue; - } - - if (not it_ue_harq->h_dl.has_value() or it_ue_harq->h_dl->empty()) { - it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); - continue; - } - - // If the HARQ process has the "fallback" flag set to false, it means that the HARQ process got reset by its - // timeout, and in the meantime got reused by the non-fallback scheduler. In this case, it cannot be processed by - // the fallback scheduler. NOTE: this very unlikely to happen, but not impossible under certain extreme conditions. - if (not it_ue_harq->h_dl->get_grant_params().is_fallback) { - it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); - continue; - } - ++it_ue_harq; - } - // Remove UE when the SRB1 buffer status is empty and when there are no HARQ processes scheduled for future - // transmissions. - for (auto ue_it = pending_dl_ues_new_tx.begin(); ue_it != pending_dl_ues_new_tx.end();) { - auto& ue = *ue_it; - if (not ue.is_srb0.has_value() or ue.is_srb0.value()) { - ++ue_it; - continue; + // Remove UE when the SRB1 buffer status is empty and when there are no HARQ processes scheduled for future + // transmissions. + // TODO: Verify if this is still needed. + if (ue_it->is_srb0.has_value() and ue_it->is_srb0.value()) { + // NOTE: the UEs that have pending RE-TXs are handled by the \ref ongoing_ues_ack_retxs and can be removed from + // \ref pending_dl_ues_new_tx. + const bool remove_ue = ue_it->pending_srb1_buffer_bytes == 0 and + ongoing_ues_ack_retxs.end() == + std::find_if(ongoing_ues_ack_retxs.begin(), + ongoing_ues_ack_retxs.end(), + [ue_idx = ue_it->ue_index, sl](const ack_and_retx_tracker& tracker) { + return tracker.ue_index == ue_idx and tracker.h_dl->is_waiting_ack() and + tracker.h_dl->nof_retxs() == 0 and + tracker.h_dl->pdsch_slot() >= sl; + }); + if (remove_ue) { + ue_it = pending_dl_ues_new_tx.erase(ue_it); + } } - // NOTE: the UEs that have pending RE-TXs are handled by the \ref ongoing_ues_ack_retxs and can be removed from - // \ref pending_dl_ues_new_tx. - const bool remove_ue = ue.pending_srb1_buffer_bytes == 0 and - ongoing_ues_ack_retxs.end() == - std::find_if(ongoing_ues_ack_retxs.begin(), - ongoing_ues_ack_retxs.end(), - [ue_idx = ue.ue_index, sl](const ack_and_retx_tracker& tracker) { - return tracker.ue_index == ue_idx and tracker.h_dl->is_waiting_ack() and - tracker.h_dl->nof_retxs() == 0 and - tracker.h_dl->pdsch_slot() >= sl; - }); - - if (remove_ue) { - ue_it = pending_dl_ues_new_tx.erase(ue_it); - } else { - ++ue_it; - } + ++ue_it; } // Remove UL UE if the UE has left fallback or if the UE has been deleted from the scheduler. @@ -1923,19 +1880,25 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) ue_it = pending_ul_ues.erase(ue_it); continue; } - - // Remove UE when it leaves the fallback. auto& ue = ues[*ue_it]; if (not ue.get_pcell().is_in_fallback_mode()) { - for (uint32_t h_id = 0; h_id != ue.get_pcell().harqs.nof_ul_harqs(); ++h_id) { - auto h_ul = ue.get_pcell().harqs.ul_harq(to_harq_id(h_id)); - if (h_ul.has_value()) { - h_ul->cancel_retxs(); - } - } ue_it = pending_ul_ues.erase(ue_it); continue; } ++ue_it; } + + // Only remove the {UE, HARQ-process} elements that have been retransmitted and positively acked. The rest of the + // elements are potential candidate for retransmissions. + for (auto it_ue_harq = ongoing_ues_ack_retxs.begin(); it_ue_harq != ongoing_ues_ack_retxs.end();) { + if (not ues.contains(it_ue_harq->ue_index) or not ues[it_ue_harq->ue_index].get_pcell().is_in_fallback_mode()) { + it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); + continue; + } + if (not it_ue_harq->h_dl.has_value() or it_ue_harq->h_dl->empty()) { + it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); + continue; + } + ++it_ue_harq; + } } From a561905b904aaf261179816a5a3a1cfb4b4de3f0 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 2 Dec 2024 16:20:02 +0100 Subject: [PATCH 024/227] sched: minimize code duplication when allocation conRes, SRB0 or SRB1 --- .../ue_scheduling/ue_fallback_scheduler.cpp | 182 +++++++----------- .../ue_scheduling/ue_fallback_scheduler.h | 67 +++---- 2 files changed, 101 insertions(+), 148 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index ccc3190f25..4abd49c6be 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -41,8 +41,9 @@ ue_fallback_scheduler::ue_fallback_scheduler(const scheduler_ue_expert_config& e ongoing_ues_ack_retxs.reserve(MAX_NOF_DU_UES); // NOTE 1: We use a std::vector instead of a std::array because we can later on initialize the vector with the minimum // value of k1, passed through the expert config. - // NOTE 2: Although the TS 38.213, Section 9.2.3 specifies that the k1 possible values are {1, ..., 8}, some UEs do - // not handle well the value k1=8, which can result in collision between PRACH and PUCCH. + // NOTE 2: Although the TS 38.213, Section 9.2.3 specifies that the k1 possible values are {1, ..., 8}, some UE + // implementations that we work with do not handle well the value k1=8. Instead, in the particular context of RRC + // Reestablishment, they PRACH instead of sending the PUCCH. const unsigned max_k1 = 7U; srsran_sanity_check(expert_cfg.min_k1 <= max_k1, "Invalid min_k1 value"); for (unsigned k1_value = expert_cfg.min_k1; k1_value <= max_k1; ++k1_value) { @@ -81,18 +82,14 @@ void ue_fallback_scheduler::run_slot(cell_resource_allocator& res_alloc) return; } - // Schedule ConRes CE. - if (not schedule_dl_conres_new_tx(res_alloc)) { + // Schedule DL new txs with the following priority: ConRes CE, SRB0 and SRB1. + if (not schedule_dl_new_tx(res_alloc, dl_new_tx_alloc_type::conres_only)) { return; } - - // Schedule SRB0 messages before SRB1, as we prioritize SRB0 over SRB1. - if (not schedule_dl_new_tx_srb0(res_alloc)) { + if (not schedule_dl_new_tx(res_alloc, dl_new_tx_alloc_type::srb0)) { return; } - - // Keep SRB1 with lower priority than SRB0. - schedule_dl_new_tx_srb1(res_alloc); + schedule_dl_new_tx(res_alloc, dl_new_tx_alloc_type::srb1); } void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_index, @@ -215,8 +212,7 @@ bool ue_fallback_scheduler::schedule_dl_retx(cell_resource_allocator& res_alloc) std::optional& h_dl = next_ue_harq_retx.h_dl; if (h_dl->has_pending_retx()) { - std::optional most_recent_tx_ack = get_most_recent_slot_tx(u.ue_index); - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, h_dl, most_recent_tx_ack, next_ue_harq_retx.is_srb0); + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, h_dl, next_ue_harq_retx.is_srb0); // This is the case of the scheduler reaching the maximum number of sched attempts. if (outcome == dl_sched_outcome::stop_dl_scheduling) { return false; @@ -246,132 +242,91 @@ void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& } } -bool ue_fallback_scheduler::schedule_dl_conres_new_tx(cell_resource_allocator& res_alloc) +ue_fallback_scheduler::dl_new_tx_alloc_type +ue_fallback_scheduler::get_dl_new_tx_alloc_type(const fallback_ue& next_ue) const { - auto next_ue = pending_dl_ues_new_tx.begin(); - while (next_ue != pending_dl_ues_new_tx.end()) { - // The UE might have been deleted in the meantime, check if still exists. - if (not ues.contains(next_ue->ue_index)) { - next_ue = pending_dl_ues_new_tx.erase(next_ue); - continue; - } - - // Check whether UE has any pending ConRes CE to be scheduled. - if (not next_ue->is_conres_pending) { - ++next_ue; - continue; - } - - // Check whether Msg4 over SRB has been received or not. - // NOTE: UE with both pending ConRes + Msg4 is handled by \c schedule_dl_new_tx_srb0 and \c schedule_dl_new_tx_srb1. - if (next_ue->is_srb0.has_value()) { - ++next_ue; - continue; - } + auto& u = ues[next_ue.ue_index]; + if (not next_ue.is_srb0.has_value()) { + // No SRB0 or SRB1. Verify if ConRes CE needs to be scheduled. + return next_ue.is_conres_pending ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; + } - auto& u = ues[next_ue->ue_index]; - if (not u.is_conres_ce_pending()) { - ++next_ue; - continue; - } + if (next_ue.is_srb0.value()) { + return u.has_pending_dl_newtx_bytes(LCID_SRB0) ? dl_new_tx_alloc_type::srb0 : dl_new_tx_alloc_type::error; + } - std::optional most_recent_tx_ack = get_most_recent_slot_tx(u.ue_index); - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, most_recent_tx_ack, next_ue->is_srb0); - if (outcome == dl_sched_outcome::success) { - next_ue = pending_dl_ues_new_tx.erase(next_ue); - } else if (outcome == dl_sched_outcome::next_ue) { - ++next_ue; - } else { - // This is the case the DL fallback scheduler has reached the maximum number of scheduling attempts and the fnc - // returns \ref stop_dl_scheduling. - return false; - } + // NOTE: Since SRB1 data can be segmented, it could happen that not all the SRB1 bytes are scheduled at once. The + // scheduler will attempt to allocate those remaining bytes in the following slots. The policy we adopt in this + // scheduler is to schedule first all possible grants to a given UE (to speed up the re-establishment and + // re-configuration). Only after the SRB1 buffer of that UE is emptied, we move on to the next UE. + if (has_pending_bytes_for_srb1(next_ue.ue_index)) { + return dl_new_tx_alloc_type::srb1; } - return true; + + return dl_new_tx_alloc_type::skip; } -bool ue_fallback_scheduler::schedule_dl_new_tx_srb0(cell_resource_allocator& res_alloc) +bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_alloc, + dl_new_tx_alloc_type selected_alloc_type) { for (auto next_ue = pending_dl_ues_new_tx.begin(); next_ue != pending_dl_ues_new_tx.end();) { - // The UE might have been deleted in the meantime, check if still exists. - if (not ues.contains(next_ue->ue_index)) { + // Determine if we should schedule ConRes, SRB0, SRB1 for the given UE. + const auto alloc_type = get_dl_new_tx_alloc_type(*next_ue); + if (alloc_type == dl_new_tx_alloc_type::error) { + // The UE is not in a state for scheduling + logger.error("ue={}: UE is an inconsistent state in the fallback scheduler", next_ue->ue_index); next_ue = pending_dl_ues_new_tx.erase(next_ue); continue; } - - // Check whether UE has any pending SRB0 data to be scheduled. - if (not next_ue->is_srb0.has_value() or not next_ue->is_srb0.value()) { + if (alloc_type != selected_alloc_type) { + // This type of alloc is not being prioritized. ++next_ue; continue; } - auto& u = ues[next_ue->ue_index]; - std::optional most_recent_tx_ack = get_most_recent_slot_tx(u.ue_index); - if (not u.has_pending_dl_newtx_bytes(LCID_SRB0)) { + // Make the scheduling attempt. + auto& u = ues[next_ue->ue_index]; + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, next_ue->is_srb0); + if (outcome == dl_sched_outcome::next_ue) { + // Allocation failed but we can attempt with another UE. ++next_ue; continue; } - - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, most_recent_tx_ack, next_ue->is_srb0); - if (outcome == dl_sched_outcome::success) { - next_ue = pending_dl_ues_new_tx.erase(next_ue); - } else if (outcome == dl_sched_outcome::next_ue) { - ++next_ue; - } else if (outcome == dl_sched_outcome::srb_pending) { - next_ue->is_conres_pending = false; - ++next_ue; - } else { + if (outcome == dl_sched_outcome::stop_dl_scheduling) { // This is the case the DL fallback scheduler has reached the maximum number of scheduling attempts and the fnc // returns \ref stop_dl_scheduling. return false; } - } - return true; -} -void ue_fallback_scheduler::schedule_dl_new_tx_srb1(cell_resource_allocator& res_alloc) -{ - for (auto next_ue = pending_dl_ues_new_tx.begin(); next_ue != pending_dl_ues_new_tx.end();) { - // The UE might have been deleted in the meantime, check if still exists. - if (not ues.contains(next_ue->ue_index)) { - next_ue = pending_dl_ues_new_tx.erase(next_ue); - continue; - } + // There was an allocation. This does not, however, mean that the pending data was completely flushed. - // Check whether UE has any pending SRB1 data to be scheduled. - if (not next_ue->is_srb0.has_value() or next_ue->is_srb0.value()) { - ++next_ue; - continue; - } + // We assume that there is always space for ConRes CE when an allocation takes place. + next_ue->is_conres_pending = false; - auto& u = ues[next_ue->ue_index]; - std::optional most_recent_tx_ack = get_most_recent_slot_tx(u.ue_index); - // NOTE: Since SRB1 data can be segmented, it could happen that not all the SRB1 bytes are scheduled at once. The - // scheduler will attempt to allocate those remaining bytes in the following slots. The policy we adopt in this - // scheduler is to schedule first all possible grants to a given UE (to speed up the re-establishment and - // re-configuration). Only after the SRB1 buffer of that UE is emptied, we move on to the next UE. - if (not has_pending_bytes_for_srb1(u.ue_index)) { - ++next_ue; - continue; - } + if (alloc_type == dl_new_tx_alloc_type::conres_only or alloc_type == dl_new_tx_alloc_type::srb0) { + // ConRes-only, SRB0-ony and ConRes+SRB0 cases - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, most_recent_tx_ack, next_ue->is_srb0); - if (outcome == dl_sched_outcome::success) { - next_ue->is_conres_pending = false; - // Move to the next UE ONLY IF the UE has no more pending bytes for SRB1. This is to give priority to the same UE, - // if there are still some SRB1 bytes left in the buffer. At the next iteration, the scheduler will try again with - // the same scheduler, but starting from the next available slot. - if (not has_pending_bytes_for_srb1(u.ue_index)) { + if (outcome == dl_sched_outcome::success) { + next_ue = pending_dl_ues_new_tx.erase(next_ue); + } else { + // ConRes CE was scheduled but SRB0 wasn't. ++next_ue; } - } else if (outcome == dl_sched_outcome::next_ue) { - ++next_ue; } else { - // This is the case the DL fallback scheduler has reached the maximum number of scheduling attempts and the fnc - // returns \ref stop_dl_scheduling. - return; + // SRB1-ony and ConRes+SRB1 cases + + if (outcome == dl_sched_outcome::success) { + // Move to the next UE ONLY IF the UE has no more pending bytes for SRB1. This is to give priority to the same + // UE, if there are still some SRB1 bytes left in the buffer. At the next iteration, the scheduler will try + // again with the same scheduler, but starting from the next available slot. + if (not has_pending_bytes_for_srb1(u.ue_index)) { + ++next_ue; + } + } } } + + return true; } static slot_point get_next_srb_slot(const cell_configuration& cell_cfg, slot_point sl_tx) @@ -394,7 +349,6 @@ ue_fallback_scheduler::dl_sched_outcome ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_alloc, ue& u, std::optional h_dl_retx, - std::optional most_recent_tx_ack_slots, std::optional is_srb0) { const auto& bwp_cfg_common = cell_cfg.dl_cfg_common.init_dl_bwp; @@ -412,6 +366,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // in the future when, in the same slot, there is already an SRB PDSCH allocated. This can happen, for example, if // there is a retransmission (previously) allocated at slot sched_ref_slot + max_dl_slots_ahead_sched, and then the // scheduler attempt to allocate a new TX on the same slot. + std::optional most_recent_tx_ack_slots = get_most_recent_slot_tx(u.ue_index); if (most_recent_tx_ack_slots.has_value() and sched_ref_slot + max_dl_slots_ahead_sched <= most_recent_tx_ack_slots.value().most_recent_tx_slot) { return dl_sched_outcome::next_ue; @@ -1851,6 +1806,17 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) continue; } + if (ue_it->is_conres_pending != u.is_conres_ce_pending()) { + logger.error("ue={}: Invalid ConRes state detected", ue_it->ue_index); + ue_it->is_conres_pending = u.is_conres_ce_pending(); + } + + if (not ue_it->is_conres_pending and not ue_it->is_srb0.has_value()) { + // UE has no new txs pending. It can be removed. + ue_it = pending_dl_ues_new_tx.erase(ue_it); + continue; + } + // Remove UE when the SRB1 buffer status is empty and when there are no HARQ processes scheduled for future // transmissions. // TODO: Verify if this is still needed. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index f91c0f3081..63263481c5 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -13,8 +13,6 @@ #include "../policy/ue_allocator.h" #include "../support/sch_pdu_builder.h" #include "ue_repository.h" -#include "srsran/scheduler/scheduler_configurator.h" -#include namespace srsran { @@ -55,6 +53,26 @@ class ue_fallback_scheduler void run_slot(cell_resource_allocator& res_alloc); private: + enum class dl_new_tx_alloc_type { conres_only, srb0, srb1, skip, error }; + + /// Size of the ring buffer used to store the slots where the scheduler has found no PDCCH/PDSCH resources. + static const size_t FALLBACK_SCHED_RING_BUFFER_SIZE = + get_allocator_ring_size_gt_min(SCHEDULER_MAX_K0 + SCHEDULER_MAX_K1 + NTN_CELL_SPECIFIC_KOFFSET_MAX); + + /// Defines the information that is needed to track the DL UEs that are pending for new SRB0/SRB1/ConRes CE TX. + struct fallback_ue { + du_ue_index_t ue_index; + // This field is empty if only ConRes indication is received from MAC and buffer status from upper layers for + // SRB0/SRB1 is not yet received. + std::optional is_srb0; + // This field indicated whether ConRes CE pending to be sent or not. + bool is_conres_pending; + // Represents the number of LCID-1 bytes (excluding any overhead) that are pending for this UE. + // This is only meaningful for SRB1 and gets updated every time an RLC buffer state update is received or when we + // schedule a new PDSCH TX for this UE. + unsigned pending_srb1_buffer_bytes = 0; + }; + /// Helper that schedules DL SRB0 and SRB1 retx. Returns false if the DL fallback schedule should stop the DL /// allocation, true otherwise. bool schedule_dl_retx(cell_resource_allocator& res_alloc); @@ -62,29 +80,13 @@ class ue_fallback_scheduler /// Helper that schedules new UL SRB1 tx. void schedule_ul_new_tx_and_retx(cell_resource_allocator& res_alloc); - /// Helper that schedules new DL ConRes CE when Msg4 over SRB has not yet been received. Returns false if the DL - /// fallback schedule should exit, true otherwise. - /// \remark This function handles the following scenarios: - /// - Schedules ConRes CE only if ConRes indication is received from MAC but no buffer status update is received - /// for SRB0/SRB1. - bool schedule_dl_conres_new_tx(cell_resource_allocator& res_alloc); - - /// Helper that schedules new DL SRB0 tx. Returns false if the DL fallback schedule should exit, true otherwise. - /// \remark This function handles the following scenarios: - /// - Schedules SRB0 only (not empty) if ConRes CE has already sent. - /// - Schedules SRB0 (not empty) + ConRes CE (if pending) if there is enough space in PDSCH resource grid. - /// - Schedules ConRes CE only (if pending) if there is not enough space in PDSCH resource grid to fit SRB0 (not - /// empty) + ConRes CE. - bool schedule_dl_new_tx_srb0(cell_resource_allocator& res_alloc); - - /// Helper that schedules new DL SRB1 tx. - /// \remark This function handles the following scenarios: - /// - Schedules SRB1 (not empty) + ConRes CE (if pending). - void schedule_dl_new_tx_srb1(cell_resource_allocator& res_alloc); + /// Determine which type of DL allocation is required for a given UE candidate. + dl_new_tx_alloc_type get_dl_new_tx_alloc_type(const fallback_ue& next_ue) const; - /// Size of the ring buffer used to store the slots where the scheduler has found no PDCCH/PDSCH resources. - static const size_t FALLBACK_SCHED_RING_BUFFER_SIZE = - get_allocator_ring_size_gt_min(SCHEDULER_MAX_K0 + SCHEDULER_MAX_K1 + NTN_CELL_SPECIFIC_KOFFSET_MAX); + /// Helper that schedules pending DL new txs for ConRes CE, SRB0 or SRB1. + /// \param[in] selected_alloc_type Type of allocation to make. Options: ConRes CE only, SRB0 and SRB1. + /// \return false if the fallback scheduler should stop its operation for the given slot. + bool schedule_dl_new_tx(cell_resource_allocator& res_alloc, dl_new_tx_alloc_type selected_alloc_type); /// Erase the UEs' HARQ processes that have been acked from the SRB scheduler cache. void slot_indication(slot_point sl); @@ -104,8 +106,7 @@ class ue_fallback_scheduler dl_sched_outcome schedule_dl_srb(cell_resource_allocator& res_alloc, ue& u, std::optional h_dl_retx, - std::optional most_recent_tx_ack_slots = std::nullopt, - std::optional is_srb0 = std::nullopt); + std::optional is_srb0 = std::nullopt); enum class ul_srb_sched_outcome { next_ue, next_slot, stop_ul_scheduling }; @@ -203,20 +204,6 @@ class ue_fallback_scheduler slot_point sl_tx, const std::optional& h_dl_retx) const; - /// Defines the information that is needed to track the DL UEs that are pending for new SRB0/SRB1/ConRes CE TX. - struct fallback_ue { - du_ue_index_t ue_index; - // This field is empty if only ConRes indication is received from MAC and buffer status from upper layers for - // SRB0/SRB1 is not yet received. - std::optional is_srb0; - // This field indicated whether ConRes CE pending to be sent or not. - bool is_conres_pending; - // Represents the number of LCID-1 bytes (excluding any overhead) that are pending for this UE. - // This is only meaningful for SRB1 and gets updated every time an RLC buffer state update is received or when we - // schedule a new PDSCH TX for this UE. - unsigned pending_srb1_buffer_bytes = 0; - }; - /// List of UE's DU Indexes for which SRB0 and SRB1 messages needs to be scheduled. std::vector pending_dl_ues_new_tx; From f31f11ff105b4e4c92a96df93a00ef7508eaa3ea Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 2 Dec 2024 16:25:46 +0100 Subject: [PATCH 025/227] sched: improve logging of ue_fallback_scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 4abd49c6be..7d4d137a82 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -98,13 +98,12 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i unsigned srb_buffer_bytes) { if (not ues.contains(ue_index)) { - logger.error("ue_index={} not found in the scheduler", ue_index); + logger.error("ue={}: DL Buffer Occupancy update discarded. UE is not found in the scheduler", ue_index); return; } ue& u = ues[ue_index]; if (not u.get_pcell().is_in_fallback_mode()) { - logger.error("Discarding DL buffer state indication in fallback scheduler. Cause: ue_index={} not in fallback mode", - ue_index); + logger.error("ue={}: DL Buffer Occupancy update discarded. UE is not in fallback mode", ue_index); return; } @@ -141,11 +140,15 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) { - if (not ues.contains(ue_index) or not ues[ue_index].get_pcell().is_in_fallback_mode()) { - logger.error("ue_index={} not found in the scheduler or not in fallback", ue_index); + if (not ues.contains(ue_index)) { + logger.error("ue={}: ConRes CE discarded. Cause: UE is not found in the scheduler", ue_index); return; } auto& u = ues[ue_index]; + if (not u.get_pcell().is_in_fallback_mode()) { + logger.error("ue={}: ConRes CE discarded. Cause: UE is not in fallback state", ue_index); + return; + } // Mark the start of the conRes timer. u.drx_controller().on_con_res_start(); From 609e72efeb5e5cf8cfcb7615d2d5deb66891c84d Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 2 Dec 2024 18:15:14 +0100 Subject: [PATCH 026/227] sched: remove pending ul UEs when they have no pending newtxs or retxs --- lib/scheduler/ue_context/ue_cell.h | 11 +++------ .../ue_scheduling/ue_fallback_scheduler.cpp | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/scheduler/ue_context/ue_cell.h b/lib/scheduler/ue_context/ue_cell.h index 5d7fe55ba2..8a461967eb 100644 --- a/lib/scheduler/ue_context/ue_cell.h +++ b/lib/scheduler/ue_context/ue_cell.h @@ -41,8 +41,6 @@ class ue_cell unsigned consecutive_pusch_kos = 0; }; - bool is_in_fallback_mode() const { return in_fallback_mode; } - ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, @@ -66,6 +64,9 @@ class ue_cell /// \brief Determines whether the UE cell is currently active. bool is_active() const { return active; } + /// Whether the UE is in fallback mode. + bool is_in_fallback_mode() const { return in_fallback_mode; } + const ue_cell_configuration& cfg() const { return *ue_cfg; } /// \brief Deactivates cell. @@ -135,12 +136,6 @@ class ue_cell get_active_ul_search_spaces(slot_point pdcch_slot, std::optional required_dci_rnti_type = {}) const; - /// \brief Defines the fallback state of the ue_cell. - /// Transitions can be fallback => sr_csi_received => normal => fallback. The fallback => sr_csi_received transition - /// is triggered by the reception of SR or CSI, the sr_csi_received => normal is triggered by the reception of 2 - /// CRC=OK after the first SR or CSI is received. - enum class fallback_state { fallback, sr_csi_received, normal }; - /// \brief Get UE channel state handler. ue_channel_state_manager& channel_state_manager() { return channel_state; } const ue_channel_state_manager& channel_state_manager() const { return channel_state; } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 7d4d137a82..eb8532848f 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -211,7 +211,7 @@ void ue_fallback_scheduler::handle_sr_indication(du_ue_index_t ue_index) bool ue_fallback_scheduler::schedule_dl_retx(cell_resource_allocator& res_alloc) { for (auto& next_ue_harq_retx : ongoing_ues_ack_retxs) { - auto& u = *ues.find(next_ue_harq_retx.ue_index); + auto& u = ues[next_ue_harq_retx.ue_index]; std::optional& h_dl = next_ue_harq_retx.h_dl; if (h_dl->has_pending_retx()) { @@ -227,16 +227,11 @@ bool ue_fallback_scheduler::schedule_dl_retx(cell_resource_allocator& res_alloc) void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& res_alloc) { - // Processes all the UL UE at once, including UE with new transmissions and UE with retransmissions. + // Processes all the UL UEs at once, including UEs with new transmissions and UEs with retransmissions. for (auto next_ue = pending_ul_ues.begin(); next_ue != pending_ul_ues.end();) { - // next_ue must be in the ues list, else it would have been removed by the \ref slot_indication() function. auto& u = ues[*next_ue]; std::optional h_ul_retx = u.get_pcell().harqs.find_pending_ul_retx(); - if (not h_ul_retx.has_value() and not u.pending_ul_newtx_bytes()) { - ++next_ue; - continue; - } - ul_srb_sched_outcome outcome = schedule_ul_ue(res_alloc, u, h_ul_retx); + ul_srb_sched_outcome outcome = schedule_ul_ue(res_alloc, u, h_ul_retx); if (outcome == ul_srb_sched_outcome::stop_ul_scheduling) { // If there is no PDCCH space, then stop the scheduling for all UL UEs. return; @@ -365,11 +360,12 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // TODO: Make this compatible with k0 > 0. slot_point sched_ref_slot = res_alloc[0].slot; + std::optional most_recent_tx_ack_slots = get_most_recent_slot_tx(u.ue_index); + // This is to prevent the edge case of the scheduler trying to allocate an SRB PDSCH in the farthest possible slot // in the future when, in the same slot, there is already an SRB PDSCH allocated. This can happen, for example, if // there is a retransmission (previously) allocated at slot sched_ref_slot + max_dl_slots_ahead_sched, and then the // scheduler attempt to allocate a new TX on the same slot. - std::optional most_recent_tx_ack_slots = get_most_recent_slot_tx(u.ue_index); if (most_recent_tx_ack_slots.has_value() and sched_ref_slot + max_dl_slots_ahead_sched <= most_recent_tx_ack_slots.value().most_recent_tx_slot) { return dl_sched_outcome::next_ue; @@ -1843,14 +1839,21 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) ++ue_it; } - // Remove UL UE if the UE has left fallback or if the UE has been deleted from the scheduler. for (auto ue_it = pending_ul_ues.begin(); ue_it != pending_ul_ues.end();) { if (not ues.contains(*ue_it)) { + // UE was removed in the meantime. ue_it = pending_ul_ues.erase(ue_it); continue; } auto& ue = ues[*ue_it]; if (not ue.get_pcell().is_in_fallback_mode()) { + // UE has left fallback mode. + ue_it = pending_ul_ues.erase(ue_it); + continue; + } + std::optional h_ul_retx = ue.get_pcell().harqs.find_pending_ul_retx(); + if (not h_ul_retx.has_value() and not ue.pending_ul_newtx_bytes()) { + // UE has no pending data. ue_it = pending_ul_ues.erase(ue_it); continue; } From 7d2135e7ebde51d50d2dbe9e419582d20d906cce Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 2 Dec 2024 18:23:16 +0100 Subject: [PATCH 027/227] sched: remove unnecessary members of ue_cell class --- lib/scheduler/ue_context/ue_cell.cpp | 3 --- lib/scheduler/ue_context/ue_cell.h | 10 ---------- lib/scheduler/ue_scheduling/ue_event_manager.cpp | 2 +- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/lib/scheduler/ue_context/ue_cell.cpp b/lib/scheduler/ue_context/ue_cell.cpp index cc745ec28a..345e7943f0 100644 --- a/lib/scheduler/ue_context/ue_cell.cpp +++ b/lib/scheduler/ue_context/ue_cell.cpp @@ -290,9 +290,6 @@ int ue_cell::handle_crc_pdu(slot_point pusch_slot, const ul_crc_pdu_indication& h_ul->get_grant_params().mcs_table, h_ul->get_grant_params().olla_mcs); - // Update PUSCH KO count metrics. - ue_metrics.consecutive_pusch_kos = (crc_pdu.tb_crc_success) ? 0 : ue_metrics.consecutive_pusch_kos + 1; - // Update PUSCH SNR reported from PHY. if (crc_pdu.ul_sinr_dB.has_value()) { channel_state.update_pusch_snr(crc_pdu.ul_sinr_dB.value()); diff --git a/lib/scheduler/ue_context/ue_cell.h b/lib/scheduler/ue_context/ue_cell.h index 8a461967eb..3ce23f2d1a 100644 --- a/lib/scheduler/ue_context/ue_cell.h +++ b/lib/scheduler/ue_context/ue_cell.h @@ -37,10 +37,6 @@ struct grant_prbs_mcs { class ue_cell { public: - struct metrics { - unsigned consecutive_pusch_kos = 0; - }; - ue_cell(du_ue_index_t ue_index_, rnti_t crnti_val, const ue_cell_configuration& ue_cell_cfg_, @@ -117,10 +113,6 @@ class ue_cell /// Update UE with the latest CSI report for a given cell. void handle_csi_report(const csi_report_data& csi_report); - /// \brief Get the current UE cell metrics. - const metrics& get_metrics() const { return ue_metrics; } - metrics& get_metrics() { return ue_metrics; } - sch_mcs_index get_ul_mcs(pusch_mcs_table mcs_table) const { return ue_mcs_calculator.calculate_ul_mcs(mcs_table); } /// \brief Get recommended aggregation level for PDCCH at a given CQI. @@ -167,8 +159,6 @@ class ue_cell /// cellConfigCommon are used. bool in_fallback_mode = true; - metrics ue_metrics; - ue_channel_state_manager channel_state; ue_link_adaptation_controller ue_mcs_calculator; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 7d458e0a6e..4eabffbf70 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -81,7 +81,7 @@ class ue_event_manager::ue_dl_buffer_occupancy_manager final : public scheduler_ // Forward DL BO update to UE. u.handle_dl_buffer_state_indication(dl_bo); auto& du_pcell = parent.du_cells[u.get_pcell().cell_index]; - if (dl_bo.lcid == LCID_SRB0 or (u.get_pcell().is_in_fallback_mode() and dl_bo.lcid == LCID_SRB1)) { + if (u.get_pcell().is_in_fallback_mode()) { // Signal SRB fallback scheduler with the new SRB0/SRB1 buffer state. du_pcell.fallback_sched->handle_dl_buffer_state_indication( dl_bo.ue_index, dl_bo.lcid == LCID_SRB0, sl, dl_bo.bs); From 47281bae09fe6242d3007e4abcd63f34c0c7a388 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 3 Dec 2024 15:30:01 +0100 Subject: [PATCH 028/227] sched: fix check in fallback_scheduler for srb1 --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index eb8532848f..8a82a7241a 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -243,13 +243,13 @@ void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& ue_fallback_scheduler::dl_new_tx_alloc_type ue_fallback_scheduler::get_dl_new_tx_alloc_type(const fallback_ue& next_ue) const { - auto& u = ues[next_ue.ue_index]; if (not next_ue.is_srb0.has_value()) { // No SRB0 or SRB1. Verify if ConRes CE needs to be scheduled. return next_ue.is_conres_pending ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; } if (next_ue.is_srb0.value()) { + auto& u = ues[next_ue.ue_index]; return u.has_pending_dl_newtx_bytes(LCID_SRB0) ? dl_new_tx_alloc_type::srb0 : dl_new_tx_alloc_type::error; } @@ -1819,7 +1819,7 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) // Remove UE when the SRB1 buffer status is empty and when there are no HARQ processes scheduled for future // transmissions. // TODO: Verify if this is still needed. - if (ue_it->is_srb0.has_value() and ue_it->is_srb0.value()) { + if (ue_it->is_srb0.has_value() and not ue_it->is_srb0.value()) { // NOTE: the UEs that have pending RE-TXs are handled by the \ref ongoing_ues_ack_retxs and can be removed from // \ref pending_dl_ues_new_tx. const bool remove_ue = ue_it->pending_srb1_buffer_bytes == 0 and From e813c74968e4ce72e5c7c17c456f796824f76793 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 3 Dec 2024 17:10:52 +0100 Subject: [PATCH 029/227] sched: fix removal during loop in fallback scheduler --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 1 + lib/scheduler/ue_scheduling/ue_fallback_scheduler.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 8a82a7241a..f8b9d0599d 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1833,6 +1833,7 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) }); if (remove_ue) { ue_it = pending_dl_ues_new_tx.erase(ue_it); + continue; } } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 63263481c5..27fbefdcc1 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -66,7 +66,7 @@ class ue_fallback_scheduler // SRB0/SRB1 is not yet received. std::optional is_srb0; // This field indicated whether ConRes CE pending to be sent or not. - bool is_conres_pending; + bool is_conres_pending = false; // Represents the number of LCID-1 bytes (excluding any overhead) that are pending for this UE. // This is only meaningful for SRB1 and gets updated every time an RLC buffer state update is received or when we // schedule a new PDSCH TX for this UE. From c43c02676af731a08dede3d52dd8e92ce057c9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 21 Nov 2024 12:31:11 +0100 Subject: [PATCH 030/227] ci: use runners variables for cpu/ram in build jobs --- .gitlab/ci-shared/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci-shared/build.yml b/.gitlab/ci-shared/build.yml index cdff42361b..d8ebd804c1 100644 --- a/.gitlab/ci-shared/build.yml +++ b/.gitlab/ci-shared/build.yml @@ -70,10 +70,10 @@ variables: 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 - KUBERNETES_MEMORY_LIMIT: 12Gi + KUBERNETES_CPU_REQUEST: ${SRS_CPU_LIMIT} + KUBERNETES_CPU_LIMIT: ${SRS_CPU_LIMIT} + KUBERNETES_MEMORY_REQUEST: ${SRS_MEMORY_LIMIT} + KUBERNETES_MEMORY_LIMIT: ${SRS_MEMORY_LIMIT} KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "40G" KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "40G" tags: From e8fa4084cdc8c4cc6cb00ab63ca91054778000cd Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 15 Nov 2024 17:16:22 +0000 Subject: [PATCH 031/227] gnb,cu_up: changed upf config to ngu config --- apps/cu/CMakeLists.txt | 2 +- apps/cu/cu.cpp | 6 ++-- apps/gnb/gnb.cpp | 6 ++-- apps/services/CMakeLists.txt | 2 ++ apps/services/network/CMakeLists.txt | 13 ++++++++ apps/services/network/udp_cli11_schema.cpp | 31 +++++++++++++++++++ apps/services/network/udp_cli11_schema.h | 28 +++++++++++++++++ apps/units/o_cu_up/cu_up/cu_up_unit_config.h | 16 +++++----- .../cu_up/cu_up_unit_config_cli11_schema.cpp | 20 ++++++------ .../cu_up/cu_up_unit_config_translators.cpp | 10 +++--- .../cu_up/cu_up_unit_config_yaml_writer.cpp | 19 +++++++----- apps/units/o_cu_up/o_cu_up_builder.cpp | 2 +- 12 files changed, 116 insertions(+), 39 deletions(-) create mode 100644 apps/services/network/CMakeLists.txt create mode 100644 apps/services/network/udp_cli11_schema.cpp create mode 100644 apps/services/network/udp_cli11_schema.h diff --git a/apps/cu/CMakeLists.txt b/apps/cu/CMakeLists.txt index dadeb49a2f..65ee23b552 100644 --- a/apps/cu/CMakeLists.txt +++ b/apps/cu/CMakeLists.txt @@ -17,11 +17,11 @@ install(TARGETS srscu RUNTIME) target_link_libraries(srscu PRIVATE - srsran_app_services srsran_support srsran_versioning srsran_o_cu_cp_app_unit srsran_o_cu_up_app_unit + srsran_app_services srsran_ngap srsran_f1c_gateway srsran_e1_gateway diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index c47be76cbe..540bc82a76 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -145,10 +145,10 @@ static void autoderive_cu_up_parameters_after_parsing(o_cu_up_unit_config& o const cu_cp_unit_config& cu_cp_cfg) { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. - if (o_cu_up_cfg.cu_up_cfg.upf_cfg.bind_addr == "auto") { - o_cu_up_cfg.cu_up_cfg.upf_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; + if (o_cu_up_cfg.cu_up_cfg.ngu_cfg.bind_addr == "auto") { + o_cu_up_cfg.cu_up_cfg.ngu_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; } - o_cu_up_cfg.cu_up_cfg.upf_cfg.no_core = cu_cp_cfg.amf_config.no_core; + o_cu_up_cfg.cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; o_cu_up_cfg.e2_cfg.pcaps.enabled = o_cu_up_cfg.e2_cfg.base_config.enable_unit_e2 && o_cu_up_cfg.e2_cfg.pcaps.enabled; } diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 64bca625f0..01e25c044e 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -168,10 +168,10 @@ static void autoderive_slicing_args(du_high_unit_config& du_hi_cfg, cu_cp_unit_c static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_cfg, const cu_cp_unit_config& cu_cp_cfg) { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. - if (cu_up_cfg.upf_cfg.bind_addr == "auto") { - cu_up_cfg.upf_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; + if (cu_up_cfg.ngu_cfg.bind_addr == "auto") { + cu_up_cfg.ngu_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; } - cu_up_cfg.upf_cfg.no_core = cu_cp_cfg.amf_config.no_core; + cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; } int main(int argc, char** argv) diff --git a/apps/services/CMakeLists.txt b/apps/services/CMakeLists.txt index d8de80b00b..e2d5387d3f 100644 --- a/apps/services/CMakeLists.txt +++ b/apps/services/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(buffer_pool) add_subdirectory(e2) add_subdirectory(hal) add_subdirectory(logger) +add_subdirectory(network) add_subdirectory(worker_manager) set(SOURCES @@ -23,6 +24,7 @@ target_include_directories(srsran_app_services PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(srsran_app_services srsran_buffer_pool_app_service srsran_e2_app_service + srsran_network_app_service srsran_hal_app_service srsran_logger_app_service srsran_worker_manager_app_service) diff --git a/apps/services/network/CMakeLists.txt b/apps/services/network/CMakeLists.txt new file mode 100644 index 0000000000..823539990c --- /dev/null +++ b/apps/services/network/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 + udp_cli11_schema.cpp) + +add_library(srsran_network_app_service STATIC ${SOURCES}) +target_include_directories(srsran_network_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/network/udp_cli11_schema.cpp b/apps/services/network/udp_cli11_schema.cpp new file mode 100644 index 0000000000..f0fbb2eb67 --- /dev/null +++ b/apps/services/network/udp_cli11_schema.cpp @@ -0,0 +1,31 @@ +/* + * + * 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 "udp_cli11_schema.h" +#include "srsran/support/cli11_utils.h" + +using namespace srsran; + +static void configure_cli11_udp_args(CLI::App& app, udp_appconfig& udp_params) +{ + add_option(app, "--max_rx_msgs", udp_params.rx_max_mmsg, "Maximum amount of messages RX in a single syscall") + ->capture_default_str(); + add_option(app, + "--pool_threshold", + udp_params.pool_occupancy_threshold, + "Pool accupancy threshold after which packets are dropped") + ->capture_default_str(); +} + +void srsran::configure_cli11_with_udp_config_schema(CLI::App& app, udp_appconfig& config) +{ + CLI::App* udp_subcmd = add_subcommand(app, "udp", "UDP parameters")->configurable(); + configure_cli11_udp_args(*udp_subcmd, config); +} diff --git a/apps/services/network/udp_cli11_schema.h b/apps/services/network/udp_cli11_schema.h new file mode 100644 index 0000000000..262c096937 --- /dev/null +++ b/apps/services/network/udp_cli11_schema.h @@ -0,0 +1,28 @@ +/* + * + * 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 udp_appconfig { + unsigned rx_max_mmsg = 256; + float pool_occupancy_threshold = 0.9; +}; + +/// \brief Configures the given CLI11 application with the UDP application configuration schema. +/// +/// \param[out] app CLI11 application to configure. +/// \param[out] config UDP configuration that stores the parameters. +void configure_cli11_with_udp_config_schema(CLI::App& app, udp_appconfig& config); + +} // namespace srsran diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config.h b/apps/units/o_cu_up/cu_up/cu_up_unit_config.h index 3be65cd4fe..1a86d4d478 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config.h +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config.h @@ -10,6 +10,7 @@ #pragma once +#include "apps/services/network/udp_cli11_schema.h" #include "apps/units/o_cu_up/cu_up/cu_up_unit_pcap_config.h" #include "cu_up_unit_logger_config.h" #include "srsran/ran/qos/five_qi.h" @@ -25,13 +26,12 @@ struct cu_up_unit_metrics_config { } pdcp; }; -struct cu_up_unit_upf_config { - std::string bind_addr = "auto"; - std::string bind_interface = "auto"; - std::string ext_addr = "auto"; - int udp_rx_max_msgs = 256; - float pool_threshold = 0.9; - bool no_core = false; +struct cu_up_unit_ngu_config { + std::string bind_addr = "auto"; + std::string bind_interface = "auto"; + std::string ext_addr = "auto"; + bool no_core = false; + udp_appconfig udp_config = {}; }; /// F1-U configuration at CU_UP side @@ -60,7 +60,7 @@ struct cu_up_unit_config { unsigned gtpu_reordering_timer_ms = 0; bool warn_on_drop = false; /// UPF configuration. - cu_up_unit_upf_config upf_cfg; + cu_up_unit_ngu_config ngu_cfg; /// Metrics. cu_up_unit_metrics_config metrics; /// Loggers. diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp index 5d35446df4..b4d0a7dc19 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp @@ -17,29 +17,27 @@ using namespace srsran; -static void configure_cli11_upf_args(CLI::App& app, cu_up_unit_upf_config& upf_params) +static void configure_cli11_ngu_args(CLI::App& app, cu_up_unit_ngu_config& ngu_params) { - add_option(app, "--bind_addr", upf_params.bind_addr, "Local IP address to bind for N3 interface") + add_option(app, "--bind_addr", ngu_params.bind_addr, "Local IP address to bind for N3 interface") ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); - add_option(app, "--bind_interface", upf_params.bind_interface, "Network device to bind for N3 interface") + add_option(app, "--bind_interface", ngu_params.bind_interface, "Network device to bind for N3 interface") ->capture_default_str(); add_option(app, "--ext_addr", - upf_params.ext_addr, + ngu_params.ext_addr, "External IP address that is advertised to receive GTP-U packets from UPF via N3 interface") ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); - add_option(app, "--udp_max_rx_msgs", upf_params.udp_rx_max_msgs, "Maximum amount of messages RX in a single syscall"); - add_option( - app, "--pool_threshold", upf_params.pool_threshold, "Pool accupancy threshold after which packets are dropped") - ->check(CLI::Range(0.0, 1.0)); - add_option(app, "--no_core", upf_params.no_core, "Allow gNB to run without a core"); + add_option(app, "--no_core", ngu_params.no_core, "Allow gNB to run without a core"); + + configure_cli11_with_udp_config_schema(app, ngu_params.udp_config); } static void configure_cli11_cu_up_args(CLI::App& app, cu_up_unit_config& cu_up_params) { // UPF section. - CLI::App* upf_subcmd = add_subcommand(app, "upf", "UPF parameters")->configurable(); - configure_cli11_upf_args(*upf_subcmd, cu_up_params.upf_cfg); + CLI::App* ngu_subcmd = add_subcommand(app, "ngu", "NG-U parameters")->configurable(); + configure_cli11_ngu_args(*ngu_subcmd, cu_up_params.ngu_cfg); add_option(app, "--gtpu_queue_size", cu_up_params.gtpu_queue_size, "GTP-U queue size, in PDUs") ->capture_default_str(); diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp index 9fea329a51..1730dafbfe 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp @@ -23,11 +23,11 @@ srs_cu_up::cu_up_config srsran::generate_cu_up_config(const cu_up_unit_config& c out_cfg.n3_cfg.gtpu_reordering_timer = std::chrono::milliseconds{config.gtpu_reordering_timer_ms}; out_cfg.n3_cfg.warn_on_drop = config.warn_on_drop; - out_cfg.net_cfg.n3_bind_addr = config.upf_cfg.bind_addr; - out_cfg.net_cfg.n3_ext_addr = config.upf_cfg.ext_addr; - out_cfg.net_cfg.n3_bind_interface = config.upf_cfg.bind_interface; - out_cfg.net_cfg.n3_rx_max_mmsg = config.upf_cfg.udp_rx_max_msgs; - out_cfg.net_cfg.pool_threshold = config.upf_cfg.pool_threshold; + out_cfg.net_cfg.n3_bind_addr = config.ngu_cfg.bind_addr; + out_cfg.net_cfg.n3_ext_addr = config.ngu_cfg.ext_addr; + out_cfg.net_cfg.n3_bind_interface = config.ngu_cfg.bind_interface; + out_cfg.net_cfg.n3_rx_max_mmsg = config.ngu_cfg.udp_config.rx_max_mmsg; + out_cfg.net_cfg.pool_threshold = config.ngu_cfg.udp_config.pool_occupancy_threshold; out_cfg.test_mode_cfg.enabled = config.test_mode_cfg.enabled; out_cfg.test_mode_cfg.integrity_enabled = config.test_mode_cfg.integrity_enabled; diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp index 0f763a8673..57f481f8fe 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp @@ -14,13 +14,18 @@ using namespace srsran; -static void fill_cu_up_upf_section(YAML::Node node, const cu_up_unit_upf_config& config) +static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) { - node["bind_addr"] = config.bind_addr; - node["bind_interface"] = config.bind_interface; - node["ext_addr"] = config.ext_addr; - node["udp_max_rx_msgs"] = config.udp_rx_max_msgs; - node["no_core"] = config.no_core; + node["max_rx_msgs"] = config.rx_max_mmsg; +} + +static void fill_cu_up_ngu_section(YAML::Node node, const cu_up_unit_ngu_config& config) +{ + node["bind_addr"] = config.bind_addr; + node["bind_interface"] = config.bind_interface; + node["ext_addr"] = config.ext_addr; + node["no_core"] = config.no_core; + fill_cu_up_udp_section(node["udp"], config.udp_config); } static void fill_cu_up_metrics_section(YAML::Node node, const cu_up_unit_metrics_config& config) @@ -102,7 +107,7 @@ void srsran::fill_cu_up_config_in_yaml_schema(YAML::Node& node, const cu_up_unit fill_cu_up_log_section(node["log"], config.loggers); fill_cu_up_pcap_section(node["pcap"], config.pcap_cfg); fill_cu_up_metrics_section(node["metrics"], config.metrics); - fill_cu_up_upf_section(node["upf"], config.upf_cfg); + fill_cu_up_ngu_section(node["ngu"], config.ngu_cfg); fill_cu_up_qos_section(node, config.qos_cfg); } diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index c6691ac3df..bb4b816395 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -65,7 +65,7 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ config.cu_up_cfg.net_cfg.f1u_bind_addr = address.value(); // Create NG-U gateway. std::unique_ptr ngu_gw; - if (not unit_cfg.cu_up_cfg.upf_cfg.no_core) { + if (not unit_cfg.cu_up_cfg.ngu_cfg.no_core) { udp_network_gateway_config ngu_gw_config = {}; ngu_gw_config.bind_address = config.cu_up_cfg.net_cfg.n3_bind_addr; ngu_gw_config.bind_port = config.cu_up_cfg.net_cfg.n3_bind_port; From 3194b2799dde8d9e94bff36340abb9b11e524a05 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 19 Nov 2024 16:41:54 +0000 Subject: [PATCH 032/227] cu_up: add cli11 option for configuring multiple socket --- apps/cu/cu.cpp | 3 ++- apps/gnb/gnb.cpp | 3 ++- apps/units/o_cu_up/cu_up/cu_up_unit_config.h | 8 ++++++-- .../cu_up/cu_up_unit_config_cli11_schema.cpp | 16 ++++++---------- .../cu_up/cu_up_unit_config_translators.cpp | 2 ++ .../cu_up/cu_up_unit_config_yaml_writer.cpp | 10 ++++++---- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 540bc82a76..04e6bf31a4 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -145,9 +145,10 @@ static void autoderive_cu_up_parameters_after_parsing(o_cu_up_unit_config& o const cu_cp_unit_config& cu_cp_cfg) { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. + /* TODO Fixup if (o_cu_up_cfg.cu_up_cfg.ngu_cfg.bind_addr == "auto") { o_cu_up_cfg.cu_up_cfg.ngu_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; - } + }*/ o_cu_up_cfg.cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; o_cu_up_cfg.e2_cfg.pcaps.enabled = o_cu_up_cfg.e2_cfg.base_config.enable_unit_e2 && o_cu_up_cfg.e2_cfg.pcaps.enabled; } diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 01e25c044e..0625eb1ee8 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -168,9 +168,10 @@ static void autoderive_slicing_args(du_high_unit_config& du_hi_cfg, cu_cp_unit_c static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_cfg, const cu_cp_unit_config& cu_cp_cfg) { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. + /* TODO fixup if (cu_up_cfg.ngu_cfg.bind_addr == "auto") { cu_up_cfg.ngu_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; - } + }*/ cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; } diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config.h b/apps/units/o_cu_up/cu_up/cu_up_unit_config.h index 1a86d4d478..8b08f0e61f 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config.h +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config.h @@ -26,14 +26,18 @@ struct cu_up_unit_metrics_config { } pdcp; }; -struct cu_up_unit_ngu_config { +struct cu_up_unit_ngu_socket_config { std::string bind_addr = "auto"; std::string bind_interface = "auto"; std::string ext_addr = "auto"; - bool no_core = false; udp_appconfig udp_config = {}; }; +struct cu_up_unit_ngu_config { + bool no_core = false; + std::vector ngu_socket_cfg; +}; + /// F1-U configuration at CU_UP side struct cu_cp_unit_f1u_config { int32_t t_notify; ///< Maximum backoff time for discard notifications from CU_UP to DU (ms) diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp index b4d0a7dc19..93c7a32dbd 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp @@ -17,20 +17,16 @@ using namespace srsran; +// static void configure_cli11_ngu_socket_args(CLI::App& app, cu_up_unit_ngu_config& ngu_params) +//{ +// // TODO Fixup +// } + static void configure_cli11_ngu_args(CLI::App& app, cu_up_unit_ngu_config& ngu_params) { - add_option(app, "--bind_addr", ngu_params.bind_addr, "Local IP address to bind for N3 interface") - ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); - add_option(app, "--bind_interface", ngu_params.bind_interface, "Network device to bind for N3 interface") - ->capture_default_str(); - add_option(app, - "--ext_addr", - ngu_params.ext_addr, - "External IP address that is advertised to receive GTP-U packets from UPF via N3 interface") - ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); add_option(app, "--no_core", ngu_params.no_core, "Allow gNB to run without a core"); - configure_cli11_with_udp_config_schema(app, ngu_params.udp_config); + // Add option for multiple sockets, for usage with different slices, 5QIs or parallization. } static void configure_cli11_cu_up_args(CLI::App& app, cu_up_unit_config& cu_up_params) diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp index 1730dafbfe..2c9e3b34a4 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp @@ -23,11 +23,13 @@ srs_cu_up::cu_up_config srsran::generate_cu_up_config(const cu_up_unit_config& c out_cfg.n3_cfg.gtpu_reordering_timer = std::chrono::milliseconds{config.gtpu_reordering_timer_ms}; out_cfg.n3_cfg.warn_on_drop = config.warn_on_drop; + /* TODO fixup out_cfg.net_cfg.n3_bind_addr = config.ngu_cfg.bind_addr; out_cfg.net_cfg.n3_ext_addr = config.ngu_cfg.ext_addr; out_cfg.net_cfg.n3_bind_interface = config.ngu_cfg.bind_interface; out_cfg.net_cfg.n3_rx_max_mmsg = config.ngu_cfg.udp_config.rx_max_mmsg; out_cfg.net_cfg.pool_threshold = config.ngu_cfg.udp_config.pool_occupancy_threshold; + */ out_cfg.test_mode_cfg.enabled = config.test_mode_cfg.enabled; out_cfg.test_mode_cfg.integrity_enabled = config.test_mode_cfg.integrity_enabled; diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp index 57f481f8fe..5a05d67973 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp @@ -14,18 +14,20 @@ using namespace srsran; -static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) -{ - node["max_rx_msgs"] = config.rx_max_mmsg; -} +// static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) +//{ +// node["max_rx_msgs"] = config.rx_max_mmsg; +//} static void fill_cu_up_ngu_section(YAML::Node node, const cu_up_unit_ngu_config& config) { + /* node["bind_addr"] = config.bind_addr; node["bind_interface"] = config.bind_interface; node["ext_addr"] = config.ext_addr; node["no_core"] = config.no_core; fill_cu_up_udp_section(node["udp"], config.udp_config); + */ } static void fill_cu_up_metrics_section(YAML::Node node, const cu_up_unit_metrics_config& config) From 856d7123527df180309e6efe33010e2b9c56101e Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 20 Nov 2024 12:13:17 +0000 Subject: [PATCH 033/227] cu_up: Remove net_cfg from CU-UP config --- apps/cu/cu.cpp | 7 ++- apps/gnb/gnb.cpp | 7 ++- apps/services/network/CMakeLists.txt | 3 +- apps/units/o_cu_up/cu_up/cu_up_unit_config.h | 4 +- .../cu_up/cu_up_unit_config_cli11_schema.cpp | 33 +++++++++++-- .../cu_up/cu_up_unit_config_translators.cpp | 8 ---- .../cu_up/cu_up_unit_config_yaml_writer.cpp | 15 +++--- apps/units/o_cu_up/o_cu_up_builder.cpp | 9 +++- include/srsran/cu_up/cu_up_config.h | 2 - lib/cu_up/cu_up_impl.cpp | 2 +- lib/cu_up/cu_up_manager_impl.cpp | 10 ++-- lib/cu_up/cu_up_manager_impl.h | 1 - lib/cu_up/pdu_session_manager_impl.cpp | 16 +++---- lib/cu_up/pdu_session_manager_impl.h | 2 - lib/cu_up/ue_context.h | 2 - lib/cu_up/ue_manager.cpp | 2 - lib/cu_up/ue_manager.h | 6 +-- tests/unittests/cu_up/cu_up_test.cpp | 48 ++++++++++--------- .../cu_up/pdu_session_manager_test.cpp | 9 ++-- .../cu_up/pdu_session_manager_test.h | 24 ++++------ tests/unittests/cu_up/ue_manager_test.cpp | 3 +- 21 files changed, 108 insertions(+), 105 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 04e6bf31a4..1400278d69 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -145,10 +145,9 @@ static void autoderive_cu_up_parameters_after_parsing(o_cu_up_unit_config& o const cu_cp_unit_config& cu_cp_cfg) { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. - /* TODO Fixup - if (o_cu_up_cfg.cu_up_cfg.ngu_cfg.bind_addr == "auto") { - o_cu_up_cfg.cu_up_cfg.ngu_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; - }*/ + if (o_cu_up_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg.empty()) { + // TODO auto generate configs + } o_cu_up_cfg.cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; o_cu_up_cfg.e2_cfg.pcaps.enabled = o_cu_up_cfg.e2_cfg.base_config.enable_unit_e2 && o_cu_up_cfg.e2_cfg.pcaps.enabled; } diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 0625eb1ee8..122b95cb3d 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -168,10 +168,9 @@ static void autoderive_slicing_args(du_high_unit_config& du_hi_cfg, cu_cp_unit_c static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_cfg, const cu_cp_unit_config& cu_cp_cfg) { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. - /* TODO fixup - if (cu_up_cfg.ngu_cfg.bind_addr == "auto") { - cu_up_cfg.ngu_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; - }*/ + if (cu_up_cfg.ngu_cfg.ngu_socket_cfg.empty()) { + // create default socket config + } cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; } diff --git a/apps/services/network/CMakeLists.txt b/apps/services/network/CMakeLists.txt index 823539990c..94b7063c02 100644 --- a/apps/services/network/CMakeLists.txt +++ b/apps/services/network/CMakeLists.txt @@ -6,8 +6,7 @@ # the distribution. # -set(SOURCES - udp_cli11_schema.cpp) +set(SOURCES udp_cli11_schema.cpp) add_library(srsran_network_app_service STATIC ${SOURCES}) target_include_directories(srsran_network_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config.h b/apps/units/o_cu_up/cu_up/cu_up_unit_config.h index 8b08f0e61f..2ff313eece 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config.h +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config.h @@ -34,8 +34,8 @@ struct cu_up_unit_ngu_socket_config { }; struct cu_up_unit_ngu_config { - bool no_core = false; - std::vector ngu_socket_cfg; + bool no_core = false; + std::vector ngu_socket_cfg; }; /// F1-U configuration at CU_UP side diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp index 93c7a32dbd..5c26dc69f7 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp @@ -17,16 +17,41 @@ using namespace srsran; -// static void configure_cli11_ngu_socket_args(CLI::App& app, cu_up_unit_ngu_config& ngu_params) -//{ -// // TODO Fixup -// } +static void configure_cli11_ngu_socket_args(CLI::App& app, cu_up_unit_ngu_socket_config& ngu_sock_params) +{ + add_option(app, "--bind_addr", ngu_sock_params.bind_addr, "Local IP address to bind for N3 interface") + ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); + add_option(app, "--bind_interface", ngu_sock_params.bind_interface, "Network device to bind for N3 interface") + ->capture_default_str(); + add_option(app, + "--ext_addr", + ngu_sock_params.ext_addr, + "External IP address that is advertised to receive GTP-U packets from UPF via N3 interface") + ->check(CLI::ValidIPV4 | CLI::IsMember({"auto"})); + + configure_cli11_with_udp_config_schema(app, ngu_sock_params.udp_config); +} static void configure_cli11_ngu_args(CLI::App& app, cu_up_unit_ngu_config& ngu_params) { add_option(app, "--no_core", ngu_params.no_core, "Allow gNB to run without a core"); // Add option for multiple sockets, for usage with different slices, 5QIs or parallization. + auto sock_lambda = [&ngu_params](const std::vector& values) { + // Prepare the radio bearers + ngu_params.ngu_socket_cfg.resize(values.size()); + + // Format every QoS setting. + for (unsigned i = 0, e = values.size(); i != e; ++i) { + CLI::App subapp("NG-U socket parameters", "NG-U socket config, item #" + std::to_string(i)); + subapp.config_formatter(create_yaml_config_parser()); + subapp.allow_config_extras(CLI::config_extras_mode::capture); + configure_cli11_ngu_socket_args(subapp, ngu_params.ngu_socket_cfg[i]); + std::istringstream ss(values[i]); + subapp.parse_from_stream(ss); + } + }; + add_option_cell(app, "--socket", sock_lambda, "Configures UDP/IP socket parameters of the N3 interface"); } static void configure_cli11_cu_up_args(CLI::App& app, cu_up_unit_config& cu_up_params) diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp index 2c9e3b34a4..10371e26c6 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_translators.cpp @@ -23,14 +23,6 @@ srs_cu_up::cu_up_config srsran::generate_cu_up_config(const cu_up_unit_config& c out_cfg.n3_cfg.gtpu_reordering_timer = std::chrono::milliseconds{config.gtpu_reordering_timer_ms}; out_cfg.n3_cfg.warn_on_drop = config.warn_on_drop; - /* TODO fixup - out_cfg.net_cfg.n3_bind_addr = config.ngu_cfg.bind_addr; - out_cfg.net_cfg.n3_ext_addr = config.ngu_cfg.ext_addr; - out_cfg.net_cfg.n3_bind_interface = config.ngu_cfg.bind_interface; - out_cfg.net_cfg.n3_rx_max_mmsg = config.ngu_cfg.udp_config.rx_max_mmsg; - out_cfg.net_cfg.pool_threshold = config.ngu_cfg.udp_config.pool_occupancy_threshold; - */ - out_cfg.test_mode_cfg.enabled = config.test_mode_cfg.enabled; out_cfg.test_mode_cfg.integrity_enabled = config.test_mode_cfg.integrity_enabled; return out_cfg; diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp index 5a05d67973..c3a1512a2c 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp @@ -14,21 +14,22 @@ using namespace srsran; -// static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) -//{ -// node["max_rx_msgs"] = config.rx_max_mmsg; -//} +[[maybe_unused]] +static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) +{ + node["max_rx_msgs"] = config.rx_max_mmsg; +} +/* static void fill_cu_up_ngu_section(YAML::Node node, const cu_up_unit_ngu_config& config) { - /* node["bind_addr"] = config.bind_addr; node["bind_interface"] = config.bind_interface; node["ext_addr"] = config.ext_addr; node["no_core"] = config.no_core; fill_cu_up_udp_section(node["udp"], config.udp_config); - */ } +*/ static void fill_cu_up_metrics_section(YAML::Node node, const cu_up_unit_metrics_config& config) { @@ -109,7 +110,7 @@ void srsran::fill_cu_up_config_in_yaml_schema(YAML::Node& node, const cu_up_unit fill_cu_up_log_section(node["log"], config.loggers); fill_cu_up_pcap_section(node["pcap"], config.pcap_cfg); fill_cu_up_metrics_section(node["metrics"], config.metrics); - fill_cu_up_ngu_section(node["ngu"], config.ngu_cfg); + // fill_cu_up_ngu_section(node["ngu"], config.ngu_cfg); fill_cu_up_qos_section(node, config.qos_cfg); } diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index bb4b816395..296ca939c4 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -62,16 +62,21 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ auto address = dependencies.f1u_gateway->get_cu_bind_address(); srsran_assert(address.has_value(), "Invalid F1-U bind address"); - config.cu_up_cfg.net_cfg.f1u_bind_addr = address.value(); + // TODO get bind addr from f1u gw + // config.cu_up_cfg.net_cfg.f1u_bind_addr = address.value(); + // Create NG-U gateway. std::unique_ptr ngu_gw; if (not unit_cfg.cu_up_cfg.ngu_cfg.no_core) { udp_network_gateway_config ngu_gw_config = {}; + // TODO create multiple gateways from vector of configurations + /* ngu_gw_config.bind_address = config.cu_up_cfg.net_cfg.n3_bind_addr; ngu_gw_config.bind_port = config.cu_up_cfg.net_cfg.n3_bind_port; ngu_gw_config.bind_interface = config.cu_up_cfg.net_cfg.n3_bind_interface; ngu_gw_config.rx_max_mmsg = config.cu_up_cfg.net_cfg.n3_rx_max_mmsg; - ngu_gw = srs_cu_up::create_udp_ngu_gateway( + */ + ngu_gw = srs_cu_up::create_udp_ngu_gateway( ngu_gw_config, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); } else { ngu_gw = srs_cu_up::create_no_core_ngu_gateway(); diff --git a/include/srsran/cu_up/cu_up_config.h b/include/srsran/cu_up/cu_up_config.h index 50bb6eb6e0..f0270b7ab6 100644 --- a/include/srsran/cu_up/cu_up_config.h +++ b/include/srsran/cu_up/cu_up_config.h @@ -73,8 +73,6 @@ struct cu_up_test_mode_config { struct cu_up_config { /// 5QI as key. std::map qos; - /// Network interface configuration. - network_interface_config net_cfg; /// N3 configuration. n3_interface_config n3_cfg; /// Test mode configuration. diff --git a/lib/cu_up/cu_up_impl.cpp b/lib/cu_up/cu_up_impl.cpp index ee65a10299..01c31d7365 100644 --- a/lib/cu_up/cu_up_impl.cpp +++ b/lib/cu_up/cu_up_impl.cpp @@ -31,7 +31,7 @@ static void assert_cu_up_dependencies_valid(const cu_up_dependencies& dependenci static cu_up_manager_impl_config generate_cu_up_manager_impl_config(const cu_up_config& config) { - return {config.qos, config.net_cfg, config.n3_cfg, config.test_mode_cfg}; + return {config.qos, config.n3_cfg, config.test_mode_cfg}; } static cu_up_manager_impl_dependencies diff --git a/lib/cu_up/cu_up_manager_impl.cpp b/lib/cu_up/cu_up_manager_impl.cpp index 72c696e533..8449ef84f4 100644 --- a/lib/cu_up/cu_up_manager_impl.cpp +++ b/lib/cu_up/cu_up_manager_impl.cpp @@ -27,11 +27,10 @@ void process_successful_pdu_resource_setup_mod_outcome( pdu_session_resource_setup_list, const pdu_session_setup_result& result); -static ue_manager_config generate_ue_manager_config(const network_interface_config& net_config, - const n3_interface_config& n3_config, - const cu_up_test_mode_config& test_mode_config) +static ue_manager_config generate_ue_manager_config(const n3_interface_config& n3_config, + const cu_up_test_mode_config& test_mode_config) { - return {net_config, n3_config, test_mode_config}; + return {n3_config, test_mode_config}; } static ue_manager_dependencies generate_ue_manager_dependencies(const cu_up_manager_impl_dependencies& dependencies, @@ -52,14 +51,13 @@ static ue_manager_dependencies generate_ue_manager_dependencies(const cu_up_mana cu_up_manager_impl::cu_up_manager_impl(const cu_up_manager_impl_config& config, const cu_up_manager_impl_dependencies& dependencies) : qos(config.qos), - net_cfg(config.net_cfg), n3_cfg(config.n3_cfg), test_mode_cfg(config.test_mode_cfg), exec_mapper(dependencies.exec_mapper), timers(dependencies.timers) { /// > Create UE manager - ue_mng = std::make_unique(generate_ue_manager_config(net_cfg, n3_cfg, test_mode_cfg), + ue_mng = std::make_unique(generate_ue_manager_config(n3_cfg, test_mode_cfg), generate_ue_manager_dependencies(dependencies, logger)); } diff --git a/lib/cu_up/cu_up_manager_impl.h b/lib/cu_up/cu_up_manager_impl.h index e1928bbad4..482fc0221b 100644 --- a/lib/cu_up/cu_up_manager_impl.h +++ b/lib/cu_up/cu_up_manager_impl.h @@ -23,7 +23,6 @@ namespace srsran::srs_cu_up { /// CU-UP manager implementation configuration. struct cu_up_manager_impl_config { std::map qos; - network_interface_config net_cfg; n3_interface_config n3_cfg; cu_up_test_mode_config test_mode_cfg; }; diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 7e9a799afc..eb2e1f034c 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -23,7 +23,6 @@ using namespace srs_cu_up; pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t ue_index_, std::map qos_cfg_, const security::sec_as_config& security_info_, - const network_interface_config& net_config_, const n3_interface_config& n3_config_, const cu_up_test_mode_config& test_mode_config_, cu_up_ue_logger& logger_, @@ -44,7 +43,6 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t ue_index(ue_index_), qos_cfg(std::move(qos_cfg_)), security_info(security_info_), - net_config(net_config_), n3_config(n3_config_), test_mode_config(test_mode_config_), logger(logger_), @@ -103,9 +101,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ ul_tunnel_info.tp_address); // Advertise either local or external IP address of N3 interface - const std::string& n3_addr = net_config.n3_ext_addr.empty() || net_config.n3_ext_addr == "auto" - ? net_config.n3_bind_addr - : net_config.n3_ext_addr; + const std::string& n3_addr = "8.8.8.8"; // TODO get bind addr from GW. pdu_session_result.gtp_tunnel = up_transport_layer_info(transport_layer_address::create_from_string(n3_addr), new_session->local_teid); @@ -118,7 +114,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ msg.ue_index = ue_index; msg.cfg.tx.peer_teid = int_to_gtpu_teid(ul_tunnel_info.gtp_teid.value()); msg.cfg.tx.peer_addr = ul_tunnel_info.tp_address.to_string(); - msg.cfg.tx.peer_port = net_config.upf_port; + msg.cfg.tx.peer_port = GTPU_PORT; // TODO get actual port from GW msg.cfg.rx.local_teid = new_session->local_teid; msg.cfg.rx.t_reordering = n3_config.gtpu_reordering_timer; msg.cfg.rx.warn_expired_t_reordering = n3_config.warn_on_drop; @@ -463,10 +459,10 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif logger.log_info("Attaching dl_teid={} to F1-U tunnel with ul_teid={}", drb_to_mod.dl_up_params[0].up_tnl_info, drb_iter->second->f1u_ul_teid); - f1u_gw.attach_dl_teid( - up_transport_layer_info(transport_layer_address::create_from_string(net_config.f1u_bind_addr), - drb_iter->second->f1u_ul_teid), - drb_to_mod.dl_up_params[0].up_tnl_info); + f1u_gw.attach_dl_teid(up_transport_layer_info(transport_layer_address::create_from_string( + "8.8.8.8") /*TODO get bind addr from gateway*/, + drb_iter->second->f1u_ul_teid), + drb_to_mod.dl_up_params[0].up_tnl_info); drb_iter->second->pdcp_to_f1u_adapter.connect_f1u(drb_iter->second->f1u->get_tx_sdu_handler()); } diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index 5eb205aed8..21318d130c 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -33,7 +33,6 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl pdu_session_manager_impl(ue_index_t ue_index_, std::map qos_cfg_, const security::sec_as_config& security_info_, - const network_interface_config& net_config_, const n3_interface_config& n3_config_, const cu_up_test_mode_config& test_mode_config_, cu_up_ue_logger& logger_, @@ -76,7 +75,6 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl ue_index_t ue_index; const std::map qos_cfg; const security::sec_as_config& security_info; - const network_interface_config& net_config; const n3_interface_config& n3_config; cu_up_test_mode_config test_mode_config; cu_up_ue_logger& logger; diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index 094e28a261..d9425c0800 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -40,7 +40,6 @@ class ue_context : public pdu_session_manager_ctrl ue_context(ue_index_t index_, ue_context_cfg cfg_, e1ap_control_message_handler& e1ap_, - const network_interface_config& net_config_, const n3_interface_config& n3_config_, const cu_up_test_mode_config& test_mode_config_, std::unique_ptr ue_exec_mapper_, @@ -63,7 +62,6 @@ class ue_context : public pdu_session_manager_ctrl pdu_session_manager(index, cfg.qos, cfg.security_info, - net_config_, n3_config_, test_mode_config_, logger, diff --git a/lib/cu_up/ue_manager.cpp b/lib/cu_up/ue_manager.cpp index 2395a0fb89..d5a72c4f78 100644 --- a/lib/cu_up/ue_manager.cpp +++ b/lib/cu_up/ue_manager.cpp @@ -15,7 +15,6 @@ using namespace srsran; using namespace srs_cu_up; ue_manager::ue_manager(const ue_manager_config& config, const ue_manager_dependencies& dependencies) : - net_config(config.net_config), n3_config(config.n3_config), test_mode_config(config.test_mode_config), e1ap(dependencies.e1ap), @@ -69,7 +68,6 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) std::unique_ptr new_ctx = std::make_unique(new_idx, ue_cfg, e1ap, - net_config, n3_config, test_mode_config, std::move(ue_exec_mapper), diff --git a/lib/cu_up/ue_manager.h b/lib/cu_up/ue_manager.h index ff88030ea3..80ac9fd1fa 100644 --- a/lib/cu_up/ue_manager.h +++ b/lib/cu_up/ue_manager.h @@ -23,9 +23,8 @@ namespace srs_cu_up { /// UE manager configuration. struct ue_manager_config { - const network_interface_config& net_config; - const n3_interface_config& n3_config; - const cu_up_test_mode_config& test_mode_config; + const n3_interface_config& n3_config; + const cu_up_test_mode_config& test_mode_config; }; /// UE manager dependencies. @@ -63,7 +62,6 @@ class ue_manager : public ue_manager_ctrl /// \return The UE index. ue_index_t get_next_ue_index(); - const network_interface_config& net_config; const n3_interface_config& n3_config; const cu_up_test_mode_config& test_mode_config; e1ap_control_message_handler& e1ap; diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index 513a9318fe..360078a17b 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -108,8 +108,9 @@ class cu_up_test : public ::testing::Test // create config cu_up_config cfg; - cfg.qos[uint_to_five_qi(9)] = {}; - cfg.net_cfg.n3_bind_port = 0; // Random free port selected by the OS. + cfg.qos[uint_to_five_qi(9)] = {}; + // cfg.net_cfg.n3_bind_port = 0; // Random free port selected by the OS. + cfg.n3_cfg.gtpu_reordering_timer = std::chrono::milliseconds(0); cfg.n3_cfg.warn_on_drop = false; cfg.statistics_report_period = std::chrono::seconds(1); @@ -132,10 +133,10 @@ class cu_up_test : public ::testing::Test void init(const cu_up_config& cfg, cu_up_dependencies&& deps) { udp_network_gateway_config udp_cfg{}; - udp_cfg.bind_interface = cfg.net_cfg.n3_bind_interface; - udp_cfg.bind_address = cfg.net_cfg.n3_bind_addr; - udp_cfg.bind_port = cfg.net_cfg.n3_bind_port; - ngu_gw = create_udp_ngu_gateway(udp_cfg, *broker, *executor); + // udp_cfg.bind_interface = cfg.net_cfg.n3_bind_interface; + // udp_cfg.bind_address = cfg.net_cfg.n3_bind_addr; + // udp_cfg.bind_port = cfg.net_cfg.n3_bind_port; + ngu_gw = create_udp_ngu_gateway(udp_cfg, *broker, *executor); auto cfg_copy = cfg; deps.ngu_gw = ngu_gw.get(); @@ -243,11 +244,11 @@ TEST_F(cu_up_test, when_e1ap_connection_established_then_e1ap_connected) TEST_F(cu_up_test, dl_data_flow) { cu_up_config cfg = get_default_cu_up_config(); - test_logger.debug("Using network_interface_config: {}", cfg.net_cfg); + // test_logger.debug("Using network_interface_config: {}", cfg.net_cfg); // Initialize UPF simulator on a random port. - upf_info_t upf_info = init_upf(); - cfg.net_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); + upf_info_t upf_info = init_upf(); + // cfg.net_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); ASSERT_GE(upf_info.sock_fd, 0); cu_up_dependencies dependencies = get_defatul_cu_up_dependencies(); @@ -262,11 +263,11 @@ TEST_F(cu_up_test, dl_data_flow) // UL message 1 nru_ul_message nru_msg1 = {}; const uint8_t t_pdu_arr1[] = { - 0x80, 0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0xe8, 0x83, 0x40, 0x00, 0x40, 0x01, 0xfa, 0x00, 0xac, 0x10, 0x00, - 0x03, 0xac, 0x10, 0x00, 0x01, 0x08, 0x00, 0x2c, 0xbe, 0xb4, 0xa4, 0x00, 0x01, 0xd3, 0x45, 0x61, 0x63, 0x00, - 0x00, 0x00, 0x00, 0x1a, 0x20, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + 0x80, 0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0xe8, 0x83, 0x40, 0x00, 0x40, 0x01, 0xfa, 0x00, 0xac, 0x10, 0x00, + 0x03, 0xac, 0x10, 0x00, 0x01, 0x08, 0x00, 0x2c, 0xbe, 0xb4, 0xa4, 0x00, 0x01, 0xd3, 0x45, 0x61, 0x63, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0x20, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; span t_pdu_span1 = {t_pdu_arr1}; byte_buffer t_pdu_buf1 = byte_buffer::create(t_pdu_span1).value(); nru_msg1.t_pdu = byte_buffer_chain::create(std::move(t_pdu_buf1)).value(); @@ -279,17 +280,17 @@ TEST_F(cu_up_test, dl_data_flow) // We wait here for the UL PDU to arrive, to make sure the DDDS has been processed. // receive message 1 std::array rx_buf; - int ret; + [[maybe_unused]] int ret; ret = recv(upf_info.sock_fd, rx_buf.data(), rx_buf.size(), 0); // Now that the disered buffer size is updated, we push DL PDUs - sockaddr_in cu_up_addr; - cu_up_addr.sin_family = AF_INET; - cu_up_addr.sin_port = htons(cu_up->get_n3_bind_port().value()); - cu_up_addr.sin_addr.s_addr = inet_addr(cfg.net_cfg.n3_bind_addr.c_str()); + [[maybe_unused]] sockaddr_in cu_up_addr; + cu_up_addr.sin_family = AF_INET; + cu_up_addr.sin_port = htons(cu_up->get_n3_bind_port().value()); + // cu_up_addr.sin_addr.s_addr = inet_addr(cfg.net_cfg.n3_bind_addr.c_str()); // DL PDU teid=2, qfi=1 - const uint8_t gtpu_ping_vec[] = { + [[maybe_unused]] const uint8_t gtpu_ping_vec[] = { 0x34, 0xff, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x01, 0x00, 0x45, 0x00, 0x00, 0x54, 0x9b, 0xfb, 0x00, 0x00, 0x40, 0x01, 0x56, 0x5a, 0xc0, 0xa8, 0x04, 0x01, 0xc0, 0xa8, 0x03, 0x02, 0x00, 0x00, 0xb8, 0xc0, 0x00, 0x02, 0x00, 0x01, 0x5d, 0x26, 0x77, 0x64, 0x00, 0x00, 0x00, @@ -298,6 +299,7 @@ TEST_F(cu_up_test, dl_data_flow) 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; // send message 1 + /* ret = sendto(upf_info.sock_fd, gtpu_ping_vec, sizeof(gtpu_ping_vec), 0, (sockaddr*)&cu_up_addr, sizeof(cu_up_addr)); ASSERT_GE(ret, 0) << "Failed to send message via sock_fd=" << upf_info.sock_fd << " to `" << cfg.net_cfg.n3_bind_addr << ":" << cu_up->get_n3_bind_port().value() << "` - " << strerror(errno); @@ -306,7 +308,7 @@ TEST_F(cu_up_test, dl_data_flow) ret = sendto(upf_info.sock_fd, gtpu_ping_vec, sizeof(gtpu_ping_vec), 0, (sockaddr*)&cu_up_addr, sizeof(cu_up_addr)); ASSERT_GE(ret, 0) << "Failed to send message via sock_fd=" << upf_info.sock_fd << " to `" << cfg.net_cfg.n3_bind_addr << ":" << cu_up->get_n3_bind_port().value() << "` - " << strerror(errno); - + */ close(upf_info.sock_fd); // check reception of message 1 @@ -336,8 +338,8 @@ TEST_F(cu_up_test, ul_data_flow) upf_info_t upf_info = init_upf(); //> Test main part: create CU-UP and transmit data - cfg.net_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); - test_logger.debug("Using network_interface_config: {}", cfg.net_cfg); + // cfg.net_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); + // test_logger.debug("Using network_interface_config: {}", cfg.net_cfg); cu_up_dependencies dependencies = get_defatul_cu_up_dependencies(); init(cfg, std::move(dependencies)); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.cpp b/tests/unittests/cu_up/pdu_session_manager_test.cpp index c85dca8b51..5076954a66 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.cpp +++ b/tests/unittests/cu_up/pdu_session_manager_test.cpp @@ -35,9 +35,12 @@ TEST_P(pdu_session_manager_test_set_n3_ext_addr, when_valid_pdu_session_setup_it // check successful outcome ASSERT_TRUE(setup_result.success); ASSERT_EQ(setup_result.gtp_tunnel.gtp_teid.value(), 1); - const std::string tp_address_expect = net_config.n3_ext_addr.empty() || net_config.n3_ext_addr == "auto" - ? net_config.n3_bind_addr - : net_config.n3_ext_addr; + + // TODO fixup + const std::string tp_address_expect = "8.8.8.8"; + // const std::string tp_address_expect = net_config.n3_ext_addr.empty() || net_config.n3_ext_addr == "auto" + // ? net_config.n3_bind_addr + // : net_config.n3_ext_addr; ASSERT_EQ(setup_result.gtp_tunnel.tp_address.to_string(), tp_address_expect); ASSERT_EQ(setup_result.drb_setup_results[0].gtp_tunnel.gtp_teid.value(), 1); ASSERT_EQ(pdu_session_mng->get_nof_pdu_sessions(), 1); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index f7bf0ff8f4..b3aa396113 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -18,14 +18,11 @@ namespace srsran { namespace srs_cu_up { -const network_interface_config net_config_default = {}; - /// Fixture base class for PDU session manager tests class pdu_session_manager_test_base { protected: - virtual ~pdu_session_manager_test_base() = default; - virtual network_interface_config get_net_config() = 0; + virtual ~pdu_session_manager_test_base() = default; void init() { @@ -48,11 +45,10 @@ class pdu_session_manager_test_base manual_task_worker teid_worker{128}; - net_config = get_net_config(); + // TODO add dummy gateway pdu_session_mng = std::make_unique(MIN_UE_INDEX, qos, security_info, - net_config, n3_config, cu_up_test_mode_config{}, logger, @@ -91,7 +87,6 @@ class pdu_session_manager_test_base std::unique_ptr pdu_session_mng; null_dlt_pcap gtpu_pcap; security::sec_as_config security_info; - network_interface_config net_config; n3_interface_config n3_config = {}; cu_up_ue_logger logger{"CU-UP", {MIN_UE_INDEX}}; }; @@ -100,9 +95,8 @@ class pdu_session_manager_test_base class pdu_session_manager_test : public pdu_session_manager_test_base, public ::testing::Test { protected: - network_interface_config get_net_config() override { return net_config_default; } - void SetUp() override { init(); } - void TearDown() override { finish(); } + void SetUp() override { init(); } + void TearDown() override { finish(); } }; /// Fixture class for PDU session manager tests with configurable N3 ext addr @@ -110,12 +104,14 @@ class pdu_session_manager_test_set_n3_ext_addr : public pdu_session_manager_test public ::testing::TestWithParam { protected: - network_interface_config get_net_config() override - { - network_interface_config cfg = net_config_default; + // TODO is this still needed? + /* +network_interface_config get_net_config() override +{ cfg.n3_ext_addr = GetParam(); return cfg; - } +} + */ void SetUp() override { init(); } void TearDown() override { finish(); } }; diff --git a/tests/unittests/cu_up/ue_manager_test.cpp b/tests/unittests/cu_up/ue_manager_test.cpp index e2559928b0..65ee0722be 100644 --- a/tests/unittests/cu_up/ue_manager_test.cpp +++ b/tests/unittests/cu_up/ue_manager_test.cpp @@ -40,7 +40,7 @@ class ue_manager_test : public ::testing::Test ue_cfg = {security::sec_as_config{}, activity_notification_level_t::ue, std::chrono::seconds(0)}; // create DUT object - ue_mng = std::make_unique(ue_manager_config{net_config, n3_config, test_mode_config}, + ue_mng = std::make_unique(ue_manager_config{n3_config, test_mode_config}, ue_manager_dependencies{*e1ap, timers, *f1u_gw, @@ -71,7 +71,6 @@ class ue_manager_test : public ::testing::Test timer_manager timers; ue_context_cfg ue_cfg; std::unique_ptr ue_mng; - network_interface_config net_config; n3_interface_config n3_config; cu_up_test_mode_config test_mode_config{}; srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST", false); From 93a86794b4802d4a2a2aa64c0e82eabb2d5c975b Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 20 Nov 2024 13:28:44 +0000 Subject: [PATCH 034/227] cu_up: create multiple gateways at CU-UP wrapper --- apps/cu/cu.cpp | 15 ++++++++- apps/gnb/gnb.cpp | 4 ++- apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp | 37 ++++++++++++++++++++++ apps/units/o_cu_up/o_cu_up_builder.cpp | 36 ++++++++++++--------- apps/units/o_cu_up/o_cu_up_unit_impl.cpp | 10 +++--- apps/units/o_cu_up/o_cu_up_unit_impl.h | 12 +++---- 6 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 1400278d69..e1e7a2f53b 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -146,7 +146,9 @@ static void autoderive_cu_up_parameters_after_parsing(o_cu_up_unit_config& o { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. if (o_cu_up_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg.empty()) { - // TODO auto generate configs + cu_up_unit_ngu_socket_config sock_cfg; + sock_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; + o_cu_up_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg.push_back(sock_cfg); } o_cu_up_cfg.cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; o_cu_up_cfg.e2_cfg.pcaps.enabled = o_cu_up_cfg.e2_cfg.base_config.enable_unit_e2 && o_cu_up_cfg.e2_cfg.pcaps.enabled; @@ -266,6 +268,17 @@ int main(int argc, char** argv) io_broker_config io_broker_cfg(low_prio_cpu_mask); std::unique_ptr epoll_broker = create_io_broker(io_broker_type::epoll, io_broker_cfg); + // Create NG-U GWs + cu_up_unit_ngu_config& ngu_cfg = o_cu_up_app_unit->get_o_cu_up_unit_config().cu_up_cfg.ngu_cfg; + for (srsran::cu_up_unit_ngu_socket_config& sock_cfg : ngu_cfg.ngu_socket_cfg) { + udp_network_gateway_config n3_udp_cfg = {}; + n3_udp_cfg.bind_address = sock_cfg.bind_addr; + n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; + n3_udp_cfg.bind_port = GTPU_PORT; + n3_udp_cfg.rx_max_mmsg = sock_cfg.udp_config.rx_max_mmsg; + n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; + } + // Create F1-C GW (TODO cleanup port and PPID args with factory) sctp_network_gateway_config f1c_sctp_cfg = {}; f1c_sctp_cfg.if_name = "F1-C"; diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 122b95cb3d..30d5c5692b 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -169,7 +169,9 @@ static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_c { // If no UPF is configured, we set the UPF configuration from the CU-CP AMF configuration. if (cu_up_cfg.ngu_cfg.ngu_socket_cfg.empty()) { - // create default socket config + cu_up_unit_ngu_socket_config sock_cfg; + sock_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; + cu_up_cfg.ngu_cfg.ngu_socket_cfg.push_back(sock_cfg); } cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; } diff --git a/apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp b/apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp new file mode 100644 index 0000000000..0834b5aa8f --- /dev/null +++ b/apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp @@ -0,0 +1,37 @@ +/* + * + * 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 "cu_up_wrapper.h" + +using namespace srsran; + +cu_up_wrapper::cu_up_wrapper(std::vector> gateways_, + std::unique_ptr e2_metric_connector_, + std::unique_ptr cu_up_) : + gateways(std::move(gateways_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) +{ + srsran_assert(not gateways.empty(), "Invlid NGU gateways"); + srsran_assert(cu_up, "Invalid CU-UP"); +} + +void cu_up_wrapper::start() +{ + cu_up->start(); +} + +void cu_up_wrapper::stop() +{ + cu_up->stop(); +} + +std::optional cu_up_wrapper::get_n3_bind_port() +{ + return cu_up->get_n3_bind_port(); +} diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 296ca939c4..a2d2a7faf9 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -65,23 +65,29 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ // TODO get bind addr from f1u gw // config.cu_up_cfg.net_cfg.f1u_bind_addr = address.value(); - // Create NG-U gateway. - std::unique_ptr ngu_gw; + // Create NG-U gateway(s). + std::vector> ngu_gws; if (not unit_cfg.cu_up_cfg.ngu_cfg.no_core) { - udp_network_gateway_config ngu_gw_config = {}; - // TODO create multiple gateways from vector of configurations - /* - ngu_gw_config.bind_address = config.cu_up_cfg.net_cfg.n3_bind_addr; - ngu_gw_config.bind_port = config.cu_up_cfg.net_cfg.n3_bind_port; - ngu_gw_config.bind_interface = config.cu_up_cfg.net_cfg.n3_bind_interface; - ngu_gw_config.rx_max_mmsg = config.cu_up_cfg.net_cfg.n3_rx_max_mmsg; - */ - ngu_gw = srs_cu_up::create_udp_ngu_gateway( - ngu_gw_config, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); + for (const cu_up_unit_ngu_socket_config& sock_cfg : unit_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg) { + udp_network_gateway_config n3_udp_cfg = {}; + n3_udp_cfg.bind_address = sock_cfg.bind_addr; + n3_udp_cfg.bind_interface = sock_cfg.bind_interface; + n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; + n3_udp_cfg.bind_port = GTPU_PORT; + n3_udp_cfg.rx_max_mmsg = sock_cfg.udp_config.rx_max_mmsg; + n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; + n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets + + std::unique_ptr ngu_gw = srs_cu_up::create_udp_ngu_gateway( + n3_udp_cfg, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); + ngu_gws.push_back(std::move(ngu_gw)); + } } else { - ngu_gw = srs_cu_up::create_no_core_ngu_gateway(); + std::unique_ptr ngu_gw = srs_cu_up::create_no_core_ngu_gateway(); + ngu_gws.push_back(std::move(ngu_gw)); } - ocu_up_dependencies.cu_dependencies.ngu_gw = ngu_gw.get(); + + ocu_up_dependencies.cu_dependencies.ngu_gw = ngu_gws[0].get(); // TODO pass actual gateway to CU-UP auto e2_metric_connectors = std::make_unique(); @@ -103,7 +109,7 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ } ocu_unit.unit = - std::make_unique(std::move(ngu_gw), + std::make_unique(std::move(ngu_gws), std::move(e2_metric_connectors), srs_cu_up::create_o_cu_up(config, std::move(ocu_up_dependencies))); diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp index 3c323503b9..35b841d6c8 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp @@ -12,12 +12,12 @@ using namespace srsran; -o_cu_up_unit_impl::o_cu_up_unit_impl(std::unique_ptr gateway_, - std::unique_ptr e2_metric_connector_, - std::unique_ptr cu_up_) : - gateway(std::move(gateway_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) +o_cu_up_unit_impl::o_cu_up_unit_impl(std::vector> gateways_, + std::unique_ptr e2_metric_connector_, + std::unique_ptr cu_up_) : + gateways(std::move(gateways_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) { - srsran_assert(gateway, "Invlid NGU gateway"); + srsran_assert(not gateways.empty(), "Invlid NGU gateway"); srsran_assert(cu_up, "Invalid CU-UP"); } diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.h b/apps/units/o_cu_up/o_cu_up_unit_impl.h index f7bb08c794..6b9167b255 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.h +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.h @@ -27,9 +27,9 @@ using e2_cu_metrics_connector_manager = class o_cu_up_unit_impl : public srs_cu_up::o_cu_up { public: - o_cu_up_unit_impl(std::unique_ptr gateway_, - std::unique_ptr e2_metric_connector_, - std::unique_ptr cu_up_); + o_cu_up_unit_impl(std::vector> gateways_, + std::unique_ptr e2_metric_connector_, + std::unique_ptr cu_up_); // See interface for documentation. srs_cu_up::cu_up_interface& get_cu_up() override; @@ -38,9 +38,9 @@ class o_cu_up_unit_impl : public srs_cu_up::o_cu_up srs_cu_up::cu_up_power_controller& get_power_controller() override; private: - std::unique_ptr gateway; - std::unique_ptr e2_metric_connector; - std::unique_ptr cu_up; + std::vector> gateways; + std::unique_ptr e2_metric_connector; + std::unique_ptr cu_up; }; } // namespace srsran From 8c0e5f92eee7e9294a90dedad78e7687ea924098 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 21 Nov 2024 13:02:59 +0000 Subject: [PATCH 035/227] cu_up: get correct f1u and ngu bind address from GWs --- apps/cu/cu.cpp | 11 ---- apps/units/o_cu_up/o_cu_up_builder.cpp | 6 ++- include/srsran/cu_up/cu_up_config.h | 4 +- lib/cu_up/cu_up_impl.cpp | 35 ++++++++----- lib/cu_up/cu_up_impl.h | 23 ++++---- lib/cu_up/cu_up_manager_impl.cpp | 1 + lib/cu_up/cu_up_manager_impl.h | 19 +++---- lib/cu_up/pdu_session_manager_impl.cpp | 30 +++++++---- lib/cu_up/pdu_session_manager_impl.h | 42 ++++++++------- lib/cu_up/ue_context.h | 34 ++++++------ lib/cu_up/ue_manager.cpp | 2 + lib/cu_up/ue_manager.h | 52 ++++++++++--------- lib/gateways/udp_network_gateway_impl.cpp | 1 + tests/unittests/cu_up/cu_up_test.cpp | 21 ++++---- .../cu_up/pdu_session_manager_test.h | 2 + tests/unittests/cu_up/ue_manager_test.cpp | 1 + 16 files changed, 158 insertions(+), 126 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index e1e7a2f53b..ec708543f7 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -268,17 +268,6 @@ int main(int argc, char** argv) io_broker_config io_broker_cfg(low_prio_cpu_mask); std::unique_ptr epoll_broker = create_io_broker(io_broker_type::epoll, io_broker_cfg); - // Create NG-U GWs - cu_up_unit_ngu_config& ngu_cfg = o_cu_up_app_unit->get_o_cu_up_unit_config().cu_up_cfg.ngu_cfg; - for (srsran::cu_up_unit_ngu_socket_config& sock_cfg : ngu_cfg.ngu_socket_cfg) { - udp_network_gateway_config n3_udp_cfg = {}; - n3_udp_cfg.bind_address = sock_cfg.bind_addr; - n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; - n3_udp_cfg.bind_port = GTPU_PORT; - n3_udp_cfg.rx_max_mmsg = sock_cfg.udp_config.rx_max_mmsg; - n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; - } - // Create F1-C GW (TODO cleanup port and PPID args with factory) sctp_network_gateway_config f1c_sctp_cfg = {}; f1c_sctp_cfg.if_name = "F1-C"; diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index a2d2a7faf9..9055709125 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -87,7 +87,11 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ ngu_gws.push_back(std::move(ngu_gw)); } - ocu_up_dependencies.cu_dependencies.ngu_gw = ngu_gws[0].get(); // TODO pass actual gateway to CU-UP + // Pass NG-U gateways to CU-UP + ocu_up_dependencies.cu_dependencies.ngu_gws.resize(ngu_gws.size()); + for (size_t i = 0; i < ngu_gws.size(); i++) { + ocu_up_dependencies.cu_dependencies.ngu_gws[i] = ngu_gws[i].get(); + } auto e2_metric_connectors = std::make_unique(); diff --git a/include/srsran/cu_up/cu_up_config.h b/include/srsran/cu_up/cu_up_config.h index f0270b7ab6..cea3cea6d9 100644 --- a/include/srsran/cu_up/cu_up_config.h +++ b/include/srsran/cu_up/cu_up_config.h @@ -93,8 +93,6 @@ struct cu_up_dependencies { cu_up_executor_mapper* exec_mapper = nullptr; /// F1-U gateway. f1u_cu_up_gateway* f1u_gateway = nullptr; - /// NGU gateway. - ngu_gateway* ngu_gw = nullptr; /// Time manager. timer_manager* timers = nullptr; /// PCAP. @@ -103,6 +101,8 @@ struct cu_up_dependencies { pdcp_metrics_notifier* pdcp_metric_notifier = nullptr; /// E1AP connection client. e1_connection_client* e1_conn_client = nullptr; + /// NG-U gateways + std::vector ngu_gws; }; } // namespace srs_cu_up diff --git a/lib/cu_up/cu_up_impl.cpp b/lib/cu_up/cu_up_impl.cpp index 01c31d7365..ca1aa972a1 100644 --- a/lib/cu_up/cu_up_impl.cpp +++ b/lib/cu_up/cu_up_impl.cpp @@ -25,7 +25,10 @@ static void assert_cu_up_dependencies_valid(const cu_up_dependencies& dependenci srsran_assert(dependencies.exec_mapper != nullptr, "Invalid CU-UP UE executor pool"); srsran_assert(dependencies.e1_conn_client != nullptr, "Invalid E1 connection client"); srsran_assert(dependencies.f1u_gateway != nullptr, "Invalid F1-U connector"); - srsran_assert(dependencies.ngu_gw != nullptr, "Invalid N3 gateway"); + srsran_assert(not dependencies.ngu_gws.empty(), "Invalid N3 gateway list"); + for (auto* gw : dependencies.ngu_gws) { + srsran_assert(gw != nullptr, "Invalid N3 gateway"); + } srsran_assert(dependencies.gtpu_pcap != nullptr, "Invalid GTP-U pcap"); } @@ -35,16 +38,18 @@ static cu_up_manager_impl_config generate_cu_up_manager_impl_config(const cu_up_ } static cu_up_manager_impl_dependencies -generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, - e1ap_interface& e1ap, - gtpu_network_gateway_adapter& gtpu_gw_adapter, - gtpu_demux& ngu_demux, - gtpu_teid_pool& n3_teid_allocator, - gtpu_teid_pool& f1u_teid_allocator) +generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, + e1ap_interface& e1ap, + gtpu_network_gateway_adapter& gtpu_gw_adapter, + gtpu_demux& ngu_demux, + const std::vector>& ngu_gws, + gtpu_teid_pool& n3_teid_allocator, + gtpu_teid_pool& f1u_teid_allocator) { return {e1ap, gtpu_gw_adapter, ngu_demux, + ngu_gws, n3_teid_allocator, f1u_teid_allocator, *dependencies.exec_mapper, @@ -83,13 +88,17 @@ cu_up::cu_up(const cu_up_config& config_, const cu_up_dependencies& dependencies // Establish new NG-U session and connect the instantiated session to the GTP-U DEMUX adapter, so that the latter // is called when new NG-U DL PDUs are received. - ngu_session = dependencies.ngu_gw->create(gw_data_gtpu_demux_adapter); - if (ngu_session == nullptr) { - report_error("Unable to allocate the required NG-U network resources"); + for (ngu_gateway* gw : dependencies.ngu_gws) { + std::unique_ptr ngu_session = gw->create(gw_data_gtpu_demux_adapter); + if (ngu_session == nullptr) { + report_error("Unable to allocate the required NG-U network resources"); + } + ngu_sessions.push_back(std::move(ngu_session)); } // Connect GTPU GW adapter to NG-U session in order to send UL PDUs. - gtpu_gw_adapter.connect_network_gateway(*ngu_session); + // We use the first UDP GW for UL. + gtpu_gw_adapter.connect_network_gateway(*ngu_sessions[0]); // Create N3 TEID allocator gtpu_allocator_creation_request n3_alloc_msg = {}; @@ -111,7 +120,7 @@ cu_up::cu_up(const cu_up_config& config_, const cu_up_dependencies& dependencies cu_up_mng = std::make_unique( generate_cu_up_manager_impl_config(cfg), generate_cu_up_manager_impl_dependencies( - dependencies, *e1ap, gtpu_gw_adapter, *ngu_demux, *n3_teid_allocator, *f1u_teid_allocator)); + dependencies, *e1ap, gtpu_gw_adapter, *ngu_demux, ngu_sessions, *n3_teid_allocator, *f1u_teid_allocator)); /// > Connect E1AP to CU-UP manager e1ap_cu_up_mng_adapter.connect_cu_up_manager(*cu_up_mng); @@ -212,7 +221,7 @@ void cu_up::stop() } // CU-UP stops listening to new GTPU Rx PDUs. - ngu_session.reset(); + ngu_sessions.clear(); logger.info("CU-UP stopped successfully"); } diff --git a/lib/cu_up/cu_up_impl.h b/lib/cu_up/cu_up_impl.h index dce0d83215..7f7a2cf61f 100644 --- a/lib/cu_up/cu_up_impl.h +++ b/lib/cu_up/cu_up_impl.h @@ -36,8 +36,11 @@ class cu_up final : public cu_up_interface void stop() override; /// helper functions for testing - std::optional get_n3_bind_port() override { return ngu_session->get_bind_port(); } - cu_up_manager* get_cu_up_manager() { return cu_up_mng.get(); } + std::optional get_n3_bind_port() override // TODO include index? + { + return ngu_sessions[0]->get_bind_port(); + } + cu_up_manager* get_cu_up_manager() { return cu_up_mng.get(); } private: void disconnect(); @@ -58,14 +61,14 @@ class cu_up final : public cu_up_interface std::unique_ptr ctrl_exec_mapper; // Components - std::atomic e1ap_connected = {false}; - std::unique_ptr e1ap; - std::unique_ptr ngu_session; - std::unique_ptr ngu_demux; - std::unique_ptr ngu_echo; - std::unique_ptr n3_teid_allocator; - std::unique_ptr f1u_teid_allocator; - std::unique_ptr cu_up_mng; + std::atomic e1ap_connected = {false}; + std::unique_ptr e1ap; + std::vector> ngu_sessions; + std::unique_ptr ngu_demux; + std::unique_ptr ngu_echo; + std::unique_ptr n3_teid_allocator; + std::unique_ptr f1u_teid_allocator; + std::unique_ptr cu_up_mng; // Adapters network_gateway_data_gtpu_demux_adapter gw_data_gtpu_demux_adapter; diff --git a/lib/cu_up/cu_up_manager_impl.cpp b/lib/cu_up/cu_up_manager_impl.cpp index 8449ef84f4..a532c2e4b4 100644 --- a/lib/cu_up/cu_up_manager_impl.cpp +++ b/lib/cu_up/cu_up_manager_impl.cpp @@ -39,6 +39,7 @@ static ue_manager_dependencies generate_ue_manager_dependencies(const cu_up_mana return {dependencies.e1ap, dependencies.timers, dependencies.f1u_gateway, + dependencies.ngu_gws, dependencies.gtpu_gw_adapter, dependencies.ngu_demux, dependencies.n3_teid_allocator, diff --git a/lib/cu_up/cu_up_manager_impl.h b/lib/cu_up/cu_up_manager_impl.h index 482fc0221b..437bc0c0b0 100644 --- a/lib/cu_up/cu_up_manager_impl.h +++ b/lib/cu_up/cu_up_manager_impl.h @@ -29,15 +29,16 @@ struct cu_up_manager_impl_config { /// CU-UP manager implementation dependencies. struct cu_up_manager_impl_dependencies { - e1ap_interface& e1ap; - gtpu_network_gateway_adapter& gtpu_gw_adapter; - gtpu_demux& ngu_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_mapper; - f1u_cu_up_gateway& f1u_gateway; - timer_manager& timers; - dlt_pcap& gtpu_pcap; + e1ap_interface& e1ap; + gtpu_network_gateway_adapter& gtpu_gw_adapter; + gtpu_demux& ngu_demux; + const std::vector>& ngu_gws; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_mapper; + f1u_cu_up_gateway& f1u_gateway; + timer_manager& timers; + dlt_pcap& gtpu_pcap; }; class cu_up_manager_impl final : public cu_up_manager diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index eb2e1f034c..c09703aec9 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -15,6 +15,7 @@ #include "srsran/gtpu/gtpu_tunnel_ngu_factory.h" #include "srsran/pdcp/pdcp_factory.h" #include "srsran/sdap/sdap_factory.h" +#include "srsran/support/srsran_assert.h" #include using namespace srsran; @@ -26,11 +27,12 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t const n3_interface_config& n3_config_, const cu_up_test_mode_config& test_mode_config_, cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + const std::vector>& ngu_gws_, gtpu_teid_pool& n3_teid_allocator_, gtpu_teid_pool& f1u_teid_allocator_, gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, @@ -59,7 +61,8 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t ue_ctrl_exec(ue_ctrl_exec_), crypto_exec(crypto_exec_), gtpu_pcap(gtpu_pcap_), - f1u_gw(f1u_gw_) + f1u_gw(f1u_gw_), + ngu_gws(ngu_gws_) { } @@ -101,7 +104,11 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ ul_tunnel_info.tp_address); // Advertise either local or external IP address of N3 interface - const std::string& n3_addr = "8.8.8.8"; // TODO get bind addr from GW. + // TODO select correct GW based on slice or UE info. + std::string n3_addr; + if (not ngu_gws[0]->get_bind_address(n3_addr)) { + report_error("Could not get NG-U bind addres to report to core."); + } pdu_session_result.gtp_tunnel = up_transport_layer_info(transport_layer_address::create_from_string(n3_addr), new_session->local_teid); @@ -459,8 +466,13 @@ pdu_session_manager_impl::modify_pdu_session(const e1ap_pdu_session_res_to_modif logger.log_info("Attaching dl_teid={} to F1-U tunnel with ul_teid={}", drb_to_mod.dl_up_params[0].up_tnl_info, drb_iter->second->f1u_ul_teid); - f1u_gw.attach_dl_teid(up_transport_layer_info(transport_layer_address::create_from_string( - "8.8.8.8") /*TODO get bind addr from gateway*/, + + expected bind_addr = f1u_gw.get_cu_bind_address(); + if (not bind_addr.has_value()) { + logger.log_error("Could not get bind address for F1-U tunnel"); + continue; + } + f1u_gw.attach_dl_teid(up_transport_layer_info(transport_layer_address::create_from_string(bind_addr.value()), drb_iter->second->f1u_ul_teid), drb_to_mod.dl_up_params[0].up_tnl_info); diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index 21318d130c..99dff65db2 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -30,26 +30,27 @@ namespace srs_cu_up { class pdu_session_manager_impl final : public pdu_session_manager_ctrl { public: - pdu_session_manager_impl(ue_index_t ue_index_, - std::map qos_cfg_, - const security::sec_as_config& security_info_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - task_executor& ue_dl_exec_, - task_executor& ue_ul_exec_, - task_executor& ue_ctrl_exec_, - task_executor& crypto_exec_, - dlt_pcap& gtpu_pcap_); + pdu_session_manager_impl(ue_index_t ue_index_, + std::map qos_cfg_, + const security::sec_as_config& security_info_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + cu_up_ue_logger& logger_, + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + const std::vector>& ngu_gws_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, + gtpu_demux_ctrl& gtpu_rx_demux_, + task_executor& ue_dl_exec_, + task_executor& ue_ul_exec_, + task_executor& ue_ctrl_exec_, + task_executor& crypto_exec_, + dlt_pcap& gtpu_pcap_); pdu_session_setup_result setup_pdu_session(const e1ap_pdu_session_res_to_setup_item& session) override; pdu_session_modification_result modify_pdu_session(const e1ap_pdu_session_res_to_modify_item& session, @@ -92,6 +93,7 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl task_executor& crypto_exec; dlt_pcap& gtpu_pcap; f1u_cu_up_gateway& f1u_gw; + const std::vector>& ngu_gws; std::map> pdu_sessions; // key is pdu_session_id }; diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index d9425c0800..d7218c4788 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -37,22 +37,23 @@ struct ue_context_cfg { class ue_context : public pdu_session_manager_ctrl { public: - ue_context(ue_index_t index_, - ue_context_cfg cfg_, - e1ap_control_message_handler& e1ap_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - std::unique_ptr ue_exec_mapper_, - fifo_async_task_scheduler& task_sched_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - dlt_pcap& gtpu_pcap) : + ue_context(ue_index_t index_, + ue_context_cfg cfg_, + e1ap_control_message_handler& e1ap_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + std::unique_ptr ue_exec_mapper_, + fifo_async_task_scheduler& task_sched_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + const std::vector>& ngu_gws_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, + gtpu_demux_ctrl& gtpu_rx_demux_, + dlt_pcap& gtpu_pcap) : task_sched(task_sched_), ue_exec_mapper(std::move(ue_exec_mapper_)), index(index_), @@ -70,6 +71,7 @@ class ue_context : public pdu_session_manager_ctrl ue_ul_timer_factory_, ue_ctrl_timer_factory_, f1u_gw_, + ngu_gws_, n3_teid_allocator_, f1u_teid_allocator_, gtpu_tx_notifier_, diff --git a/lib/cu_up/ue_manager.cpp b/lib/cu_up/ue_manager.cpp index d5a72c4f78..dcf40142de 100644 --- a/lib/cu_up/ue_manager.cpp +++ b/lib/cu_up/ue_manager.cpp @@ -19,6 +19,7 @@ ue_manager::ue_manager(const ue_manager_config& config, const ue_manager_depende test_mode_config(config.test_mode_config), e1ap(dependencies.e1ap), f1u_gw(dependencies.f1u_gw), + ngu_gws(dependencies.ngu_gws), gtpu_tx_notifier(dependencies.gtpu_tx_notifier), gtpu_rx_demux(dependencies.gtpu_rx_demux), n3_teid_allocator(dependencies.n3_teid_allocator), @@ -76,6 +77,7 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) ue_ul_timer_factory, ue_ctrl_timer_factory, f1u_gw, + ngu_gws, n3_teid_allocator, f1u_teid_allocator, gtpu_tx_notifier, diff --git a/lib/cu_up/ue_manager.h b/lib/cu_up/ue_manager.h index 80ac9fd1fa..d8503be903 100644 --- a/lib/cu_up/ue_manager.h +++ b/lib/cu_up/ue_manager.h @@ -29,16 +29,17 @@ struct ue_manager_config { /// UE manager dependencies. struct ue_manager_dependencies { - e1ap_control_message_handler& e1ap; - timer_manager& timers; - f1u_cu_up_gateway& f1u_gw; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - dlt_pcap& gtpu_pcap; - srslog::basic_logger& logger; + e1ap_control_message_handler& e1ap; + timer_manager& timers; + f1u_cu_up_gateway& f1u_gw; + const std::vector>& ngu_gws; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + dlt_pcap& gtpu_pcap; + srslog::basic_logger& logger; }; class ue_manager : public ue_manager_ctrl @@ -62,21 +63,22 @@ class ue_manager : public ue_manager_ctrl /// \return The UE index. ue_index_t get_next_ue_index(); - const n3_interface_config& n3_config; - const cu_up_test_mode_config& test_mode_config; - e1ap_control_message_handler& e1ap; - f1u_cu_up_gateway& f1u_gw; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - task_executor& ctrl_executor; - dlt_pcap& gtpu_pcap; - timer_manager& timers; - ue_db_t ue_db; - ue_task_schedulers_t ue_task_schedulers; - srslog::basic_logger& logger; + const n3_interface_config& n3_config; + const cu_up_test_mode_config& test_mode_config; + e1ap_control_message_handler& e1ap; + f1u_cu_up_gateway& f1u_gw; + const std::vector>& ngu_gws; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + task_executor& ctrl_executor; + dlt_pcap& gtpu_pcap; + timer_manager& timers; + ue_db_t ue_db; + ue_task_schedulers_t ue_task_schedulers; + srslog::basic_logger& logger; }; } // namespace srs_cu_up diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index 2b42705f6e..d2698bcdb3 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -52,6 +52,7 @@ bool udp_network_gateway_impl::subscribe_to(io_broker& broker) logger.error("Failed to register UDP network gateway at IO broker. socket_fd={}", get_socket_fd()); return false; } + logger.debug("Registered UDP network gateway at IO broker. socket_fd={}", get_socket_fd()); return true; } diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index 360078a17b..b20c21b098 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -101,6 +101,10 @@ class cu_up_test : public ::testing::Test f1u_gw = std::make_unique(f1u_bearer); broker = create_io_broker(io_broker_type::epoll); upf_addr_str = "127.0.0.1"; + + // Set default UDP configs + cu_up_udp_cfg.bind_port = 0; // Random free port selected by the OS. + cu_up_udp_cfg.bind_address = "127.0.0.2"; // Random free port selected by the OS. } cu_up_config get_default_cu_up_config() @@ -109,7 +113,6 @@ class cu_up_test : public ::testing::Test cu_up_config cfg; cfg.qos[uint_to_five_qi(9)] = {}; - // cfg.net_cfg.n3_bind_port = 0; // Random free port selected by the OS. cfg.n3_cfg.gtpu_reordering_timer = std::chrono::milliseconds(0); cfg.n3_cfg.warn_on_drop = false; @@ -125,22 +128,18 @@ class cu_up_test : public ::testing::Test deps.exec_mapper = exec_pool.get(); deps.e1_conn_client = &e1ap_client; deps.f1u_gateway = f1u_gw.get(); - deps.ngu_gw = ngu_gw.get(); - deps.timers = app_timers.get(); + deps.ngu_gws.push_back(ngu_gw.get()); + deps.timers = app_timers.get(); return deps; } void init(const cu_up_config& cfg, cu_up_dependencies&& deps) { - udp_network_gateway_config udp_cfg{}; - // udp_cfg.bind_interface = cfg.net_cfg.n3_bind_interface; - // udp_cfg.bind_address = cfg.net_cfg.n3_bind_addr; - // udp_cfg.bind_port = cfg.net_cfg.n3_bind_port; - ngu_gw = create_udp_ngu_gateway(udp_cfg, *broker, *executor); + ngu_gw = create_udp_ngu_gateway(cu_up_udp_cfg, *broker, *executor); auto cfg_copy = cfg; - deps.ngu_gw = ngu_gw.get(); - cu_up = std::make_unique(cfg_copy, std::move(deps)); + deps.ngu_gws.push_back(ngu_gw.get()); + cu_up = std::make_unique(cfg_copy, std::move(deps)); } void TearDown() override @@ -160,6 +159,8 @@ class cu_up_test : public ::testing::Test std::unique_ptr cu_up; srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); + udp_network_gateway_config cu_up_udp_cfg{}; + std::unique_ptr worker; std::unique_ptr executor; null_dlt_pcap dummy_pcap; diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index b3aa396113..83dfa8f134 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -46,6 +46,7 @@ class pdu_session_manager_test_base manual_task_worker teid_worker{128}; // TODO add dummy gateway + std::vector> ngu_gws_tmp; pdu_session_mng = std::make_unique(MIN_UE_INDEX, qos, security_info, @@ -57,6 +58,7 @@ class pdu_session_manager_test_base timers_factory, timers_factory, *f1u_gw, + ngu_gws_tmp, *n3_allocator, *f1u_allocator, *gtpu_tx_notifier, diff --git a/tests/unittests/cu_up/ue_manager_test.cpp b/tests/unittests/cu_up/ue_manager_test.cpp index 65ee0722be..03c8da1337 100644 --- a/tests/unittests/cu_up/ue_manager_test.cpp +++ b/tests/unittests/cu_up/ue_manager_test.cpp @@ -44,6 +44,7 @@ class ue_manager_test : public ::testing::Test ue_manager_dependencies{*e1ap, timers, *f1u_gw, + {}, *gtpu_tx_notifier, *gtpu_rx_demux, *gtpu_n3_allocator, From f873ccdbfb461453c612c2f140141df7a197fee7 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 21 Nov 2024 14:56:17 +0000 Subject: [PATCH 036/227] cu_up: fix tests after introducing multiple NG-U GWs --- include/srsran/cu_up/cu_up_config.h | 5 +- include/srsran/support/io/sockets.h | 4 +- lib/cu_up/pdu_session_manager_impl.cpp | 2 +- lib/gateways/udp_network_gateway_impl.cpp | 9 +++- lib/support/network/sockets.cpp | 13 ++++- tests/unittests/cu_up/cu_up_test.cpp | 49 +++++++++---------- tests/unittests/cu_up/cu_up_test_helpers.h | 16 ++++++ .../cu_up/pdu_session_manager_test.h | 8 +-- tests/unittests/cu_up/ue_manager_test.cpp | 8 ++- 9 files changed, 76 insertions(+), 38 deletions(-) diff --git a/include/srsran/cu_up/cu_up_config.h b/include/srsran/cu_up/cu_up_config.h index cea3cea6d9..7df4b16c9d 100644 --- a/include/srsran/cu_up/cu_up_config.h +++ b/include/srsran/cu_up/cu_up_config.h @@ -28,7 +28,6 @@ namespace srs_cu_up { struct network_interface_config { /// Port of UPF for NG-U connection (TODO: Refactor to use UPF port that we get from E1). - int upf_port = GTPU_PORT; // TS 29.281 Sec. 4.4.2.3 Encapsulated T-PDUs /// Local IP address to bind for connection from UPF to receive downlink user-plane traffic (N3 interface). std::string n3_bind_addr = "127.0.1.1"; @@ -57,6 +56,7 @@ struct network_interface_config { }; struct n3_interface_config { + int upf_port = GTPU_PORT; // TS 29.281 Sec. 4.4.2.3 Encapsulated T-PDUs std::chrono::milliseconds gtpu_reordering_timer; // N3 reordering timer bool warn_on_drop; }; @@ -123,8 +123,7 @@ struct formatter { auto format(const srsran::srs_cu_up::network_interface_config& cfg, FormatContext& ctx) { return format_to(ctx.out(), - "upf_port={}, n3_bind_addr={}, n3_bind_port={}, f1u_bind_addr={}, f1u_bind_port={}", - cfg.upf_port, + "n3_bind_addr={}, n3_bind_port={}, f1u_bind_addr={}, f1u_bind_port={}", cfg.n3_bind_addr, cfg.n3_bind_port, cfg.f1u_bind_addr, diff --git a/include/srsran/support/io/sockets.h b/include/srsran/support/io/sockets.h index 26c447091a..4e4e84ea3a 100644 --- a/include/srsran/support/io/sockets.h +++ b/include/srsran/support/io/sockets.h @@ -37,6 +37,8 @@ bool bind_to_interface(const unique_fd& fd, const std::string& interface, srslog bool sockaddr_to_ip_str(const sockaddr* addr, std::string& ip_address, srslog::basic_logger& logger); +uint16_t sockaddr_to_port(const sockaddr* addr, srslog::basic_logger& logger); + /// Set a receive timeout for a socket. bool set_receive_timeout(const unique_fd& fd, std::chrono::seconds rx_timeout, srslog::basic_logger& logger); @@ -64,4 +66,4 @@ struct formatter { } }; -} // namespace fmt \ No newline at end of file +} // namespace fmt diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index c09703aec9..ce234f9212 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -121,7 +121,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ msg.ue_index = ue_index; msg.cfg.tx.peer_teid = int_to_gtpu_teid(ul_tunnel_info.gtp_teid.value()); msg.cfg.tx.peer_addr = ul_tunnel_info.tp_address.to_string(); - msg.cfg.tx.peer_port = GTPU_PORT; // TODO get actual port from GW + msg.cfg.tx.peer_port = n3_config.upf_port; msg.cfg.rx.local_teid = new_session->local_teid; msg.cfg.rx.t_reordering = n3_config.gtpu_reordering_timer; msg.cfg.rx.warn_expired_t_reordering = n3_config.warn_on_drop; diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index d2698bcdb3..507ee578c2 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -92,7 +92,12 @@ void udp_network_gateway_impl::handle_pdu_impl(const byte_buffer& pdu, const soc strerror(errno)); } - logger.debug("Sent PDU of {} bytes", pdu.length()); + std::string local_addr_str; + std::string dest_addr_str; + uint16_t dest_port = sockaddr_to_port((sockaddr*)&dest_addr, logger); + sockaddr_to_ip_str((sockaddr*)&dest_addr, dest_addr_str, logger); + sockaddr_to_ip_str((sockaddr*)&local_addr, local_addr_str, logger); + logger.debug("Sent PDU of {} bytes. local_ip={} dest={}:{}", pdu.length(), local_addr_str, dest_addr_str, dest_port); } void udp_network_gateway_impl::handle_io_error(io_broker::error_code code) @@ -325,7 +330,7 @@ bool udp_network_gateway_impl::get_bind_address(std::string& ip_address) const } ip_address = addr_str; - logger.debug("Read bind port of UDP network gateway: {}", ip_address); + logger.debug("Read bind address of UDP network gateway: {}", ip_address); return true; } diff --git a/lib/support/network/sockets.cpp b/lib/support/network/sockets.cpp index 402c32c1b9..9fa29b970b 100644 --- a/lib/support/network/sockets.cpp +++ b/lib/support/network/sockets.cpp @@ -94,10 +94,21 @@ bool srsran::sockaddr_to_ip_str(const sockaddr* addr, std::string& ip_address, s } ip_address = addr_str; - logger.debug("Read bind port of UDP network gateway: {}", ip_address); return true; } +uint16_t srsran::sockaddr_to_port(const sockaddr* addr, srslog::basic_logger& logger) +{ + if (addr->sa_family == AF_INET) { + return ntohs(((sockaddr_in*)addr)->sin_port); + } + if (addr->sa_family == AF_INET6) { + return ntohs(((sockaddr_in6*)addr)->sin6_port); + } + logger.error("Unhandled address family."); + return 0; +} + bool srsran::set_receive_timeout(const unique_fd& fd, std::chrono::seconds rx_timeout, srslog::basic_logger& logger) { srsran_sanity_check(fd.is_open(), "Invalid FD"); diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index b20c21b098..51e5e1418b 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -121,13 +121,14 @@ class cu_up_test : public ::testing::Test return cfg; } - cu_up_dependencies get_defatul_cu_up_dependencies() + cu_up_dependencies get_default_cu_up_dependencies() { cu_up_dependencies deps; deps.gtpu_pcap = &dummy_pcap; deps.exec_mapper = exec_pool.get(); deps.e1_conn_client = &e1ap_client; deps.f1u_gateway = f1u_gw.get(); + ngu_gw = create_udp_ngu_gateway(cu_up_udp_cfg, *broker, *executor); deps.ngu_gws.push_back(ngu_gw.get()); deps.timers = app_timers.get(); return deps; @@ -135,11 +136,8 @@ class cu_up_test : public ::testing::Test void init(const cu_up_config& cfg, cu_up_dependencies&& deps) { - ngu_gw = create_udp_ngu_gateway(cu_up_udp_cfg, *broker, *executor); - auto cfg_copy = cfg; - deps.ngu_gws.push_back(ngu_gw.get()); - cu_up = std::make_unique(cfg_copy, std::move(deps)); + cu_up = std::make_unique(cfg_copy, std::move(deps)); } void TearDown() override @@ -230,7 +228,7 @@ class cu_up_test : public ::testing::Test TEST_F(cu_up_test, when_e1ap_connection_established_then_e1ap_connected) { - init(get_default_cu_up_config(), get_defatul_cu_up_dependencies()); + init(get_default_cu_up_config(), get_default_cu_up_dependencies()); // Connect E1AP cu_up->get_cu_up_manager()->on_e1ap_connection_establish(); @@ -245,14 +243,13 @@ TEST_F(cu_up_test, when_e1ap_connection_established_then_e1ap_connected) TEST_F(cu_up_test, dl_data_flow) { cu_up_config cfg = get_default_cu_up_config(); - // test_logger.debug("Using network_interface_config: {}", cfg.net_cfg); // Initialize UPF simulator on a random port. upf_info_t upf_info = init_upf(); - // cfg.net_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); ASSERT_GE(upf_info.sock_fd, 0); + cfg.n3_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); - cu_up_dependencies dependencies = get_defatul_cu_up_dependencies(); + cu_up_dependencies dependencies = get_default_cu_up_dependencies(); // Initialize CU-UP init(cfg, std::move(dependencies)); @@ -278,20 +275,24 @@ TEST_F(cu_up_test, dl_data_flow) f1u_bearer.handle_pdu(std::move(nru_msg1)); + test_logger.info("Waiting UL PDU. This is required to update DDDS"); + // We wait here for the UL PDU to arrive, to make sure the DDDS has been processed. // receive message 1 std::array rx_buf; - [[maybe_unused]] int ret; + int ret; ret = recv(upf_info.sock_fd, rx_buf.data(), rx_buf.size(), 0); + test_logger.info("Processed UL PDU. DDDS is updated"); + // Now that the disered buffer size is updated, we push DL PDUs - [[maybe_unused]] sockaddr_in cu_up_addr; - cu_up_addr.sin_family = AF_INET; - cu_up_addr.sin_port = htons(cu_up->get_n3_bind_port().value()); - // cu_up_addr.sin_addr.s_addr = inet_addr(cfg.net_cfg.n3_bind_addr.c_str()); + sockaddr_in cu_up_addr; + cu_up_addr.sin_family = AF_INET; + cu_up_addr.sin_port = htons(cu_up->get_n3_bind_port().value()); + cu_up_addr.sin_addr.s_addr = inet_addr(cu_up_udp_cfg.bind_address.c_str()); // DL PDU teid=2, qfi=1 - [[maybe_unused]] const uint8_t gtpu_ping_vec[] = { + const uint8_t gtpu_ping_vec[] = { 0x34, 0xff, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x01, 0x00, 0x45, 0x00, 0x00, 0x54, 0x9b, 0xfb, 0x00, 0x00, 0x40, 0x01, 0x56, 0x5a, 0xc0, 0xa8, 0x04, 0x01, 0xc0, 0xa8, 0x03, 0x02, 0x00, 0x00, 0xb8, 0xc0, 0x00, 0x02, 0x00, 0x01, 0x5d, 0x26, 0x77, 0x64, 0x00, 0x00, 0x00, @@ -300,16 +301,16 @@ TEST_F(cu_up_test, dl_data_flow) 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; // send message 1 - /* ret = sendto(upf_info.sock_fd, gtpu_ping_vec, sizeof(gtpu_ping_vec), 0, (sockaddr*)&cu_up_addr, sizeof(cu_up_addr)); - ASSERT_GE(ret, 0) << "Failed to send message via sock_fd=" << upf_info.sock_fd << " to `" << cfg.net_cfg.n3_bind_addr - << ":" << cu_up->get_n3_bind_port().value() << "` - " << strerror(errno); + ASSERT_GE(ret, 0) << "Failed to send message via sock_fd=" << upf_info.sock_fd << " to `" + << cu_up_udp_cfg.bind_address << ":" << cu_up->get_n3_bind_port().value() << "` - " + << strerror(errno); // send message 2 ret = sendto(upf_info.sock_fd, gtpu_ping_vec, sizeof(gtpu_ping_vec), 0, (sockaddr*)&cu_up_addr, sizeof(cu_up_addr)); - ASSERT_GE(ret, 0) << "Failed to send message via sock_fd=" << upf_info.sock_fd << " to `" << cfg.net_cfg.n3_bind_addr - << ":" << cu_up->get_n3_bind_port().value() << "` - " << strerror(errno); - */ + ASSERT_GE(ret, 0) << "Failed to send message via sock_fd=" << upf_info.sock_fd << " to `" + << cu_up_udp_cfg.bind_address << ":" << cu_up->get_n3_bind_port().value() << "` - " + << strerror(errno); close(upf_info.sock_fd); // check reception of message 1 @@ -337,12 +338,10 @@ TEST_F(cu_up_test, ul_data_flow) //> Test preamble: listen on a free port upf_info_t upf_info = init_upf(); + cfg.n3_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); //> Test main part: create CU-UP and transmit data - // cfg.net_cfg.upf_port = ntohs(upf_info.upf_addr.sin_port); - // test_logger.debug("Using network_interface_config: {}", cfg.net_cfg); - - cu_up_dependencies dependencies = get_defatul_cu_up_dependencies(); + cu_up_dependencies dependencies = get_default_cu_up_dependencies(); init(cfg, std::move(dependencies)); create_drb(); diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index 930d826bf9..0cce1a80e4 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -19,6 +19,7 @@ #include "srsran/gtpu/gtpu_demux.h" #include "srsran/gtpu/gtpu_teid_pool.h" #include "srsran/gtpu/gtpu_tunnel_common_tx.h" +#include "srsran/gtpu/ngu_gateway.h" #include #include #include @@ -254,6 +255,21 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway std::list removed_ul_teid_list = {}; }; +class dummy_ngu_gateway final : public srs_cu_up::ngu_tnl_pdu_session +{ + bool get_bind_address(std::string& ip_address) const override + { + ip_address = "127.0.0.2"; + return true; + } + + std::optional get_bind_port() const override { return 2152; } + + void handle_pdu(byte_buffer pdu, const sockaddr_storage& dest_addr) override {} + + void on_new_pdu(byte_buffer pdu, const sockaddr_storage& src_addr) override {} +}; + class dummy_e1ap final : public srs_cu_up::e1ap_control_message_handler { public: diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 83dfa8f134..2061c85580 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -36,6 +36,8 @@ class pdu_session_manager_test_base f1u_gw = std::make_unique(f1u_bearer); n3_allocator = std::make_unique(); f1u_allocator = std::make_unique(); + auto ngu_gw = std::make_unique(); + ngu_gws.push_back(std::move(ngu_gw)); // create DUT object ue_inactivity_timer = timers_factory.create_timer(); @@ -45,8 +47,6 @@ class pdu_session_manager_test_base manual_task_worker teid_worker{128}; - // TODO add dummy gateway - std::vector> ngu_gws_tmp; pdu_session_mng = std::make_unique(MIN_UE_INDEX, qos, security_info, @@ -58,7 +58,7 @@ class pdu_session_manager_test_base timers_factory, timers_factory, *f1u_gw, - ngu_gws_tmp, + ngu_gws, *n3_allocator, *f1u_allocator, *gtpu_tx_notifier, @@ -72,6 +72,7 @@ class pdu_session_manager_test_base void finish() { + ngu_gws.clear(); // flush logger after each test srslog::flush(); } @@ -84,6 +85,7 @@ class pdu_session_manager_test_base std::unique_ptr gtpu_tx_notifier; dummy_inner_f1u_bearer f1u_bearer; std::unique_ptr f1u_gw; + std::vector> ngu_gws; std::unique_ptr n3_allocator; std::unique_ptr f1u_allocator; std::unique_ptr pdu_session_mng; diff --git a/tests/unittests/cu_up/ue_manager_test.cpp b/tests/unittests/cu_up/ue_manager_test.cpp index 03c8da1337..9d1abb80fc 100644 --- a/tests/unittests/cu_up/ue_manager_test.cpp +++ b/tests/unittests/cu_up/ue_manager_test.cpp @@ -33,7 +33,9 @@ class ue_manager_test : public ::testing::Test gtpu_f1u_allocator = std::make_unique(); gtpu_tx_notifier = std::make_unique(); f1u_gw = std::make_unique(f1u_bearer); - e1ap = std::make_unique(); + auto ngu_gw = std::make_unique(); + ngu_gws.push_back(std::move(ngu_gw)); + e1ap = std::make_unique(); cu_up_exec_mapper = std::make_unique(&worker); // Create UE cfg @@ -44,7 +46,7 @@ class ue_manager_test : public ::testing::Test ue_manager_dependencies{*e1ap, timers, *f1u_gw, - {}, + ngu_gws, *gtpu_tx_notifier, *gtpu_rx_demux, *gtpu_n3_allocator, @@ -56,6 +58,7 @@ class ue_manager_test : public ::testing::Test void TearDown() override { + ngu_gws.clear(); // flush logger after each test srslog::flush(); } @@ -69,6 +72,7 @@ class ue_manager_test : public ::testing::Test dummy_inner_f1u_bearer f1u_bearer; null_dlt_pcap gtpu_pcap; std::unique_ptr f1u_gw; + std::vector> ngu_gws; timer_manager timers; ue_context_cfg ue_cfg; std::unique_ptr ue_mng; From a631dde705167f23a79c9ab850fd6630f9a4777d Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 29 Nov 2024 12:52:35 +0000 Subject: [PATCH 037/227] cu_up: fix pdu session manager unit tests --- .../cu_up/pdu_session_manager_test.cpp | 11 ++--------- .../unittests/cu_up/pdu_session_manager_test.h | 17 ----------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/tests/unittests/cu_up/pdu_session_manager_test.cpp b/tests/unittests/cu_up/pdu_session_manager_test.cpp index 5076954a66..375a8d460f 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.cpp +++ b/tests/unittests/cu_up/pdu_session_manager_test.cpp @@ -16,7 +16,7 @@ using namespace srsran; using namespace srs_cu_up; /// PDU session handling tests (creation/deletion) -TEST_P(pdu_session_manager_test_set_n3_ext_addr, when_valid_pdu_session_setup_item_session_can_be_added) +TEST_F(pdu_session_manager_test, when_valid_pdu_session_setup_item_session_can_be_added) { // no sessions added yet ASSERT_EQ(pdu_session_mng->get_nof_pdu_sessions(), 0); @@ -37,10 +37,7 @@ TEST_P(pdu_session_manager_test_set_n3_ext_addr, when_valid_pdu_session_setup_it ASSERT_EQ(setup_result.gtp_tunnel.gtp_teid.value(), 1); // TODO fixup - const std::string tp_address_expect = "8.8.8.8"; - // const std::string tp_address_expect = net_config.n3_ext_addr.empty() || net_config.n3_ext_addr == "auto" - // ? net_config.n3_bind_addr - // : net_config.n3_ext_addr; + const std::string tp_address_expect = "127.0.0.2"; // address of dummy gateway ASSERT_EQ(setup_result.gtp_tunnel.tp_address.to_string(), tp_address_expect); ASSERT_EQ(setup_result.drb_setup_results[0].gtp_tunnel.gtp_teid.value(), 1); ASSERT_EQ(pdu_session_mng->get_nof_pdu_sessions(), 1); @@ -394,10 +391,6 @@ TEST_F(pdu_session_manager_test, when_new_ul_info_is_requested_f1u_is_disconnect ASSERT_EQ(pdu_session_mng->get_nof_pdu_sessions(), 1); } -INSTANTIATE_TEST_SUITE_P(pdu_session_manager_test_n3_ext_addr, - pdu_session_manager_test_set_n3_ext_addr, - ::testing::Values("", "auto", "1.2.3.4")); - int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 2061c85580..ba51f6f67e 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -103,23 +103,6 @@ class pdu_session_manager_test : public pdu_session_manager_test_base, public :: void TearDown() override { finish(); } }; -/// Fixture class for PDU session manager tests with configurable N3 ext addr -class pdu_session_manager_test_set_n3_ext_addr : public pdu_session_manager_test_base, - public ::testing::TestWithParam -{ -protected: - // TODO is this still needed? - /* -network_interface_config get_net_config() override -{ - cfg.n3_ext_addr = GetParam(); - return cfg; -} - */ - void SetUp() override { init(); } - void TearDown() override { finish(); } -}; - inline e1ap_pdu_session_res_to_setup_item generate_pdu_session_res_to_setup_item(pdu_session_id_t psi, drb_id_t drb_id, qos_flow_id_t qfi, five_qi_t five_qi) { From f4513da4e5b5364592e35ee01d68e763b4538792 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 29 Nov 2024 17:07:43 +0000 Subject: [PATCH 038/227] config: fix cu_up ngu yaml writter --- .../cu_up/cu_up_unit_config_yaml_writer.cpp | 28 ++++++++++---- apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp | 37 ------------------- tests/unittests/cu_up/cu_up_test.cpp | 10 ++--- 3 files changed, 26 insertions(+), 49 deletions(-) delete mode 100644 apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp index c3a1512a2c..cdae254701 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp @@ -14,22 +14,36 @@ using namespace srsran; -[[maybe_unused]] static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) { - node["max_rx_msgs"] = config.rx_max_mmsg; + node["max_rx_msgs"] = config.rx_max_mmsg; + node["pool_occupancy_threshold"] = config.pool_occupancy_threshold; } -/* -static void fill_cu_up_ngu_section(YAML::Node node, const cu_up_unit_ngu_config& config) +static void fill_cu_up_ngu_socket_entry(YAML::Node& node, const cu_up_unit_ngu_socket_config& config) { node["bind_addr"] = config.bind_addr; node["bind_interface"] = config.bind_interface; node["ext_addr"] = config.ext_addr; - node["no_core"] = config.no_core; fill_cu_up_udp_section(node["udp"], config.udp_config); } -*/ + +static void fill_cu_up_ngu_socket_section(YAML::Node node, const std::vector& sock_cfg) +{ + auto sock_node = node["socket"]; + for (const auto& cfg : sock_cfg) { + YAML::Node node_sock; + fill_cu_up_ngu_socket_entry(node_sock, cfg); + sock_node.push_back(node_sock); + } +} + +static void fill_cu_up_ngu_section(YAML::Node node, const cu_up_unit_ngu_config& config) +{ + node["no_core"] = config.no_core; + + fill_cu_up_ngu_socket_section(node, config.ngu_socket_cfg); +} static void fill_cu_up_metrics_section(YAML::Node node, const cu_up_unit_metrics_config& config) { @@ -110,7 +124,7 @@ void srsran::fill_cu_up_config_in_yaml_schema(YAML::Node& node, const cu_up_unit fill_cu_up_log_section(node["log"], config.loggers); fill_cu_up_pcap_section(node["pcap"], config.pcap_cfg); fill_cu_up_metrics_section(node["metrics"], config.metrics); - // fill_cu_up_ngu_section(node["ngu"], config.ngu_cfg); + fill_cu_up_ngu_section(node["ngu"], config.ngu_cfg); fill_cu_up_qos_section(node, config.qos_cfg); } diff --git a/apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp b/apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp deleted file mode 100644 index 0834b5aa8f..0000000000 --- a/apps/units/o_cu_up/cu_up/cu_up_wrapper.cpp +++ /dev/null @@ -1,37 +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 "cu_up_wrapper.h" - -using namespace srsran; - -cu_up_wrapper::cu_up_wrapper(std::vector> gateways_, - std::unique_ptr e2_metric_connector_, - std::unique_ptr cu_up_) : - gateways(std::move(gateways_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) -{ - srsran_assert(not gateways.empty(), "Invlid NGU gateways"); - srsran_assert(cu_up, "Invalid CU-UP"); -} - -void cu_up_wrapper::start() -{ - cu_up->start(); -} - -void cu_up_wrapper::stop() -{ - cu_up->stop(); -} - -std::optional cu_up_wrapper::get_n3_bind_port() -{ - return cu_up->get_n3_bind_port(); -} diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index 51e5e1418b..aea7c9fe5b 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -261,11 +261,11 @@ TEST_F(cu_up_test, dl_data_flow) // UL message 1 nru_ul_message nru_msg1 = {}; const uint8_t t_pdu_arr1[] = { - 0x80, 0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0xe8, 0x83, 0x40, 0x00, 0x40, 0x01, 0xfa, 0x00, 0xac, 0x10, 0x00, - 0x03, 0xac, 0x10, 0x00, 0x01, 0x08, 0x00, 0x2c, 0xbe, 0xb4, 0xa4, 0x00, 0x01, 0xd3, 0x45, 0x61, 0x63, 0x00, - 0x00, 0x00, 0x00, 0x1a, 0x20, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; + 0x80, 0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0xe8, 0x83, 0x40, 0x00, 0x40, 0x01, 0xfa, 0x00, 0xac, 0x10, 0x00, + 0x03, 0xac, 0x10, 0x00, 0x01, 0x08, 0x00, 0x2c, 0xbe, 0xb4, 0xa4, 0x00, 0x01, 0xd3, 0x45, 0x61, 0x63, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0x20, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; span t_pdu_span1 = {t_pdu_arr1}; byte_buffer t_pdu_buf1 = byte_buffer::create(t_pdu_span1).value(); nru_msg1.t_pdu = byte_buffer_chain::create(std::move(t_pdu_buf1)).value(); From d9c87cde117046c8ccab357b9dc9fab9d9885aa7 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 29 Nov 2024 16:16:12 +0000 Subject: [PATCH 039/227] config: added a config example for multiple sockets --- configs/ngu_multiple_sockets.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 configs/ngu_multiple_sockets.yml diff --git a/configs/ngu_multiple_sockets.yml b/configs/ngu_multiple_sockets.yml new file mode 100644 index 0000000000..eafd03f7dc --- /dev/null +++ b/configs/ngu_multiple_sockets.yml @@ -0,0 +1,15 @@ + +cu_up: + ngu: + socket: + - + bind_addr: 127.0.3.1 # address that the NG-U socket will bind to. + udp: + max_rx_msgs: 256 # maximum packets read from the socket in a single syscall. + pool_threshold: 0.9 # Pool occupancy threshold, after which packets are dropped. + + - + bind_addr: 127.0.3.2 + udp: + max_rx_msgs: 256 # maximum packets read from the socket in a single syscall. + pool_threshold: 0.9 # Pool occupancy threshold, after which packets are dropped. From 98a23ba1f78c324c60ecd507afa5b7520cf6ead5 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 2 Dec 2024 15:27:08 +0000 Subject: [PATCH 040/227] cu_up: removed unused parameters from network_interface_config --- apps/units/o_cu_up/o_cu_up_builder.cpp | 3 -- apps/units/o_cu_up/o_cu_up_unit_impl.cpp | 2 +- include/srsran/cu_up/cu_up_config.h | 28 +------------------ lib/cu_up/pdu_session_manager_impl.cpp | 2 +- tests/unittests/cu_up/cu_up_test.cpp | 2 +- .../cu_up/pdu_session_manager_test.cpp | 1 - 6 files changed, 4 insertions(+), 34 deletions(-) diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 9055709125..532d3f8877 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -62,9 +62,6 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ auto address = dependencies.f1u_gateway->get_cu_bind_address(); srsran_assert(address.has_value(), "Invalid F1-U bind address"); - // TODO get bind addr from f1u gw - // config.cu_up_cfg.net_cfg.f1u_bind_addr = address.value(); - // Create NG-U gateway(s). std::vector> ngu_gws; if (not unit_cfg.cu_up_cfg.ngu_cfg.no_core) { diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp index 35b841d6c8..a16cebf497 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp @@ -17,7 +17,7 @@ o_cu_up_unit_impl::o_cu_up_unit_impl(std::vector cu_up_) : gateways(std::move(gateways_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) { - srsran_assert(not gateways.empty(), "Invlid NGU gateway"); + srsran_assert(not gateways.empty(), "Invalid NG-U gateway"); srsran_assert(cu_up, "Invalid CU-UP"); } diff --git a/include/srsran/cu_up/cu_up_config.h b/include/srsran/cu_up/cu_up_config.h index 7df4b16c9d..ca7e62ef6e 100644 --- a/include/srsran/cu_up/cu_up_config.h +++ b/include/srsran/cu_up/cu_up_config.h @@ -27,27 +27,6 @@ class io_broker; namespace srs_cu_up { struct network_interface_config { - /// Port of UPF for NG-U connection (TODO: Refactor to use UPF port that we get from E1). - - /// Local IP address to bind for connection from UPF to receive downlink user-plane traffic (N3 interface). - std::string n3_bind_addr = "127.0.1.1"; - - /// External IP address that is advertised to receive GTP-U packets from UPF via N3 interface. - /// It defaults to \c n3_bind_addr but may differ in case the CU-UP is behind a NAT. - std::string n3_ext_addr = "auto"; - - /// Interface name to bind the N3. `auto` does not force a specific interface and uses a normal `bind()`. - std::string n3_bind_interface = "auto"; - - /// Local port to bind for connection from UPF to receive downlink user-plane traffic (N3 interface). - int n3_bind_port = GTPU_PORT; // TS 29.281 Sec. 4.4.2.3 Encapsulated T-PDUs - - /// Maximum amount of packets received in a single syscall. - int n3_rx_max_mmsg = 256; - - /// Pool occupancy threshold after which we drop packets. - float pool_threshold = 0.9; - /// Local IP address to bind for connection from DU to receive uplink user-plane traffic. std::string f1u_bind_addr = "127.0.2.1"; @@ -122,12 +101,7 @@ struct formatter { template auto format(const srsran::srs_cu_up::network_interface_config& cfg, FormatContext& ctx) { - return format_to(ctx.out(), - "n3_bind_addr={}, n3_bind_port={}, f1u_bind_addr={}, f1u_bind_port={}", - cfg.n3_bind_addr, - cfg.n3_bind_port, - cfg.f1u_bind_addr, - cfg.f1u_bind_port); + return format_to(ctx.out(), "f1u_bind_addr={} f1u_bind_port={}", cfg.f1u_bind_addr, cfg.f1u_bind_port); } }; } // namespace fmt diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index ce234f9212..d799ecfa8c 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -107,7 +107,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ // TODO select correct GW based on slice or UE info. std::string n3_addr; if (not ngu_gws[0]->get_bind_address(n3_addr)) { - report_error("Could not get NG-U bind addres to report to core."); + report_error("Could not get NG-U bind address to report to core."); } pdu_session_result.gtp_tunnel = up_transport_layer_info(transport_layer_address::create_from_string(n3_addr), new_session->local_teid); diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index aea7c9fe5b..2b6b31f3ec 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -104,7 +104,7 @@ class cu_up_test : public ::testing::Test // Set default UDP configs cu_up_udp_cfg.bind_port = 0; // Random free port selected by the OS. - cu_up_udp_cfg.bind_address = "127.0.0.2"; // Random free port selected by the OS. + cu_up_udp_cfg.bind_address = "127.0.0.2"; // NG-U bind address } cu_up_config get_default_cu_up_config() diff --git a/tests/unittests/cu_up/pdu_session_manager_test.cpp b/tests/unittests/cu_up/pdu_session_manager_test.cpp index 375a8d460f..0636b6b03a 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.cpp +++ b/tests/unittests/cu_up/pdu_session_manager_test.cpp @@ -36,7 +36,6 @@ TEST_F(pdu_session_manager_test, when_valid_pdu_session_setup_item_session_can_b ASSERT_TRUE(setup_result.success); ASSERT_EQ(setup_result.gtp_tunnel.gtp_teid.value(), 1); - // TODO fixup const std::string tp_address_expect = "127.0.0.2"; // address of dummy gateway ASSERT_EQ(setup_result.gtp_tunnel.tp_address.to_string(), tp_address_expect); ASSERT_EQ(setup_result.drb_setup_results[0].gtp_tunnel.gtp_teid.value(), 1); From 4fbe4de086d21d19e73444558e69a3708f60665b Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 4 Dec 2024 14:55:10 +0000 Subject: [PATCH 041/227] cu: match var names to CLI11 parameters --- apps/services/network/udp_cli11_schema.cpp | 8 +++----- apps/services/network/udp_cli11_schema.h | 7 +++++-- .../units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp | 4 ++-- apps/units/o_cu_up/o_cu_up_builder.cpp | 6 +++--- include/srsran/cu_up/cu_up.h | 3 --- lib/cu_up/cu_up_impl.h | 2 +- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/services/network/udp_cli11_schema.cpp b/apps/services/network/udp_cli11_schema.cpp index f0fbb2eb67..89da3551f4 100644 --- a/apps/services/network/udp_cli11_schema.cpp +++ b/apps/services/network/udp_cli11_schema.cpp @@ -15,12 +15,10 @@ using namespace srsran; static void configure_cli11_udp_args(CLI::App& app, udp_appconfig& udp_params) { - add_option(app, "--max_rx_msgs", udp_params.rx_max_mmsg, "Maximum amount of messages RX in a single syscall") + add_option(app, "--max_rx_msgs", udp_params.rx_max_msgs, "Maximum amount of messages RX in a single syscall") ->capture_default_str(); - add_option(app, - "--pool_threshold", - udp_params.pool_occupancy_threshold, - "Pool accupancy threshold after which packets are dropped") + add_option( + app, "--pool_threshold", udp_params.pool_threshold, "Pool accupancy threshold after which packets are dropped") ->capture_default_str(); } diff --git a/apps/services/network/udp_cli11_schema.h b/apps/services/network/udp_cli11_schema.h index 262c096937..e1e8111fc2 100644 --- a/apps/services/network/udp_cli11_schema.h +++ b/apps/services/network/udp_cli11_schema.h @@ -14,9 +14,12 @@ namespace srsran { +/// UDP specific configuration of an UDP gateway. struct udp_appconfig { - unsigned rx_max_mmsg = 256; - float pool_occupancy_threshold = 0.9; + /// Maximum amount of messages RX in a single syscall. + unsigned rx_max_msgs = 256; + /// Pool accupancy threshold after which packets are dropped. + float pool_threshold = 0.9; }; /// \brief Configures the given CLI11 application with the UDP application configuration schema. diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp index cdae254701..967146d4e2 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_yaml_writer.cpp @@ -16,8 +16,8 @@ using namespace srsran; static void fill_cu_up_udp_section(YAML::Node node, const udp_appconfig& config) { - node["max_rx_msgs"] = config.rx_max_mmsg; - node["pool_occupancy_threshold"] = config.pool_occupancy_threshold; + node["max_rx_msgs"] = config.rx_max_msgs; + node["pool_threshold"] = config.pool_threshold; } static void fill_cu_up_ngu_socket_entry(YAML::Node& node, const cu_up_unit_ngu_socket_config& config) diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 532d3f8877..82a9e24e8d 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -69,10 +69,10 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ udp_network_gateway_config n3_udp_cfg = {}; n3_udp_cfg.bind_address = sock_cfg.bind_addr; n3_udp_cfg.bind_interface = sock_cfg.bind_interface; - n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; + n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.bind_port = GTPU_PORT; - n3_udp_cfg.rx_max_mmsg = sock_cfg.udp_config.rx_max_mmsg; - n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_occupancy_threshold; + n3_udp_cfg.rx_max_mmsg = sock_cfg.udp_config.rx_max_msgs; + n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets std::unique_ptr ngu_gw = srs_cu_up::create_udp_ngu_gateway( diff --git a/include/srsran/cu_up/cu_up.h b/include/srsran/cu_up/cu_up.h index 1d13998e76..0e428d09f2 100644 --- a/include/srsran/cu_up/cu_up.h +++ b/include/srsran/cu_up/cu_up.h @@ -25,9 +25,6 @@ class cu_up_interface /// \brief Stop the CU-UP. This call is blocking and only returns once all tasks in the CU-UP are completed. virtual void stop() = 0; - - /// \brief Get the N3 bind port. - virtual std::optional get_n3_bind_port() = 0; }; } // namespace srsran::srs_cu_up diff --git a/lib/cu_up/cu_up_impl.h b/lib/cu_up/cu_up_impl.h index 7f7a2cf61f..f8436e5d96 100644 --- a/lib/cu_up/cu_up_impl.h +++ b/lib/cu_up/cu_up_impl.h @@ -36,7 +36,7 @@ class cu_up final : public cu_up_interface void stop() override; /// helper functions for testing - std::optional get_n3_bind_port() override // TODO include index? + std::optional get_n3_bind_port() // TODO include index? { return ngu_sessions[0]->get_bind_port(); } From d233290fd990b94aba0a08b959133b20f76e4173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Wed, 4 Dec 2024 15:00:22 +0100 Subject: [PATCH 042/227] ci,e2e: create standalone basic ping test for local tests --- tests/e2e/pyproject.toml | 2 +- tests/e2e/tests/ping.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index 60841ea182..0f9c4df2d6 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -16,6 +16,7 @@ log_date_format = "%Y-%m-%d %H:%M:%S" log_format = "%(asctime)s [%(levelname)s] %(message)s" log_level = "INFO" markers = [ + "example", "smoke", "zmq", "zmq_single_ue", @@ -33,7 +34,6 @@ markers = [ "rf_n300", "rf_not_crash", "reattach", - "test", "zmq_2x2_mimo", "zmq_4x4_mimo", "zmq_srsue", diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index dfaf33d7d4..0afc5f81fb 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -190,7 +190,7 @@ def test_android_hp( "band, common_scs, bandwidth, ciphering", ( param(3, 15, 5, False, id="band:%s-scs:%s-bandwidth:%s-ciphering:%s"), - param(3, 15, 10, False, marks=mark.test, id="band:%s-scs:%s-bandwidth:%s-ciphering:%s"), + param(3, 15, 10, False, id="band:%s-scs:%s-bandwidth:%s-ciphering:%s"), param(3, 15, 20, False, id="band:%s-scs:%s-bandwidth:%s-ciphering:%s"), param(3, 15, 50, False, id="band:%s-scs:%s-bandwidth:%s-ciphering:%s"), param(3, 15, 50, True, id="band:%s-scs:%s-bandwidth:%s-ciphering:%s"), @@ -245,6 +245,36 @@ def test_zmq_32( ) +@mark.example +def test_example( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue_4: Tuple[UEStub, ...], + fivegc: FiveGCStub, + gnb: GNBStub, +): + """ + ZMQ Pings + """ + + _ping( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=ue_4, + gnb=gnb, + fivegc=fivegc, + band=3, + common_scs=15, + bandwidth=10, + sample_rate=None, # default from testbed + global_timing_advance=0, + time_alignment_calibration=0, + ue_stop_timeout=3, + enable_security_mode=False, + post_command=("cu_cp --inactivity_timer=600", ""), + ) + + @mark.parametrize( "band, common_scs, bandwidth, ciphering", ( From 2df84dcd8da66c093865a663ea33dffb06972ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Wed, 4 Dec 2024 15:00:57 +0100 Subject: [PATCH 043/227] ci: change default matrix actions --- .github/workflows/ccpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 8b8ac92519..6c423c24a6 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -15,8 +15,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-24.04] - compiler: [gcc, clang] + os: [ubuntu-24.04] + compiler: [gcc] steps: - uses: actions/checkout@v3 - name: Install Dependencies From 16d4fa6aed768ddc96c7a6becec60c6529348854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Wed, 4 Dec 2024 15:47:36 +0100 Subject: [PATCH 044/227] ci: update retina --- .gitlab/ci/e2e/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index ed877f792c..4b0924ec6f 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.56.11 +RETINA_VERSION=0.56.14 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From c9a72a2a77af411d61a17f472653bb5ceb93f281 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 5 Dec 2024 10:43:04 +0100 Subject: [PATCH 045/227] apps: validate nof_non_rt_threads upon start There should never be more non-real time threads than CPU cores. Moreover, this ensures the PDCP is able to create the right amount of security engines. --- apps/cu/cu_appconfig_validator.cpp | 11 ++++++- apps/gnb/gnb_appconfig_validators.cpp | 5 ++++ apps/services/worker_manager/CMakeLists.txt | 3 +- .../worker_manager_appconfig_validator.cpp | 29 +++++++++++++++++++ .../worker_manager_appconfig_validator.h | 20 +++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 apps/services/worker_manager/worker_manager_appconfig_validator.cpp create mode 100644 apps/services/worker_manager/worker_manager_appconfig_validator.h diff --git a/apps/cu/cu_appconfig_validator.cpp b/apps/cu/cu_appconfig_validator.cpp index 407a0615f3..8e51b5d1bc 100644 --- a/apps/cu/cu_appconfig_validator.cpp +++ b/apps/cu/cu_appconfig_validator.cpp @@ -10,11 +10,20 @@ #include "cu_appconfig_validator.h" #include "apps/services/logger/logger_appconfig_validator.h" +#include "apps/services/worker_manager/worker_manager_appconfig_validator.h" #include "cu_appconfig.h" using namespace srsran; bool srsran::validate_cu_appconfig(const cu_appconfig& config) { - return validate_logger_appconfig(config.log_cfg); + if (!validate_logger_appconfig(config.log_cfg)) { + return false; + } + + if (!validate_expert_execution_appconfig(config.expert_execution_cfg)) { + return false; + } + + return true; } diff --git a/apps/gnb/gnb_appconfig_validators.cpp b/apps/gnb/gnb_appconfig_validators.cpp index 854d5e9e66..d21767d42e 100644 --- a/apps/gnb/gnb_appconfig_validators.cpp +++ b/apps/gnb/gnb_appconfig_validators.cpp @@ -10,6 +10,7 @@ #include "gnb_appconfig_validators.h" #include "apps/services/logger/logger_appconfig_validator.h" +#include "apps/services/worker_manager/worker_manager_appconfig_validator.h" #include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h" #include "apps/units/o_cu_cp/cu_cp/cu_cp_unit_config.h" @@ -37,6 +38,10 @@ bool srsran::validate_appconfig(const gnb_appconfig& config) return false; } + if (!validate_expert_execution_appconfig(config.expert_execution_cfg)) { + return false; + } + if (!validate_hal_config(config.hal_config)) { return false; } diff --git a/apps/services/worker_manager/CMakeLists.txt b/apps/services/worker_manager/CMakeLists.txt index 6efb087451..56a9ae03a4 100644 --- a/apps/services/worker_manager/CMakeLists.txt +++ b/apps/services/worker_manager/CMakeLists.txt @@ -8,7 +8,8 @@ set(SOURCES worker_manager.cpp - worker_manager_cli11_schema.cpp) + worker_manager_cli11_schema.cpp + worker_manager_appconfig_validator.cpp) add_library(srsran_cpu_affinities_helper STATIC cli11_cpu_affinities_parser_helper.cpp) diff --git a/apps/services/worker_manager/worker_manager_appconfig_validator.cpp b/apps/services/worker_manager/worker_manager_appconfig_validator.cpp new file mode 100644 index 0000000000..72c7d7eba1 --- /dev/null +++ b/apps/services/worker_manager/worker_manager_appconfig_validator.cpp @@ -0,0 +1,29 @@ +/* + * + * 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_appconfig_validator.h" +#include "worker_manager_appconfig.h" + +using namespace srsran; + +bool srsran::validate_expert_execution_appconfig(const expert_execution_appconfig& config) +{ + // Ensure the number of non-real time threads does not exceed the number of CPU cores + auto& cpu_desc = cpu_architecture_info::get(); + uint32_t nof_cores = cpu_desc.get_host_nof_available_cpus(); + if (config.threads.non_rt_threads.nof_non_rt_threads > nof_cores) { + fmt::print("Invalid expert execution config: nof_non_rt_threads={} must not exceed nof_cores={}\n", + config.threads.non_rt_threads.nof_non_rt_threads, + nof_cores); + return false; + } + + return true; +} diff --git a/apps/services/worker_manager/worker_manager_appconfig_validator.h b/apps/services/worker_manager/worker_manager_appconfig_validator.h new file mode 100644 index 0000000000..16f64cedb0 --- /dev/null +++ b/apps/services/worker_manager/worker_manager_appconfig_validator.h @@ -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. + * + */ + +#pragma once + +namespace srsran { + +struct expert_execution_appconfig; + +/// Validates the given expert configuration of the application. Returns true on success, false otherwise. +bool validate_expert_execution_appconfig(const expert_execution_appconfig& config); + +} // namespace srsran From 5764678299b899cb30bbfcb988f31eef700095d7 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 3 Dec 2024 12:37:18 +0000 Subject: [PATCH 046/227] ngap: add unit test to bad PLMN handling --- .../ngap/ng_setup_procedure_test.cpp | 20 +++++++++++++++++++ tests/unittests/ngap/ngap_test_messages.cpp | 18 +++++++++++++++++ tests/unittests/ngap/ngap_test_messages.h | 3 +++ 3 files changed, 41 insertions(+) diff --git a/tests/unittests/ngap/ng_setup_procedure_test.cpp b/tests/unittests/ngap/ng_setup_procedure_test.cpp index a9eca56cc7..35636478ad 100644 --- a/tests/unittests/ngap/ng_setup_procedure_test.cpp +++ b/tests/unittests/ngap/ng_setup_procedure_test.cpp @@ -179,3 +179,23 @@ TEST_F(ngap_test, when_retry_limit_reached_then_amf_not_connected) ASSERT_TRUE(t.ready()); ASSERT_TRUE(std::holds_alternative(t.get())); } + +/// Test the ng setup procedure +TEST_F(ngap_test, when_failure_is_misconfiguration_no_retries_are_done) +{ + // Action 1: Launch NG setup procedure + test_logger.info("Launch ng setup request procedure..."); + unsigned max_setup_retries = 10; + async_task t = ngap->handle_ng_setup_request(max_setup_retries); + lazy_task_launcher t_launcher(t); + + // Status: AMF received NG Setup Request. + ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.type().value, asn1::ngap::ngap_pdu_c::types_opts::init_msg); + ASSERT_EQ(n2_gw.last_ngap_msgs.back().pdu.init_msg().value.type().value, + asn1::ngap::ngap_elem_procs_o::init_msg_c::types_opts::ng_setup_request); + + // Action 2: NG setup failure received. + ngap_message ng_setup_response_msg = generate_ng_setup_failure_with_bad_plmn(asn1::ngap::time_to_wait_opts::v10s); + ngap->handle_message(ng_setup_response_msg); + ASSERT_TRUE(t.ready()); +} diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index f3e0e33e1f..3075847a73 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -108,6 +108,24 @@ ngap_message srsran::srs_cu_cp::generate_ng_setup_failure() return ng_setup_failure; } +ngap_message srsran::srs_cu_cp::generate_ng_setup_failure_with_bad_plmn(time_to_wait_e time_to_wait) +{ + ngap_message ng_setup_failure = {}; + + ng_setup_failure.pdu.set_unsuccessful_outcome(); + ng_setup_failure.pdu.unsuccessful_outcome().load_info_obj(ASN1_NGAP_ID_NG_SETUP); + + auto& setup_fail = ng_setup_failure.pdu.unsuccessful_outcome().value.ng_setup_fail(); + setup_fail->cause.set_misc(); + setup_fail->cause.misc() = asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn; + setup_fail->time_to_wait_present = true; + setup_fail->time_to_wait.value = time_to_wait; + setup_fail->crit_diagnostics_present = false; + // add critical diagnostics + + return ng_setup_failure; +} + ngap_message srsran::srs_cu_cp::generate_ng_setup_failure_with_time_to_wait(time_to_wait_e time_to_wait) { ngap_message ng_setup_failure = generate_ng_setup_failure(); diff --git a/tests/unittests/ngap/ngap_test_messages.h b/tests/unittests/ngap/ngap_test_messages.h index c06dd7e13b..5c17286e53 100644 --- a/tests/unittests/ngap/ngap_test_messages.h +++ b/tests/unittests/ngap/ngap_test_messages.h @@ -90,6 +90,9 @@ ngap_message generate_ng_setup_response(plmn_identity plmn = plmn_identity::test /// \brief Generate a dummy NG Setup Failure. ngap_message generate_ng_setup_failure(); +/// \brief Generate a dummy NG Setup Failure with bad PLMN. +ngap_message generate_ng_setup_failure_with_bad_plmn(asn1::ngap::time_to_wait_e time_to_wait); + /// \brief Generate a dummy NG Setup Failure with a time to wait. ngap_message generate_ng_setup_failure_with_time_to_wait(asn1::ngap::time_to_wait_e time_to_wait); From a74cc33fbc7f9c0e5b3ae7f8ceff012a6f8428d9 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 3 Dec 2024 12:22:26 +0000 Subject: [PATCH 047/227] ngap: fix hanging of NG setup due to incorrect PLMNs --- lib/ngap/procedures/ng_setup_procedure.cpp | 27 ++++++++++++++++++++++ lib/ngap/procedures/ng_setup_procedure.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/lib/ngap/procedures/ng_setup_procedure.cpp b/lib/ngap/procedures/ng_setup_procedure.cpp index 1bbc95b0e0..191a0e33c6 100644 --- a/lib/ngap/procedures/ng_setup_procedure.cpp +++ b/lib/ngap/procedures/ng_setup_procedure.cpp @@ -86,6 +86,14 @@ bool ng_setup_procedure::retry_required() const asn1::ngap::ng_setup_fail_s& ng_fail = transaction_sink.failure(); + // No point in retrying when the failure is due to misconfiguration. + if (is_failure_misconfiguration(ng_fail->cause)) { + logger.warning("\"{}\": Stopping procedure. Cause: misconfiguration between gNB and AMF", name()); + logger.warning("\"{}\" failed. AMF NGAP cause: \"{}\"", name(), get_cause_str(ng_fail->cause)); + fmt::print("\"{}\" failed. AMF NGAP cause: \"{}\"\n", name(), get_cause_str(ng_fail->cause)); + return false; + } + if (not ng_fail->time_to_wait_present) { // AMF didn't command a waiting time. logger.warning("\"{}\": Stopping procedure. Cause: AMF did not set any retry waiting time", name()); @@ -127,3 +135,22 @@ ngap_ng_setup_result ng_setup_procedure::create_ng_setup_result() return res; } + +bool ng_setup_procedure::is_failure_misconfiguration(const cause_c& cause) +{ + switch (cause.type()) { + case cause_c::types_opts::radio_network: + return false; + case cause_c::types_opts::transport: + return false; + case cause_c::types_opts::nas: + return false; + case cause_c::types_opts::protocol: + return false; + case cause_c::types_opts::misc: + return cause.misc() == asn1::ngap::cause_misc_opts::unknown_plmn_or_sn_pn; + default: + break; + } + return false; +} diff --git a/lib/ngap/procedures/ng_setup_procedure.h b/lib/ngap/procedures/ng_setup_procedure.h index 5a771ab98b..3b1ed52d39 100644 --- a/lib/ngap/procedures/ng_setup_procedure.h +++ b/lib/ngap/procedures/ng_setup_procedure.h @@ -41,6 +41,8 @@ class ng_setup_procedure /// Creates procedure result to send back to procedure caller. ngap_ng_setup_result create_ng_setup_result(); + static bool is_failure_misconfiguration(const asn1::ngap::cause_c& cause); + ngap_context_t& context; const ngap_message request; const unsigned max_setup_retries; From 36aa4d646000af483197717a18e8e3a669a6116a Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Fri, 29 Nov 2024 17:47:01 +0100 Subject: [PATCH 048/227] mac: support pucch f3 in pucch_resource_generator --- .../o_du_high/du_high/du_high_config.h | 36 +- .../du_high/du_high_config_cli11_schema.cpp | 62 ++- .../du_high/du_high_config_translators.cpp | 34 +- .../du_high/du_high_config_validator.cpp | 8 +- .../du_high/du_high_config_yaml_writer.cpp | 19 +- include/srsran/du/du_cell_config.h | 27 +- include/srsran/ran/pucch/pucch_info.h | 143 ++++++ .../srsran/scheduler/scheduler_pucch_format.h | 2 +- lib/du/du_cell_config_validation.cpp | 4 +- .../du_pucch_resource_manager.cpp | 60 ++- .../pucch_resource_generator.cpp | 443 +++++++++++++----- .../pucch_resource_generator.h | 94 ++-- lib/du/du_update_config_helpers.cpp | 4 +- lib/fapi_adaptor/mac/messages/pucch.cpp | 2 +- .../config/sched_cell_config_helpers.cpp | 22 +- .../benchmarks/du_high/du_high_benchmark.cpp | 2 +- .../scheduler_multi_ue_benchmark.cpp | 11 +- .../du_high/du_high_many_ues_test.cpp | 2 +- .../scheduler/scheduler_config_helper.cpp | 2 +- .../du_ran_resource_manager_test.cpp | 17 +- .../pucch_resource_generator_test.cpp | 403 ++++++++++++---- .../fapi_adaptor/mac/messages/helpers.cpp | 2 +- .../mac/messages/ul_pucch_pdu_test.cpp | 2 +- .../scheduler/multiple_ue_sched_test.cpp | 2 +- .../test_pucch_res_test_builder_helper.cpp | 2 +- .../uci_and_pucch/uci_test_utils.cpp | 2 +- 26 files changed, 1053 insertions(+), 354 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 2443b28ca9..9fac09b1b3 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -260,6 +260,8 @@ struct du_high_unit_pucch_config { /// \c PUCCH-Config parameters. /// Force Format 0 for the PUCCH resources belonging to PUCCH resource set 0. bool use_format_0 = false; + /// Select the format for the PUCCH resources belonging to PUCCH resource set 1 {2, 3, 4}. + unsigned set1_format = 2; /// Number of PUCCH resources per UE (per PUCCH resource set) for HARQ-ACK reporting. /// Values {3,...,8} if \c use_format_0 is set. Else, Values {1,...,8}. /// \remark We assume the number of PUCCH F0/F1 resources for HARQ-ACK is equal to the equivalent number of Format 2 @@ -284,6 +286,7 @@ struct du_high_unit_pucch_config { /// Set true for PUCCH Format 0 intra-slot frequency hopping. bool f0_intraslot_freq_hopping = false; + /// PUCCH F1 resource parameters. /// \defgroup pucch_f1_params /// \brief PUCCH F1 resource parameters. /// @{ @@ -291,20 +294,45 @@ struct du_high_unit_pucch_config { bool f1_enable_occ = false; /// \brief Number of different Initial Cyclic Shifts that can be used for PUCCH Format 1. /// Values: {1, 2, 3, 4, 6, 12}; 0 corresponds to "no cyclic shift". - unsigned nof_cyclic_shift = 2; + unsigned f1_nof_cyclic_shifts = 2; /// Set true for PUCCH Format 1 intra-slot frequency hopping. bool f1_intraslot_freq_hopping = false; /// @} + /// PUCCH F2 resource parameters. + /// \defgroup pucch_f2_params + /// \brief PUCCH F2 resource parameters. + /// @{ /// Max number of PRBs for PUCCH Format 2. Values {1,...,16}. unsigned f2_max_nof_rbs = 1; /// \brief Maximum payload in bits that can be carried by PUCCH Format 2. Values {-1,...,11}. /// Value -1 to unset. If this is set, \ref f2_max_nof_rbs is ignored. - std::optional max_payload_bits; + std::optional f2_max_payload_bits; + /// Max code rate for PUCCH Format 2. + max_pucch_code_rate f2_max_code_rate = max_pucch_code_rate::dot_35; /// Set true for PUCCH Format 2 intra-slot frequency hopping. This field is ignored if f2_nof_symbols == 1. bool f2_intraslot_freq_hopping = false; - /// Max code rate. - max_pucch_code_rate max_code_rate = max_pucch_code_rate::dot_35; + /// @} + + /// PUCCH F3 resource parameters. + /// \defgroup pucch_f3_params + /// \brief PUCCH F3 resource parameters. + /// @{ + /// Max number of PRBs for PUCCH Format 3. Values {1,...,16}. + unsigned f3_max_nof_rbs = 1; + /// \brief Maximum payload in bits that can be carried by PUCCH Format 3. Values {-1,...,11}. + /// Value -1 to unset. If this is set, \ref f2_max_nof_rbs is ignored. + std::optional f3_max_payload_bits; + /// Max code rate for PUCCH Format 3. + max_pucch_code_rate f3_max_code_rate = max_pucch_code_rate::dot_35; + /// Set true for PUCCH Format 3 intra-slot frequency hopping. + bool f3_intraslot_freq_hopping = false; + /// Set true for PUCCH Format 3 additional DM-RS. + bool f3_additional_dmrs = false; + /// Set true to use pi/2-BPSK as the modulation for PUCCH Format 3. + bool f3_pi2_bpsk = false; + /// @} + /// Minimum k1 value (distance in slots between PDSCH and HARQ-ACK) that the gNB can use. Values: {1, ..., 7}. /// [Implementation-defined] As min_k1 is used for both common and dedicated PUCCH configuration, and in the UE /// fallback scheduler only allow max k1 = 7, we restrict min_k1 to 7. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 93da59451f..8af39271fb 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -852,6 +852,12 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& ->check(CLI::IsMember({1.0F, 2.0F, 2.5F, 4.0F, 5.0F, 8.0F, 10.0F, 16.0F, 20.0F, 40.0F, 80.0F, 160.0F, 320.0F})); add_option(app, "--use_format_0", pucch_params.use_format_0, "Use Format 0 for PUCCH resources from resource set 0") ->capture_default_str(); + add_option(app, + "--set1_format", + pucch_params.set1_format, + "Format to use for the resources from resource set 1 {2, 3, 4}. Default: 2") + ->capture_default_str() + ->check(CLI::Range(2, 4)); add_option(app, "--nof_ue_res_harq_per_set", pucch_params.nof_ue_pucch_res_harq_per_set, @@ -872,7 +878,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option(app, "--f1_enable_occ", pucch_params.f1_enable_occ, "Enable OCC for PUCCH F1")->capture_default_str(); add_option(app, "--f1_nof_cyclic_shifts", - pucch_params.nof_cyclic_shift, + pucch_params.f1_nof_cyclic_shifts, "Number of possible cyclic shifts available for PUCCH F1 resources") ->capture_default_str() ->check(CLI::IsMember({1, 2, 3, 4, 6, 12})); @@ -897,26 +903,27 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option(app, "--f2_max_nof_rbs", pucch_params.f2_max_nof_rbs, "Max number of RBs for PUCCH F2 resources") ->capture_default_str() ->check(CLI::Range(1, 16)); - add_option(app, "--f2_max_payload", pucch_params.max_payload_bits, "Max number payload bits for PUCCH F2 resources") + add_option( + app, "--f2_max_payload", pucch_params.f2_max_payload_bits, "Max number payload bits for PUCCH F2 resources") ->check(CLI::Range(1, 11)); add_option_function( app, "--f2_max_code_rate", [&pucch_params](const std::string& value) { if (value == "dot08") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_08; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_08; } else if (value == "dot15") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_15; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_15; } else if (value == "dot25") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_25; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_25; } else if (value == "dot35") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_35; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_35; } else if (value == "dot45") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_45; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_45; } else if (value == "dot60") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_60; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_60; } else if (value == "dot80") { - pucch_params.max_code_rate = max_pucch_code_rate::dot_80; + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_80; } }, "PUCCH F2 max code rate {dot08, dot15, dot25, dot35, dot45, dot60, dot80}. Default: dot35") @@ -926,6 +933,43 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& pucch_params.f2_intraslot_freq_hopping, "Enable intra-slot frequency hopping for PUCCH F2") ->capture_default_str(); + add_option(app, "--f3_max_nof_rbs", pucch_params.f3_max_nof_rbs, "Max number of RBs for PUCCH F3 resources") + ->capture_default_str() + ->check(CLI::Range(1, 16)); + add_option( + app, "--f3_max_payload", pucch_params.f3_max_payload_bits, "Max number payload bits for PUCCH F3 resources") + ->check(CLI::Range(1, 11)); + add_option_function( + app, + "--f3_max_code_rate", + [&pucch_params](const std::string& value) { + if (value == "dot08") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_08; + } else if (value == "dot15") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_15; + } else if (value == "dot25") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_25; + } else if (value == "dot35") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_35; + } else if (value == "dot45") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_45; + } else if (value == "dot60") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_60; + } else if (value == "dot80") { + pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_80; + } + }, + "PUCCH F3 max code rate {dot08, dot15, dot25, dot35, dot45, dot60, dot80}. Default: dot35") + ->check(CLI::IsMember({"dot08", "dot15", "dot25", "dot35", "dot45", "dot60", "dot80"}, CLI::ignore_case)); + add_option(app, + "--f3_intraslot_freq_hop", + pucch_params.f3_intraslot_freq_hopping, + "Enable intra-slot frequency hopping for PUCCH F3") + ->capture_default_str(); + add_option(app, "--f3_additional_dmrs", pucch_params.f3_additional_dmrs, "Enable additional DM-RS for PUCCH F3") + ->capture_default_str(); + add_option(app, "--f3_pi2_bpsk", pucch_params.f3_pi2_bpsk, "Enable pi/2-BPSK modulation for PUCCH F3") + ->capture_default_str(); add_option(app, "--min_k1", pucch_params.min_k1, diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index c20f82f64e..0c73f2396b 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -535,25 +535,45 @@ std::vector srsran::generate_du_cell_config(const du_hig du_pucch_cfg.nof_cell_harq_pucch_res_sets = user_pucch_cfg.nof_cell_harq_pucch_sets; du_pucch_cfg.nof_sr_resources = user_pucch_cfg.nof_cell_sr_resources; du_pucch_cfg.nof_csi_resources = param.csi_rs_enabled ? user_pucch_cfg.nof_cell_csi_resources : 0U; + if (user_pucch_cfg.use_format_0) { auto& f0_params = du_pucch_cfg.f0_or_f1_params.emplace(); // Subtract 2 PUCCH resources from value: with Format 0, 2 extra resources will be added by the DU resource // allocator when the DU create the UE configuration. du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; - du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; + du_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; f0_params.intraslot_freq_hopping = user_pucch_cfg.f0_intraslot_freq_hopping; } else { auto& f1_params = du_pucch_cfg.f0_or_f1_params.emplace(); du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; - du_pucch_cfg.nof_ue_pucch_f2_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; + du_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; f1_params.occ_supported = user_pucch_cfg.f1_enable_occ; - f1_params.nof_cyc_shifts = static_cast(user_pucch_cfg.nof_cyclic_shift); + f1_params.nof_cyc_shifts = static_cast(user_pucch_cfg.f1_nof_cyclic_shifts); f1_params.intraslot_freq_hopping = user_pucch_cfg.f1_intraslot_freq_hopping; } - du_pucch_cfg.f2_params.max_code_rate = user_pucch_cfg.max_code_rate; - du_pucch_cfg.f2_params.max_nof_rbs = user_pucch_cfg.f2_max_nof_rbs; - du_pucch_cfg.f2_params.intraslot_freq_hopping = user_pucch_cfg.f2_intraslot_freq_hopping; - du_pucch_cfg.f2_params.max_payload_bits = user_pucch_cfg.max_payload_bits; + + switch (user_pucch_cfg.set1_format) { + case 2: { + auto& f2_params = du_pucch_cfg.f2_or_f3_params.emplace(); + f2_params.max_code_rate = user_pucch_cfg.f2_max_code_rate; + f2_params.max_nof_rbs = user_pucch_cfg.f2_max_nof_rbs; + f2_params.intraslot_freq_hopping = user_pucch_cfg.f2_intraslot_freq_hopping; + f2_params.max_payload_bits = user_pucch_cfg.f2_max_payload_bits; + break; + } + case 3: { + auto& f3_params = du_pucch_cfg.f2_or_f3_params.emplace(); + f3_params.max_code_rate = user_pucch_cfg.f3_max_code_rate; + f3_params.max_nof_rbs = user_pucch_cfg.f3_max_nof_rbs; + f3_params.intraslot_freq_hopping = user_pucch_cfg.f3_intraslot_freq_hopping; + f3_params.max_payload_bits = user_pucch_cfg.f3_max_payload_bits; + f3_params.additional_dmrs = user_pucch_cfg.f3_additional_dmrs; + f3_params.pi2_bpsk = user_pucch_cfg.f3_pi2_bpsk; + break; + } + default: + break; + } // Parameters for SRS-Config. srs_du::srs_builder_params& du_srs_cfg = out_cell.srs_cfg; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index d756301661..29caad4cba 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -474,7 +474,7 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& config.pucch_cfg.f1_enable_occ ? format1_symb_to_spreading_factor(pucch_f1_nof_symbols) : 1U; // We define a block as a set of Resources (either F0/F1 or F2) aligned over the same starting PRB. - const unsigned nof_f1_per_block = nof_occ_codes * config.pucch_cfg.nof_cyclic_shift; + const unsigned nof_f1_per_block = nof_occ_codes * config.pucch_cfg.f1_nof_cyclic_shifts; // Each PUCCH resource F0/F1 occupies 1 RB (per block). nof_f0_f1_rbs = static_cast(std::ceil( static_cast(config.pucch_cfg.nof_ue_pucch_res_harq_per_set * pucch_cfg.nof_cell_harq_pucch_sets + @@ -489,10 +489,10 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& // The number of symbols per PUCCH resource F2 is not exposed to the DU user interface and set by default to 2. constexpr unsigned pucch_f2_nof_symbols = 2U; const unsigned f2_max_rbs = - config.pucch_cfg.max_payload_bits.has_value() - ? get_pucch_format2_max_nof_prbs(config.pucch_cfg.max_payload_bits.value(), + config.pucch_cfg.f2_max_payload_bits.has_value() + ? get_pucch_format2_max_nof_prbs(config.pucch_cfg.f2_max_payload_bits.value(), pucch_f2_nof_symbols, - to_max_code_rate_float(config.pucch_cfg.max_code_rate)) + to_max_code_rate_float(config.pucch_cfg.f2_max_code_rate)) : config.pucch_cfg.f2_max_nof_rbs; const unsigned nof_f2_blocks = max_nof_pucch_symbols / pucch_f2_nof_symbols; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp index cbe2149c5d..70f4624bb2 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp @@ -410,22 +410,31 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c node["p0_nominal"] = config.p0_nominal; node["pucch_resource_common"] = config.pucch_resource_common; node["use_format_0"] = config.use_format_0; + node["set1_format"] = config.set1_format; node["sr_period_ms"] = config.sr_period_msec; node["nof_ue_pucch_res_harq_per_set"] = config.nof_ue_pucch_res_harq_per_set; node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; node["f0_intraslot_freq_hop"] = config.f0_intraslot_freq_hopping; node["f1_enable_occ"] = config.f1_enable_occ; - node["f1_nof_cyclic_shifts"] = config.nof_cyclic_shift; + node["f1_nof_cyclic_shifts"] = config.f1_nof_cyclic_shifts; node["f1_intraslot_freq_hop"] = config.f1_intraslot_freq_hopping; node["nof_cell_harq_pucch_res_sets"] = config.nof_cell_harq_pucch_sets; - node["f2_nof_cell_res_csi"] = config.nof_cell_csi_resources; + node["f2_or_f3_nof_cell_res_csi"] = config.nof_cell_csi_resources; node["f2_max_nof_rbs"] = config.f2_max_nof_rbs; - node["f2_max_code_rate"] = to_string(config.max_code_rate); + node["f2_max_code_rate"] = to_string(config.f2_max_code_rate); node["f2_intraslot_freq_hop"] = config.f2_intraslot_freq_hopping; + node["f3_max_nof_rbs"] = config.f3_max_nof_rbs; + node["f3_max_code_rate"] = to_string(config.f3_max_code_rate); + node["f3_intraslot_freq_hop"] = config.f3_intraslot_freq_hopping; + node["f3_additional_dmrs"] = config.f3_additional_dmrs; + node["f3_pi2_bpsk"] = config.f3_pi2_bpsk; node["min_k1"] = config.min_k1; node["max_consecutive_kos"] = config.max_consecutive_kos; - if (config.max_payload_bits.has_value()) { - node["f2_max_payload"] = config.max_payload_bits.value(); + if (config.f2_max_payload_bits.has_value()) { + node["f2_max_payload"] = config.f2_max_payload_bits.value(); + } + if (config.f3_max_payload_bits.has_value()) { + node["f3_max_payload"] = config.f3_max_payload_bits.value(); } return node; diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index c038449a08..a1c57af1a2 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -40,7 +40,6 @@ inline unsigned format1_cp_step_to_uint(nof_cyclic_shifts opt) /// Collects the parameters for PUCCH Format 0 that can be configured. struct pucch_f0_params { - /// Indicates whether OCCs (as per \c PUCCH-format0, in \c PUCCH-Config, TS 38.331) are supported. bounded_integer nof_symbols{2}; bool intraslot_freq_hopping{false}; }; @@ -68,6 +67,19 @@ struct pucch_f2_params { bool intraslot_freq_hopping{false}; }; +/// Collects the parameters for PUCCH Format 3 that can be configured. +struct pucch_f3_params { + bounded_integer nof_symbols{14}; + unsigned max_nof_rbs{1}; + /// Maximum payload in bits that can be carried by PUCCH Format 3. When this field is set, \c max_nof_rbs is ignored + /// and the maximum number of RBs is computed according to \ref get_pucch_format3_max_nof_prbs. + std::optional max_payload_bits; + max_pucch_code_rate max_code_rate{max_pucch_code_rate::dot_25}; + bool intraslot_freq_hopping{false}; + bool additional_dmrs{false}; + bool pi2_bpsk{false}; +}; + /// \brief Parameters for PUCCH configuration. /// Defines the parameters that are used for the PUCCH configuration builder. These parameters are used to define the /// number of PUCCH resources, as well as the PUCCH format-specific parameters. @@ -75,24 +87,25 @@ struct pucch_builder_params { /// UE specific parameters. Use to set the number of resources per UE for HARQ-ACK reporting (not including SR/CSI /// dedicated resources). NOTE: by default, each UE is assigned 1 SR and 1 CSI resource. /// \remark Format 0 and Format 1 resources are mutually exclusive. + /// \remark Format 2 and Format 3 resources are mutually exclusive. bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 6; - bounded_integer nof_ue_pucch_f2_res_harq = 6; + bounded_integer nof_ue_pucch_f2_or_f3_res_harq = 6; /// \brief Number of separate PUCCH resource sets for HARQ-ACK reporting that are available in a cell. /// \remark UEs will be distributed possibly over different HARQ-ACK PUCCH sets; the more sets, the fewer UEs will /// have to share the same set, which reduces the chances that UEs won't be allocated PUCCH due to lack of resources. /// However, the usage of PUCCH-dedicated REs will be proportional to the number of sets. unsigned nof_cell_harq_pucch_res_sets = 1; - /// Defines how many PUCCH F1 resources should be dedicated for SR at cell level; each UE will be allocated 1 resource - /// for SR. + /// Defines how many PUCCH F0 or F1 resources should be dedicated for SR at cell level; each UE will be allocated 1 + /// resource for SR. unsigned nof_sr_resources = 2; - /// Defines how many PUCCH F2 resources should be dedicated for CSI at cell level; each UE will be allocated 1 + /// Defines how many PUCCH F2 or F3 resources should be dedicated for CSI at cell level; each UE will be allocated 1 /// resource for CSI. unsigned nof_csi_resources = 1; /// PUCCH Format specific parameters. - // NOTE: Having \c pucch_f1_params force the varint to use the Format 1 in the default constructor. + // NOTE: Having \c pucch_f1_params first forces the variant to use the Format 1 in the default constructor. std::variant f0_or_f1_params; - pucch_f2_params f2_params; + std::variant f2_or_f3_params; /// Maximum number of symbols per UL slot dedicated for PUCCH. /// \remark In case of Sounding Reference Signals (SRS) being used, the number of symbols should be reduced so that /// the PUCCH resources do not overlap in symbols with the SRS resources. diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index b8bb6ea465..1d7b662695 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -15,6 +15,7 @@ #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/ran/resource_block.h" #include "srsran/ran/uci/uci_info.h" +#include namespace srsran { @@ -212,6 +213,148 @@ inline unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned no return estimated_pucch_f2_capacity - long_crc_length; } +/// \brief Calculates the number of OFDM symbols filled with DM-RS in a PUCCH Format 3/4 resource. +/// \param[in] nof_symbols Transmission duration in OFDM symbols. +/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. +/// \return The number of DM-RS OFDM symbols within the PUCCH Format 3/4 transmission. +inline unsigned get_pucch_format3_4_nof_dmrs_symbols(bounded_integer nof_symbols, + bool intraslot_freq_hopping, + bool additional_dmrs) +{ + if (nof_symbols == 4) { + return intraslot_freq_hopping ? 2 : 1; + } + if (nof_symbols < 10) { + return 2; + } + return additional_dmrs ? 4 : 2; +} + +/// \brief Calculates the number of PRBs required for a given payload size for PUCCH Format 3. +/// \param[in] nof_payload_bits Total number of payload bits. +/// \param[in] nof_symbols Transmission duration in symbols. +/// \param[in] max_code_rate Maximum code rate for PUCCH format 3; it corresponds to \c maxCodeRate, part of +/// \c PUCCH-FormatConfig, TS 38.331. +/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. +/// \param[in] pi2_bpsk Flag indicating if intra slot frequency hopping is enabled. +/// \return The number of PRBs required for the transmission of nof_payload_bits with PUCCH format 3. +/// \remark The returned number of PRBs is not capped to the maximum value of \ref FORMAT3_MAX_NPRB; it's up to the +/// caller to perform this check. +inline unsigned get_pucch_format3_max_nof_prbs(unsigned nof_payload_bits, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) +{ + if (nof_payload_bits == 0 or nof_symbols == 0) { + return 0; + } + + const unsigned nof_dmrs_symbols = + get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); + const unsigned mod_order = pi2_bpsk ? 1 : 2; + + // Compute the number of PRBs first without taking into account the CRC bits. + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213. The + // ceil operation guarantees that the number of PRBs is enough to satisfy the effective code rate constraint. + unsigned nof_prbs = static_cast( + std::ceil(static_cast(nof_payload_bits) / + (static_cast((nof_symbols - nof_dmrs_symbols) * NRE * mod_order) * max_code_rate))); + + static const std::set valid_num_prbs = {1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16}; + auto round_to_valid_nof_prbs = [](unsigned value) { + // Round up to the nearest valid number of PRBs for PUCCH Format 3. + while (valid_num_prbs.find(value) == valid_num_prbs.end()) { + value++; + } + return value; + }; + + // The resulting number of PRBs is too big for PUCCH Format 3, so just return. + if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { + return nof_prbs; + } + + // Since the number of PRBs was rounded up there's no need to check that the CRC bits actually fit into the resource. + if (unsigned rounded_nof_prbs = round_to_valid_nof_prbs(nof_prbs); rounded_nof_prbs != nof_prbs) { + return rounded_nof_prbs; + } + + // Compute the total number of bits (including CRC) using the resulting PRB number. + const unsigned e_uci = get_pucch_format2_E_total(nof_prbs, nof_symbols); + // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of + // code-blocks is \f$E_{UCI}\f$. + unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); + + // Check that the number of PRBs can hold the total number of bits after rate matching. + if (static_cast(std::ceil(static_cast(payload_plus_crc_bits) / max_code_rate)) > + (nof_dmrs_symbols * NRE * nof_prbs * mod_order)) { + nof_prbs++; + + // The resulting number of PRBs is too big for PUCCH Format 3, so just return. + if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { + return nof_prbs; + } + + return round_to_valid_nof_prbs(nof_prbs); + } + return nof_prbs; +} + +/// \brief Calculates the maximum payload for a PUCCH Format 3 transmission. +/// \param[in] max_nof_prbs Transmission bandwidth in PRB. +/// \param[in] nof_symbols Transmission duration in symbols. +/// \param[in] max_code_rate Maximum allowed PUCCH Format2 code rate. +/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. +/// \param[in] pi2_bpsk Flag indicating if intra slot frequency hopping is enabled. +/// \return The maximum payload for a PUCCH Format 3 transmission. +inline unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) +{ + const unsigned nof_dmrs_symbols = + get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); + const unsigned mod_order = pi2_bpsk ? 1 : 2; + + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213; the + // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and + // max_code_rate. + const unsigned estimated_pucch_f3_capacity = static_cast(std::floor( + static_cast((nof_symbols - nof_dmrs_symbols) * NRE * mod_order * max_nof_prbs) * max_code_rate)); + + // Get the payload depending on the estimated PUCCH F3 capacity (which we define as the nof bits that the PUCCH F3 can + // carry). + + // Case: no CRC for payload <= 11 bits. + constexpr unsigned min_capacity_for_more_than_11_bit_payload = 18U; + constexpr unsigned max_payload_without_crc_addition = 11U; + if (estimated_pucch_f3_capacity < min_capacity_for_more_than_11_bit_payload) { + return std::min(estimated_pucch_f3_capacity, max_payload_without_crc_addition); + } + + // Case: 6-bit CRC for 12 <= payload <= 19 bits. + constexpr unsigned min_capacity_for_more_than_19_bit_payload = 31U; + constexpr unsigned max_payload_with_6_bit_crc_addition = 19U; + constexpr unsigned short_crc_length = 6U; + if (estimated_pucch_f3_capacity < min_capacity_for_more_than_19_bit_payload) { + return std::min(estimated_pucch_f3_capacity - short_crc_length, max_payload_with_6_bit_crc_addition); + } + + // Case: 11-bit CRC for payload >= 20. + // Compute the total number of bits (including CRC) using the resulting PRB number. + const unsigned e_uci = get_pucch_format3_E_total(max_nof_prbs, nof_symbols, pi2_bpsk); + constexpr unsigned long_crc_length = 11U; + const unsigned nof_crc_bits = get_uci_nof_crc_bits(estimated_pucch_f3_capacity - long_crc_length, e_uci); + return std::min(estimated_pucch_f3_capacity - long_crc_length, estimated_pucch_f3_capacity - nof_crc_bits); +} + /// Returns the number of possible spreading factors which is a function of the number of symbols. inline unsigned format1_symb_to_spreading_factor(bounded_integer f1_symbols) { diff --git a/include/srsran/scheduler/scheduler_pucch_format.h b/include/srsran/scheduler/scheduler_pucch_format.h index 7340a93761..a055e7b3fa 100644 --- a/include/srsran/scheduler/scheduler_pucch_format.h +++ b/include/srsran/scheduler/scheduler_pucch_format.h @@ -97,7 +97,7 @@ struct pucch_format_3 { unsigned harq_ack_nof_bits; unsigned csi_part1_bits; pucch_repetition_tx_slot slot_repetition; - uint16_t n_id_scambling; + uint16_t n_id_scrambling; bool pi_2_bpsk; max_pucch_code_rate max_code_rate; /// DMRS parameters. diff --git a/lib/du/du_cell_config_validation.cpp b/lib/du/du_cell_config_validation.cpp index a0f2888eb9..6c31ef2b0b 100644 --- a/lib/du/du_cell_config_validation.cpp +++ b/lib/du/du_cell_config_validation.cpp @@ -759,10 +759,10 @@ check_outcome srs_du::is_du_cell_config_valid(const du_cell_config& cell_cfg) HANDLE_ERROR(srs_du::pucch_parameters_validator( pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * pucch_cfg.nof_cell_harq_pucch_res_sets + pucch_cfg.nof_sr_resources, - pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() * pucch_cfg.nof_cell_harq_pucch_res_sets + + pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * pucch_cfg.nof_cell_harq_pucch_res_sets + pucch_cfg.nof_csi_resources, pucch_cfg.f0_or_f1_params, - pucch_cfg.f2_params, + pucch_cfg.f2_or_f3_params, cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(), pucch_cfg.max_nof_symbols)); HANDLE_ERROR(check_prach_config(cell_cfg)); diff --git a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index 45aa75a42c..ea57f5cdf1 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -40,7 +40,11 @@ static pucch_config build_default_pucch_cfg(const pucch_config& pucch_cfg, const if (not std::holds_alternative(user_params.f0_or_f1_params)) { target_pucch_cfg.format_1_common_param.reset(); } - target_pucch_cfg.format_2_common_param.value().max_c_rate = user_params.f2_params.max_code_rate; + std::visit( + [&target_pucch_cfg](const auto& f2_or_f3_params) { + target_pucch_cfg.format_2_common_param.value().max_c_rate = f2_or_f3_params.max_code_rate; + }, + user_params.f2_or_f3_params); return target_pucch_cfg; } @@ -52,11 +56,11 @@ du_pucch_resource_manager::du_pucch_resource_manager(span srs_du::generate_cell_pucch_res_list(cell_cfg_list_[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * cell_cfg_list_[0].pucch_cfg.nof_cell_harq_pucch_res_sets + cell_cfg_list_[0].pucch_cfg.nof_sr_resources, - cell_cfg_list_[0].pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() * + cell_cfg_list_[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * cell_cfg_list_[0].pucch_cfg.nof_cell_harq_pucch_res_sets + cell_cfg_list_[0].pucch_cfg.nof_csi_resources, cell_cfg_list_[0].pucch_cfg.f0_or_f1_params, - cell_cfg_list_[0].pucch_cfg.f2_params, + cell_cfg_list_[0].pucch_cfg.f2_or_f3_params, cell_cfg_list_[0].ul_cfg_common.init_ul_bwp.generic_params.crbs.length(), cell_cfg_list_[0].pucch_cfg.max_nof_symbols)), default_pucch_cfg( @@ -291,7 +295,7 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) sr_res_offset.value().first, csi_res_offset.has_value() ? csi_res_offset.value().first : 0, user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq, - user_defined_pucch_cfg.nof_ue_pucch_f2_res_harq, + user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq, user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets, user_defined_pucch_cfg.nof_sr_resources, user_defined_pucch_cfg.nof_csi_resources); @@ -311,11 +315,27 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) static constexpr unsigned pucch_f1_max_harq_payload = 2U; cell_grp_cfg.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value().format_max_payload[pucch_format_to_uint( pucch_format::FORMAT_1)] = pucch_f1_max_harq_payload; - cell_grp_cfg.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value().format_max_payload[pucch_format_to_uint( - pucch_format::FORMAT_2)] = - get_pucch_format2_max_payload(user_defined_pucch_cfg.f2_params.max_nof_rbs, - user_defined_pucch_cfg.f2_params.nof_symbols.to_uint(), - to_max_code_rate_float(default_pucch_cfg.format_2_common_param.value().max_c_rate)); + + if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_params)) { + const auto& f2_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + cell_grp_cfg.cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() + .format_max_payload[pucch_format_to_uint(pucch_format::FORMAT_2)] = get_pucch_format2_max_payload( + f2_params.max_nof_rbs, + f2_params.nof_symbols.to_uint(), + to_max_code_rate_float(default_pucch_cfg.format_2_common_param.value().max_c_rate)); + } else { + const auto& f3_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + cell_grp_cfg.cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() + .format_max_payload[pucch_format_to_uint(pucch_format::FORMAT_3)] = get_pucch_format3_max_payload( + f3_params.max_nof_rbs, + f3_params.nof_symbols.to_uint(), + to_max_code_rate_float(default_pucch_cfg.format_3_common_param.value().max_c_rate), + f3_params.intraslot_freq_hopping, + f3_params.additional_dmrs, + f3_params.pi2_bpsk); + } ++cells[0].ue_idx; return true; @@ -377,9 +397,21 @@ du_pucch_resource_manager::get_csi_resource_offset(const csi_meas_config& csi_me const float max_pucch_code_rate = to_max_code_rate_float(default_pucch_cfg.format_2_common_param.value().max_c_rate); - const unsigned max_payload = get_pucch_format2_max_payload(user_defined_pucch_cfg.f2_params.max_nof_rbs, - user_defined_pucch_cfg.f2_params.nof_symbols.to_uint(), - max_pucch_code_rate); + + unsigned max_payload; + if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_params)) { + const auto& f2_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + max_payload = + get_pucch_format2_max_payload(f2_params.max_nof_rbs, f2_params.nof_symbols.to_uint(), max_pucch_code_rate); + } else { + const auto& f3_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + max_payload = get_pucch_format3_max_payload(f3_params.max_nof_rbs, + f3_params.nof_symbols.to_uint(), + max_pucch_code_rate, + f3_params.intraslot_freq_hopping, + f3_params.additional_dmrs, + f3_params.pi2_bpsk); + } // This is the case of suitable CSI offset found, but the CSI offset would result in exceeding the PUCCH F2 max // payload. @@ -444,7 +476,7 @@ unsigned du_pucch_resource_manager::csi_du_res_idx_to_pucch_res_idx(unsigned csi return user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + user_defined_pucch_cfg.nof_sr_resources + - user_defined_pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() * + user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + csi_du_res_idx; } @@ -456,7 +488,7 @@ unsigned du_pucch_resource_manager::pucch_res_idx_to_csi_du_res_idx(unsigned puc return pucch_res_idx - (user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + user_defined_pucch_cfg.nof_sr_resources + - user_defined_pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() * + user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets); } diff --git a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp index d08f3f826c..93bd72e4f1 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -351,13 +351,105 @@ static std::vector compute_f2_res(unsigned return res_list; } -error_type -srsran::srs_du::pucch_parameters_validator(unsigned nof_res_f0_f1, - unsigned nof_res_f2, - std::variant f0_f1_params, - pucch_f2_params f2_params, - unsigned bwp_size_rbs, - bounded_integer max_nof_symbols) +static std::vector compute_f3_res(unsigned nof_res_f3, + pucch_f3_params params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) +{ + // Compute the number of symbols and RBs for F3. + std::vector res_list; + const unsigned nof_f3_symbols = params.nof_symbols.to_uint(); + const unsigned f3_max_rbs = params.max_payload_bits.has_value() + ? get_pucch_format3_max_nof_prbs(params.max_payload_bits.value(), + nof_f3_symbols, + to_max_code_rate_float(params.max_code_rate), + params.intraslot_freq_hopping, + params.additional_dmrs, + params.pi2_bpsk) + : params.max_nof_rbs; + + if (f3_max_rbs > pucch_constants::FORMAT3_MAX_NPRB) { + return {}; + } + + // With intraslot freq. hopping. + if (params.intraslot_freq_hopping) { + for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f3_max_rbs; rb_idx += f3_max_rbs) { + // Generate resource for increasing RB index, until the num. of required resources is reached. + const prb_interval prbs{rb_idx, rb_idx + f3_max_rbs}; + // Pre-compute the second RBs for the frequency hop specularly to the first RBs. + const prb_interval freq_hop_prbs{bwp_size_rbs - f3_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; + + // Generate resource for increasing Symbol index, until the num. of required resources is reached. + for (unsigned sym_idx = 0; sym_idx + nof_f3_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f3_symbols) { + const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f3_symbols}; + + // Allocate resources for first hop. + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_3, .symbols = symbols, .prbs = prbs, .freq_hop_grant = freq_hop_prbs}); + if (res_list.size() == nof_res_f3) { + break; + } + + // Allocate resources for second hop. + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_3, .symbols = symbols, .prbs = freq_hop_prbs, .freq_hop_grant = prbs}); + if (res_list.size() == nof_res_f3) { + break; + } + } + if (res_list.size() == nof_res_f3) { + break; + } + } + } + // With intraslot freq. hopping. + else { + for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f3_max_rbs; rb_idx += f3_max_rbs) { + const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f3_max_rbs}; + // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve + // balancing of the PUCCH resources on both sides of the BWP. + const prb_interval prbs_hi_spectrum{bwp_size_rbs - f3_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; + + // Generate resource for increasing Symbol index, until the num. of required resources is reached. + for (unsigned sym_idx = 0; sym_idx + nof_f3_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f3_symbols) { + const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f3_symbols}; + res_list.emplace_back( + pucch_grant{.format = pucch_format::FORMAT_3, .symbols = symbols, .prbs = prbs_low_spectrum}); + if (res_list.size() == nof_res_f3) { + break; + } + } + if (res_list.size() == nof_res_f3) { + break; + } + + // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of + // the BWP. + for (unsigned sym_idx = 0; sym_idx + nof_f3_symbols <= 14; sym_idx += nof_f3_symbols) { + const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f3_symbols}; + res_list.emplace_back( + pucch_grant{.format = pucch_format::FORMAT_3, .symbols = symbols, .prbs = prbs_hi_spectrum}); + if (res_list.size() == nof_res_f3) { + break; + } + } + + if (res_list.size() == nof_res_f3) { + break; + } + } + } + + return res_list; +} + +error_type srs_du::pucch_parameters_validator(unsigned nof_res_f0_f1, + unsigned nof_res_f2_f3, + std::variant f0_f1_params, + std::variant f2_f3_params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { const bool has_f0 = std::holds_alternative(f0_f1_params); unsigned nof_f0_f1_rbs = 0; @@ -370,11 +462,10 @@ srsran::srs_du::pucch_parameters_validator(unsigned return make_unexpected("Intra-slot frequency hopping for PUCCH Format 0 requires 2 symbols"); } - // We define a block as a set of Resources (either F0/F1 or F2) aligned over the same starting PRB. + // We define a block as a set of Resources (either F0/F1 or F2/F3) aligned over the same starting PRB. const unsigned nof_f0_per_block = max_nof_symbols.to_uint() / f0_params.nof_symbols.to_uint(); nof_f0_f1_rbs = static_cast(std::ceil(static_cast(nof_res_f0_f1) / static_cast(nof_f0_per_block))); - // With intraslot_freq_hopping, the nof of RBs is an even number. if (f0_params.intraslot_freq_hopping) { nof_f0_f1_rbs = static_cast(std::ceil(static_cast(nof_f0_f1_rbs) / 2.0F)) * 2; @@ -390,7 +481,7 @@ srsran::srs_du::pucch_parameters_validator(unsigned const unsigned nof_occ_codes = f1_params.occ_supported ? format1_symb_to_spreading_factor(f1_params.nof_symbols) : 1; - // We define a block as a set of Resources (either F0/F1 or F2) aligned over the same starting PRB. + // We define a block as a set of Resources (either F0/F1 or F2/F3) aligned over the same starting PRB. const unsigned nof_f1_per_block = nof_occ_codes * format1_cp_step_to_uint(f1_params.nof_cyc_shifts) * (max_nof_symbols.to_uint() / f1_params.nof_symbols.to_uint()); nof_f0_f1_rbs = @@ -401,34 +492,67 @@ srsran::srs_du::pucch_parameters_validator(unsigned } } - // > If intraslot_freq_hopping is enabled, check if PUCCH Format 2 has more than symbol. - if (f2_params.intraslot_freq_hopping and f2_params.nof_symbols == 1) { - return make_unexpected("Intra-slot frequency hopping for PUCCH Format 2 requires 2 symbols"); - } + const bool has_f2 = std::holds_alternative(f2_f3_params); + unsigned nof_f2_f3_rbs = 0; - const unsigned f2_max_rbs = f2_params.max_payload_bits.has_value() - ? get_pucch_format2_max_nof_prbs(f2_params.max_payload_bits.value(), - f2_params.nof_symbols.to_uint(), - to_max_code_rate_float(f2_params.max_code_rate)) - : f2_params.max_nof_rbs; + if (has_f2) { + const auto& f2_params = std::get(f2_f3_params); - if (f2_max_rbs > pucch_constants::FORMAT2_MAX_NPRB) { - return make_unexpected("The number of PRBs for PUCCH Format 2 exceeds the limit of 16"); - } + // > If intraslot_freq_hopping is enabled, check if PUCCH Format 2 has more than symbol. + if (f2_params.intraslot_freq_hopping and f2_params.nof_symbols == 1) { + return make_unexpected("Intra-slot frequency hopping for PUCCH Format 2 requires 2 symbols"); + } + + const unsigned f2_max_rbs = f2_params.max_payload_bits.has_value() + ? get_pucch_format2_max_nof_prbs(f2_params.max_payload_bits.value(), + f2_params.nof_symbols.to_uint(), + to_max_code_rate_float(f2_params.max_code_rate)) + : f2_params.max_nof_rbs; - const unsigned nof_f2_blocks = max_nof_symbols.to_uint() / f2_params.nof_symbols.to_uint(); - unsigned nof_f2_rbs = - static_cast(std::ceil(static_cast(nof_res_f2) / static_cast(nof_f2_blocks))) * f2_max_rbs; - // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. - if (f2_params.intraslot_freq_hopping) { - nof_f2_rbs = static_cast(std::ceil(static_cast(nof_f2_rbs) / 2.0F)) * 2; + if (f2_max_rbs > pucch_constants::FORMAT2_MAX_NPRB) { + return make_unexpected("The number of PRBs for PUCCH Format 2 exceeds the limit of 16"); + } + + // We define a block as a set of Resources (either F0/F1 or F2/F3) aligned over the same starting PRB. + const unsigned nof_f2_blocks = max_nof_symbols.to_uint() / f2_params.nof_symbols.to_uint(); + nof_f2_f3_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3) / static_cast(nof_f2_blocks))) * + f2_max_rbs; + // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. + if (f2_params.intraslot_freq_hopping) { + nof_f2_f3_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_rbs) / 2.0F)) * 2; + } + } else { + const auto& f3_params = std::get(f2_f3_params); + + const unsigned f3_max_rbs = f3_params.max_payload_bits.has_value() + ? get_pucch_format3_max_nof_prbs(f3_params.max_payload_bits.value(), + f3_params.nof_symbols.to_uint(), + to_max_code_rate_float(f3_params.max_code_rate), + f3_params.intraslot_freq_hopping, + f3_params.additional_dmrs, + f3_params.pi2_bpsk) + : f3_params.max_nof_rbs; + + if (f3_max_rbs > pucch_constants::FORMAT3_MAX_NPRB) { + return make_unexpected("The number of PRBs for PUCCH Format 3 exceeds the limit of 16"); + } + + const unsigned nof_f3_blocks = max_nof_symbols.to_uint() / f3_params.nof_symbols.to_uint(); + nof_f2_f3_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3) / static_cast(nof_f3_blocks))) * + f3_max_rbs; + // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. + if (f3_params.intraslot_freq_hopping) { + nof_f2_f3_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_rbs) / 2.0F)) * 2; + } } // Verify the number of RBs for the PUCCH resources does not exceed the BWP size. // [Implementation-defined] We do not allow the PUCCH resources to occupy more than 50% of the BWP. This is an extreme // case, and ideally the PUCCH configuration should result in a much lower PRBs usage. - const float max_allowed_prbs_usage = 0.5F; - if (static_cast(nof_f0_f1_rbs + nof_f2_rbs) / static_cast(bwp_size_rbs) >= max_allowed_prbs_usage) { + constexpr float max_allowed_prbs_usage = 0.5F; + if (static_cast(nof_f0_f1_rbs + nof_f2_f3_rbs) / static_cast(bwp_size_rbs) >= max_allowed_prbs_usage) { return make_unexpected("With the given parameters, the number of PRBs for PUCCH exceeds the 50% of the BWP PRBs"); } @@ -436,17 +560,17 @@ srsran::srs_du::pucch_parameters_validator(unsigned } static std::vector -merge_f0_f1_f2_resource_lists(const std::vector& pucch_f0_f1_resource_list, - const std::vector& pucch_f2_resource_list, - std::optional nof_cs, - unsigned bwp_size_rbs) +merge_f0_f1_f2_f3_resource_lists(const std::vector& pucch_f0_f1_resource_list, + const std::vector& pucch_f2_f3_resource_list, + std::optional nof_cs, + unsigned bwp_size_rbs) { - // This function merges the lists of PUCCH F0/F1 and F2 resource. It first allocates the F0/F1 resources on the sides - // of the BWP; second, it allocates the F2 resources beside F0/F1 ones. + // This function merges the lists of PUCCH F0/F1 and F2/F3 resource. It first allocates the F0/F1 resources on the + // sides of the BWP; second, it allocates the F2/F3 resources beside F0/F1 ones. std::vector resource_list; const bool has_f0 = not nof_cs.has_value(); - // NOTE: PUCCH F0/F1 resource are located at the sides of the BWP. PUCCH F2 are located beside the F0/F1 resources, + // NOTE: PUCCH F0/F1 resource are located at the sides of the BWP. PUCCH F2/F3 are located beside the F0/F1 resources, // specifically on F0/F1's right (on the frequency axis) for frequencies < BWP/2, and F0/F1's left (on the frequency // axis) for frequencies > BWP/2 and < BWP. unsigned f0_f1_rbs_occupancy_low_freq = 0; @@ -463,7 +587,7 @@ merge_f0_f1_f2_resource_lists(const std::vector& pucch_f0_f1_resour } pucch_format_0_cfg format0{.initial_cyclic_shift = 0U, .starting_sym_idx = res_f0.symbols.start()}; - // Update the frequency shift for PUCCH F2. + // Update the frequency shift for PUCCH F2/F3. if (res_f0.prbs.start() < bwp_size_rbs / 2 - 1U) { // f0_f1_rbs_occupancy_low_freq accounts for the PUCCH F0/F1 resource occupancy on the first half of the BWP; // PUCCH F0/F1 resources are located on the lowest RBs indices. @@ -500,7 +624,7 @@ merge_f0_f1_f2_resource_lists(const std::vector& pucch_f0_f1_resour } pucch_format_1_cfg format1{.starting_sym_idx = res_f1.symbols.start()}; - // Update the frequency shift for PUCCH F2. + // Update the frequency shift for PUCCH F2/F3. if (res_f1.prbs.start() < bwp_size_rbs / 2 - 1) { // f0_f1_rbs_occupancy_low_freq accounts for the PUCCH F0/F1 resource occupancy on the first half of the BWP; // PUCCH F0/F1 resources are located on the lowest RBs indices. @@ -532,47 +656,82 @@ merge_f0_f1_f2_resource_lists(const std::vector& pucch_f0_f1_resour } } - for (const auto& res_f2 : pucch_f2_resource_list) { - auto res_id = static_cast(resource_list.size()); - // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU - // before assigning the resources to the UE. - pucch_resource res{.res_id = {res_id, 0}}; - // Shift F2 RBs depending on previously allocated F0/F1 resources. - if (res_f2.prbs.start() < bwp_size_rbs / 2 - res_f2.prbs.length()) { - res.starting_prb = res_f2.prbs.start() + f0_f1_rbs_occupancy_low_freq; - if (res_f2.freq_hop_grant.has_value()) { - res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); - } - } else if (res_f2.prbs.start() > bwp_size_rbs / 2) { - res.starting_prb = res_f2.prbs.start() - f0_f1_rbs_occupancy_hi_freq; - if (res_f2.freq_hop_grant.has_value()) { - res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + const bool has_f2 = + not pucch_f2_f3_resource_list.empty() ? pucch_f2_f3_resource_list[0].format == pucch_format::FORMAT_2 : false; + + if (has_f2) { + for (const auto& res_f2 : pucch_f2_f3_resource_list) { + auto res_id = static_cast(resource_list.size()); + // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU + // before assigning the resources to the UE. + pucch_resource res{.res_id = {res_id, 0}}; + // Shift F2 RBs depending on previously allocated F0/F1 resources. + if (res_f2.prbs.start() < bwp_size_rbs / 2 - res_f2.prbs.length()) { + res.starting_prb = res_f2.prbs.start() + f0_f1_rbs_occupancy_low_freq; + if (res_f2.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); + } + } else if (res_f2.prbs.start() > bwp_size_rbs / 2) { + res.starting_prb = res_f2.prbs.start() - f0_f1_rbs_occupancy_hi_freq; + if (res_f2.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + } + } else { + srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); + return {}; } - } else { - srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); - return {}; + + pucch_format_2_3_cfg format2{.starting_sym_idx = res_f2.symbols.start()}; + format2.nof_symbols = res_f2.symbols.length(); + format2.nof_prbs = res_f2.prbs.length(); + res.format_params.emplace(format2); + res.format = pucch_format::FORMAT_2; + resource_list.emplace_back(res); } + } else { + for (const auto& res_f3 : pucch_f2_f3_resource_list) { + auto res_id = static_cast(resource_list.size()); + // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU + // before assigning the resources to the UE. + pucch_resource res{.res_id = {res_id, 0}}; + // Shift F2 RBs depending on previously allocated F0/F1 resources. + if (res_f3.prbs.start() < bwp_size_rbs / 2 - res_f3.prbs.length()) { + res.starting_prb = res_f3.prbs.start() + f0_f1_rbs_occupancy_low_freq; + if (res_f3.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f3.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); + } + } else if (res_f3.prbs.start() > bwp_size_rbs / 2) { + res.starting_prb = res_f3.prbs.start() - f0_f1_rbs_occupancy_hi_freq; + if (res_f3.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f3.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + } + } else { + srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); + return {}; + } - pucch_format_2_3_cfg format2{.starting_sym_idx = res_f2.symbols.start()}; - format2.nof_symbols = res_f2.symbols.length(); - format2.nof_prbs = res_f2.prbs.length(); - res.format_params.emplace(format2); - res.format = pucch_format::FORMAT_2; - resource_list.emplace_back(res); + pucch_format_2_3_cfg format3{.starting_sym_idx = res_f3.symbols.start()}; + format3.nof_symbols = res_f3.symbols.length(); + format3.nof_prbs = res_f3.prbs.length(); + res.format_params.emplace(format3); + res.format = pucch_format::FORMAT_3; + resource_list.emplace_back(res); + } } + return resource_list; } std::vector -srsran::srs_du::generate_cell_pucch_res_list(unsigned nof_res_f0_f1, - unsigned nof_res_f2, - std::variant f0_f1_params, - pucch_f2_params f2_params, - unsigned bwp_size_rbs, - bounded_integer max_nof_symbols) +srs_du::generate_cell_pucch_res_list(unsigned nof_res_f0_f1, + unsigned nof_res_f2_f3, + std::variant f0_f1_params, + std::variant f2_f3_params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { - auto outcome = - pucch_parameters_validator(nof_res_f0_f1, nof_res_f2, f0_f1_params, f2_params, bwp_size_rbs, max_nof_symbols); + auto outcome = pucch_parameters_validator( + nof_res_f0_f1, nof_res_f2_f3, f0_f1_params, f2_f3_params, bwp_size_rbs, max_nof_symbols); if (not outcome.has_value()) { srsran_assertion_failure("The cell list could not be generated due to: {}", outcome.error()); return {}; @@ -580,7 +739,7 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned const bool has_f0 = std::holds_alternative(f0_f1_params); - // Compute the PUCCH F0/F1 and F2 resources separately. + // Compute the PUCCH F0/F1 and F2/F3 resources separately. std::vector pucch_f0_f1_resource_list; unsigned nof_css = 0; if (has_f0 and nof_res_f0_f1 > 0) { @@ -595,14 +754,21 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned compute_f1_res(nof_res_f0_f1, f1_params, bwp_size_rbs, nof_css * nof_occ_codes, max_nof_symbols); } - const std::vector pucch_f2_resource_list = - nof_res_f2 > 0 ? compute_f2_res(nof_res_f2, f2_params, bwp_size_rbs, max_nof_symbols) - : std::vector{}; + const bool has_f2 = std::holds_alternative(f2_f3_params); + + std::vector pucch_f2_f3_resource_list; + if (has_f2 and nof_res_f2_f3 > 0) { + const pucch_f2_params f2_params = std::get(f2_f3_params); + pucch_f2_f3_resource_list = compute_f2_res(nof_res_f2_f3, f2_params, bwp_size_rbs, max_nof_symbols); + } else if (nof_res_f2_f3 > 0) { + const pucch_f3_params f3_params = std::get(f2_f3_params); + pucch_f2_f3_resource_list = compute_f3_res(nof_res_f2_f3, f3_params, bwp_size_rbs, max_nof_symbols); + } - auto res_list = merge_f0_f1_f2_resource_lists(pucch_f0_f1_resource_list, - pucch_f2_resource_list, - has_f0 ? std::nullopt : std::optional{nof_css}, - bwp_size_rbs); + auto res_list = merge_f0_f1_f2_f3_resource_lists(pucch_f0_f1_resource_list, + pucch_f2_f3_resource_list, + has_f0 ? std::nullopt : std::optional{nof_css}, + bwp_size_rbs); if (res_list.size() > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { srsran_assertion_failure("With the given parameters, the number of PUCCH resources generated for the " @@ -617,12 +783,12 @@ srsran::srs_du::generate_cell_pucch_res_list(unsigned static unsigned cell_res_list_and_params_validator(const std::vector& res_list, bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_res_harq, + bounded_integer nof_ue_pucch_f2_f3_res_harq, unsigned nof_harq_pucch_cfgs, - unsigned nof_cell_pucch_f1_res_sr, - unsigned nof_cell_pucch_f2_res_csi) + unsigned nof_cell_pucch_f0_f1_res_sr, + unsigned nof_cell_pucch_f2_f3_res_csi) { - const unsigned FAILURE_CASE = 0U; + constexpr unsigned FAILURE_CASE = 0U; auto count_resources = [&res_list](pucch_format format) { unsigned cnt = 0; @@ -637,15 +803,18 @@ cell_res_list_and_params_validator(const std::vector& const auto contain_format_0 = std::find_if(res_list.begin(), res_list.end(), [](const pucch_resource& res) { return res.format == pucch_format::FORMAT_0; }) != res_list.end(); + const auto contain_format_2 = std::find_if(res_list.begin(), res_list.end(), [](const pucch_resource& res) { + return res.format == pucch_format::FORMAT_2; + }) != res_list.end(); - if (contain_format_0) { + if (contain_format_0 and contain_format_2) { if (nof_ue_pucch_f0_f1_res_harq.to_uint() > 6U) { srsran_assertion_failure("With Format 0, nof_ue_pucch_f0_f1_res_harq cannot be greater than 6, as 2 " "resources in set 0 are reserved."); return FAILURE_CASE; } - if (nof_ue_pucch_f2_res_harq.to_uint() > 6U) { - srsran_assertion_failure("With Format 0, nof_ue_pucch_f2_res_harq cannot be greater than 6, as 2 " + if (nof_ue_pucch_f2_f3_res_harq.to_uint() > 6U) { + srsran_assertion_failure("With Format 0, nof_ue_pucch_f2_f3_res_harq cannot be greater than 6, as 2 " "resources in set 1 are reserved."); return FAILURE_CASE; } @@ -654,42 +823,56 @@ cell_res_list_and_params_validator(const std::vector& const unsigned tot_nof_f0_res = count_resources(pucch_format::FORMAT_0); const unsigned tot_nof_f1_res = count_resources(pucch_format::FORMAT_1); const unsigned tot_nof_f2_res = count_resources(pucch_format::FORMAT_2); + const unsigned tot_nof_f3_res = count_resources(pucch_format::FORMAT_3); if (tot_nof_f0_res != 0 and tot_nof_f1_res != 0) { srsran_assertion_failure("The cell PUCCH resource list can contain either F0 or F1 PUCCH resources, but not both."); return FAILURE_CASE; } + if (tot_nof_f2_res != 0 and tot_nof_f3_res != 0) { + srsran_assertion_failure("The cell PUCCH resource list can contain either F2 or F3 PUCCH resources, but not both."); + return FAILURE_CASE; + } + + if (tot_nof_f0_res != 0 and (tot_nof_f3_res != 0)) { + srsran_assertion_failure( + "The implementation is not currently prepared to handle PUCCH F0 and F3 resources at the same time."); + return FAILURE_CASE; + } + const unsigned tot_nof_f0_f1_res = tot_nof_f0_res + tot_nof_f1_res; + const unsigned tot_nof_f2_f3_res = tot_nof_f2_res + tot_nof_f3_res; - if (tot_nof_f0_f1_res + tot_nof_f2_res != res_list.size()) { + if (tot_nof_f0_f1_res + tot_nof_f2_f3_res != res_list.size()) { srsran_assertion_failure( - "The sum of F0/F1 and F2 PUCCH resources must be equal to the cell PUCCH resource list size."); + "The sum of F0/F1 and F2/F3 PUCCH resources must be equal to the cell PUCCH resource list size."); return FAILURE_CASE; } - if (tot_nof_f0_f1_res < 2 or tot_nof_f2_res < 2) { - srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2 PUCCH resources."); + if (tot_nof_f0_f1_res < 2 or tot_nof_f2_f3_res < 2) { + srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2/F3 PUCCH resources."); return FAILURE_CASE; } - if (nof_ue_pucch_f0_f1_res_harq.to_uint() > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr or - nof_ue_pucch_f2_res_harq.to_uint() > tot_nof_f2_res - nof_cell_pucch_f2_res_csi) { + if (nof_ue_pucch_f0_f1_res_harq.to_uint() > tot_nof_f0_f1_res - nof_cell_pucch_f0_f1_res_sr or + nof_ue_pucch_f2_f3_res_harq.to_uint() > tot_nof_f2_f3_res - nof_cell_pucch_f2_f3_res_csi) { srsran_assertion_failure( "The nof requested UE PUCCH resources is greater than the nof of resources available in the cell."); return FAILURE_CASE; } - if ((nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f0_f1_res - nof_cell_pucch_f1_res_sr) or - (nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f2_res - nof_cell_pucch_f2_res_csi)) { + if ((nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f0_f1_res - nof_cell_pucch_f0_f1_res_sr) or + (nof_ue_pucch_f2_f3_res_harq.to_uint() * nof_harq_pucch_cfgs > + tot_nof_f2_f3_res - nof_cell_pucch_f2_f3_res_csi)) { srsran_assertion_failure( "The cell PUCCH resource list doesn't contain enough resources to allocate all requested UEs."); return FAILURE_CASE; } for (unsigned res_idx = 0; res_idx != tot_nof_f0_f1_res; ++res_idx) { - if (res_list[res_idx].format == pucch_format::FORMAT_2) { - srsran_assertion_failure("The F0/F1 resources in the cell PUCCH resource list must precede all F2 resources."); + if (res_list[res_idx].format == pucch_format::FORMAT_2 || res_list[res_idx].format == pucch_format::FORMAT_3) { + srsran_assertion_failure("The F0/F1 resources in the cell PUCCH resource list must precede all F2/F3 resources."); return FAILURE_CASE; } } @@ -697,24 +880,23 @@ cell_res_list_and_params_validator(const std::vector& return tot_nof_f0_res != 0 ? tot_nof_f0_res : tot_nof_f1_res; } -bool srsran::srs_du::ue_pucch_config_builder( - serving_cell_config& serv_cell_cfg, - const std::vector& res_list, - unsigned du_harq_set_idx, - unsigned du_sr_res_idx, - unsigned du_csi_res_idx, - bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_res_harq, - unsigned nof_harq_pucch_sets, - unsigned nof_cell_pucch_f0_f1_res_sr, - unsigned nof_cell_pucch_f2_res_csi) +bool srs_du::ue_pucch_config_builder(serving_cell_config& serv_cell_cfg, + const std::vector& res_list, + unsigned du_harq_set_idx, + unsigned du_sr_res_idx, + unsigned du_csi_res_idx, + bounded_integer nof_ue_pucch_f0_f1_res_harq, + bounded_integer nof_ue_pucch_f2_f3_res_harq, + unsigned nof_harq_pucch_sets, + unsigned nof_cell_pucch_f0_f1_res_sr, + unsigned nof_cell_pucch_f2_f3_res_csi) { const unsigned tot_nof_cell_f0_f1_res = cell_res_list_and_params_validator(res_list, nof_ue_pucch_f0_f1_res_harq, - nof_ue_pucch_f2_res_harq, + nof_ue_pucch_f2_f3_res_harq, nof_harq_pucch_sets, nof_cell_pucch_f0_f1_res_sr, - nof_cell_pucch_f2_res_csi); + nof_cell_pucch_f2_f3_res_csi); if (tot_nof_cell_f0_f1_res == 0U) { return false; @@ -736,12 +918,15 @@ bool srsran::srs_du::ue_pucch_config_builder( pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_set_id = pucch_res_set_idx::set_1; - // Add F1 for HARQ. const unsigned f0_f1_idx_offset = (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq.to_uint(); const bool is_format_0 = res_list[f0_f1_idx_offset].format == pucch_format::FORMAT_0; + const unsigned f2_f3_idx_offset = + tot_nof_cell_f0_f1_res + (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_res_harq.to_uint(); + const bool is_format_2 = res_list[f2_f3_idx_offset].format == pucch_format::FORMAT_2; - for (unsigned ue_f1_cnt = 0; ue_f1_cnt < nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f1_cnt) { - const auto& cell_res = res_list[ue_f1_cnt + f0_f1_idx_offset]; + // Add F0/F1 for HARQ. + for (unsigned ue_f0_f1_cnt = 0; ue_f0_f1_cnt < nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f0_f1_cnt) { + const auto& cell_res = res_list[ue_f0_f1_cnt + f0_f1_idx_offset]; // Add PUCCH resource to pucch_res_list. pucch_cfg.pucch_res_list.emplace_back(pucch_resource{.res_id = {cell_res.res_id.cell_res_id, ue_pucch_res_id}, @@ -758,9 +943,9 @@ bool srsran::srs_du::ue_pucch_config_builder( ++ue_pucch_res_id; } - const unsigned f0_res_on_csi_prbs_syms_idx = nof_ue_pucch_f0_f1_res_harq.to_uint(); - if (is_format_0 and serv_cell_cfg.csi_meas_cfg.has_value()) { - // Add PUCCH resource to pucch_res_list. + const unsigned f0_f1_res_on_csi_prbs_syms_idx = nof_ue_pucch_f0_f1_res_harq.to_uint(); + if (is_format_0 and is_format_2 and serv_cell_cfg.csi_meas_cfg.has_value()) { + // Add CSI_F0 PUCCH resource to pucch_res_list. pucch_cfg.pucch_res_list.emplace_back(pucch_resource{ .res_id = {std::numeric_limits::max(), ue_pucch_res_id}, .format = pucch_format::FORMAT_0}); @@ -786,8 +971,8 @@ bool srsran::srs_du::ue_pucch_config_builder( // Increment the PUCCH resource ID for ASN1 message. ++ue_pucch_res_id; - // For Format 0, map the last resource of the set 0 to the SR resource. - if (is_format_0) { + // For Format 0, map the last resource of the set 0 to the SR resource (SR_F0). + if (is_format_0 and is_format_2) { auto& last_harq_res_set_0 = pucch_cfg.pucch_res_list.back(); last_harq_res_set_0.res_id.cell_res_id = sr_cell_res.res_id.cell_res_id; last_harq_res_set_0.res_id.ue_res_id = ue_pucch_res_id_for_sr; @@ -799,11 +984,11 @@ bool srsran::srs_du::ue_pucch_config_builder( pucch_res_id_t{sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}); } - // Add F2 for HARQ. - const unsigned f2_idx_offset = - tot_nof_cell_f0_f1_res + (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_res_harq.to_uint(); - for (unsigned ue_f2_cnt = 0; ue_f2_cnt < nof_ue_pucch_f2_res_harq.to_uint(); ++ue_f2_cnt) { - const auto& cell_res = res_list[f2_idx_offset + ue_f2_cnt]; + // Add F2/F3 for HARQ. + for (unsigned ue_f2_f3_cnt = 0; ue_f2_f3_cnt < nof_ue_pucch_f2_f3_res_harq.to_uint(); ++ue_f2_f3_cnt) { + const auto& cell_res = res_list[f2_f3_idx_offset + ue_f2_f3_cnt]; + + // Add PUCCH resource to pucch_res_list. pucch_cfg.pucch_res_list.emplace_back(pucch_resource{.res_id = {cell_res.res_id.cell_res_id, ue_pucch_res_id}, .starting_prb = cell_res.starting_prb, .second_hop_prb = cell_res.second_hop_prb, @@ -820,7 +1005,7 @@ bool srsran::srs_du::ue_pucch_config_builder( if (serv_cell_cfg.csi_meas_cfg.has_value()) { // Add CSI resource. const unsigned csi_res_idx = - tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_res_harq.to_uint() * nof_harq_pucch_sets + du_csi_res_idx; + tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_f3_res_harq.to_uint() * nof_harq_pucch_sets + du_csi_res_idx; const auto& csi_cell_res = res_list[csi_res_idx]; const unsigned ue_pucch_res_id_for_csi = ue_pucch_res_id; pucch_cfg.pucch_res_list.emplace_back( @@ -834,10 +1019,12 @@ bool srsran::srs_du::ue_pucch_config_builder( serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list[0].report_cfg_type) .pucch_csi_res_list.front() .pucch_res_id = {csi_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_csi}; + // Increment the PUCCH resource ID for ASN1 message. ++ue_pucch_res_id; - if (is_format_0) { + if (is_format_0 and is_format_2) { + // Add CSI_F2 resource. auto& harq_set_1_res_for_csi = pucch_cfg.pucch_res_list.back(); harq_set_1_res_for_csi.res_id.cell_res_id = csi_cell_res.res_id.cell_res_id; harq_set_1_res_for_csi.res_id.ue_res_id = ue_pucch_res_id_for_csi; @@ -848,7 +1035,8 @@ bool srsran::srs_du::ue_pucch_config_builder( pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(pucch_res_set_idx::set_1)].pucch_res_id_list.emplace_back( pucch_res_id_t{csi_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_csi}); - auto& f0_harq_on_csi_resources = pucch_cfg.pucch_res_list[f0_res_on_csi_prbs_syms_idx]; + // Fill the parameters for CSI_F0. + auto& f0_harq_on_csi_resources = pucch_cfg.pucch_res_list[f0_f1_res_on_csi_prbs_syms_idx]; f0_harq_on_csi_resources.starting_prb = csi_cell_res.starting_prb; f0_harq_on_csi_resources.second_hop_prb = csi_cell_res.second_hop_prb; f0_harq_on_csi_resources.format_params.emplace( @@ -859,8 +1047,8 @@ bool srsran::srs_du::ue_pucch_config_builder( } const unsigned f2_res_on_sr_prbs_syms_idx = ue_pucch_res_id; - if (is_format_0) { - // Add PUCCH resource to pucch_res_list. + if (is_format_0 and is_format_2) { + // Add SR_F2 PUCCH resource to pucch_res_list. pucch_cfg.pucch_res_list.emplace_back(pucch_resource{ .res_id = {std::numeric_limits::max(), ue_pucch_res_id}, .format = pucch_format::FORMAT_2}); @@ -871,6 +1059,7 @@ bool srsran::srs_du::ue_pucch_config_builder( // Increment the PUCCH resource ID for ASN1 message. ++ue_pucch_res_id; + // Fill the parameters for SR_F2. auto& f2_harq_on_sr_resources = pucch_cfg.pucch_res_list[f2_res_on_sr_prbs_syms_idx]; f2_harq_on_sr_resources.starting_prb = sr_cell_res.starting_prb; f2_harq_on_sr_resources.second_hop_prb = sr_cell_res.second_hop_prb; diff --git a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h index 221461eee6..4d98017049 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h +++ b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h @@ -18,78 +18,83 @@ namespace srsran::srs_du { /// The following values have to be set according to the \ref pucch_resource_manager capabilities. /// Maximum number of PUCCH F0/F1 resources per UE for HARQ-ACK reporting. constexpr unsigned max_ue_f0_f1_res_harq = 8; -/// Maximum number of PUCCH F2 resources per UE for HARQ-ACK reporting. -constexpr unsigned max_ue_f2_res_harq = 8; +/// Maximum number of PUCCH F2/F3 resources per UE for HARQ-ACK reporting. +constexpr unsigned max_ue_f2_f3_res_harq = 8; /// \brief Validates the user-defined parameters for building the PUCCH resource list. -/// \param[in] nof_res_f1 number of PUCCH F0/F1 resources to be generated. -/// \param[in] nof_res_f2 number of PUCCH F2 resources to be generated. -/// \param[in] f1_params PUCCH F0/F1 resource parameters. -/// \param[in] f1_params PUCCH F2 resource parameters. -/// \param[in] bwp_size_rbs Size of the BWP in RBs. +/// \param[in] nof_res_f0_f1 number of PUCCH F0/F1 resources to be generated. +/// \param[in] nof_res_f2_f3 number of PUCCH F2/F3 resources to be generated. +/// \param[in] f0_f1_params PUCCH F0/F1 resource parameters. +/// \param[in] f2_f3_params PUCCH F2 resource parameters. +/// \param[in] bwp_size_rbs size of the BWP in RBs. +/// \param[in] max_nof_symbols maximum number of symbols. /// \return In case an invalid parameter is detected, returns a string containing an error message. error_type pucch_parameters_validator(unsigned nof_res_f0_f1, - unsigned nof_res_f2, + unsigned nof_res_f2_f3, std::variant f0_f1_params, - pucch_f2_params f2_params, + std::variant f2_f3_params, unsigned bwp_size_rbs, bounded_integer max_nof_symbols); -/// \brief Generates the list of cell PUCCH resources (Format 0/1 and 2) given the number of requested resources. +/// \brief Generates the list of cell PUCCH resources (Format 0/1 and 2/3) given the number of requested resources. /// -/// PUCCH resources F0/F1 and F2 are allocated on different RBs. The function attempts to spread the resources on both -/// sides of the BWP. +/// PUCCH resources F0/F1 and F2/F3 are allocated on different RBs. The function attempts to spread the resources on +/// both sides of the BWP. /// -/// \param[in] nof_res_f0_f1 number of PUCCH F0/F1 resources to be generated. -/// \param[in] nof_res_f2 number of PUCCH F2 resources to be generated. -/// \param[in] f1_params PUCCH F0/F1 resource parameters. -/// \param[in] f1_params PUCCH F2 resource parameters. -/// \param[in] bwp_size_rbs Size of the BWP in RBs. +/// \param[in] nof_res_f0_f1 number of PUCCH F0/F1 resources to be generated. +/// \param[in] nof_res_f2_f3 number of PUCCH F2/F3 resources to be generated. +/// \param[in] f0_f1_params PUCCH F0/F1 resource parameters. +/// \param[in] f2_f3_params PUCCH F2/F3 resource parameters. +/// \param[in] bwp_size_rbs Size of the BWP in RBs. +/// \param[in] max_nof_symbols Maximum number of symbols. /// \return The list of PUCCH resources for a cell. The list has the PUCCH Format 0/1 resources in front of the list, -/// and the PUCCH Format 2 in the back of the list. +/// and the PUCCH Format 2/3 in the back of the list. /// \remark The function returns an empty list in the following cases: (i) If overall the RBs occupancy is larger than /// the BWP size. (ii) If F2 intra-slot frequency hopping is enabled with only 1 symbol. std::vector generate_cell_pucch_res_list(unsigned nof_res_f0_f1, - unsigned nof_res_f2, + unsigned nof_res_f2_f3, std::variant f0_f1_params, - pucch_f2_params f2_params, + std::variant f2_f3_params, unsigned bwp_size_rbs, bounded_integer max_nof_symbols); /// \brief Generates the list of PUCCH resources for a given UE. /// -/// This function generates the list of PUCCH F0/F1 and F2 resources for a given UE, including the resources for +/// This function generates the list of PUCCH F0/F1 and F2/F3 resources for a given UE, including the resources for /// HARQ-ACK reporting, SR and CSI. It also updates the PUCCH resource sets accordingly, as well as the pointers to the -/// PUCCH F0/F1 resource for SR and to the PUCCH F2 resource for CSI. This function overwrites the default \c +/// PUCCH F0/F1 resource for SR and to the PUCCH F2/F3 resource for CSI. This function overwrites the default \c /// ServingCellConfig passed as a function input. /// /// The UE's PUCCH resource list composed of: -/// - \ref nof_ue_pucch_f0_or_f1_res_harq PUCCH Format 0/1 resources for HARQ-ACK reporting, chosen from +/// - \ref nof_ue_pucch_f0_f1_res_harq PUCCH Format 0/1 resources for HARQ-ACK reporting, chosen from /// \ref nof_harq_pucch_sets possible sets of PUCCH Format 0/1 cell resources. /// - 1 PUCCH Format 0/1 resource for SR chosen from \ref nof_cell_pucch_f0_f1_res_sr possible sets of PUCCH Format 0/1 /// cell resources. -/// - \ref nof_ue_pucch_f0_or_f1_res_harq PUCCH Format 2 resources for HARQ-ACK reporting, chosen from -/// \ref nof_harq_pucch_sets possible sets of PUCCH Format 2 cell resources. -/// - 1 PUCCH Format 2 resource for CSI chosen from \ref nof_cell_pucch_f2_res_csi possible sets of PUCCH Format 0/1 +/// - \ref nof_ue_pucch_f2_f3_res_harq PUCCH Format 2/3 resources for HARQ-ACK reporting, chosen from +/// \ref nof_harq_pucch_sets possible sets of PUCCH Format 2/3 cell resources. +/// - 1 PUCCH Format 2/3 resource for CSI chosen from \ref nof_cell_pucch_f2_f3_res_csi possible sets of PUCCH Format +/// 2/3 /// cell resources. /// /// The returned UE PUCCH resource list \ref pucch_res_list contains the following resources, sorted as follows: -/// [ F0/F1-HARQ_0 ... F0/F1-HARQ_N-1 F0/F1-SR F2-HARQ_0 ... F2-HARQ_M-1 F2-CSI ] -/// where N = nof_ue_pucch_f0_or_f1_res_harq and M = nof_ue_pucch_f2_res_harq, +/// [ F0/F1-HARQ_0 ... F0/F1-HARQ_N-1 F0/F1-SR F2/F3-HARQ_0 ... F2/F3-HARQ_M-1 F2/F3-CSI ] +/// where N = nof_ue_pucch_f0_f1_res_harq and M = nof_ue_pucch_f2_f3_res_harq, /// and with the following indices \ref res_id: -/// - The first \ref nof_ue_pucch_f0_or_f1_res_harq are the PUCCH F0/F1 resources for HARQ-ACK and have index -/// [ (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_or_f1_res_harq, -/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_or_f1_res_harq + nof_ue_pucch_f0_or_f1_res_harq ). +/// - The first \ref nof_ue_pucch_f0_f1_res_harq are the PUCCH F0/F1 resources for HARQ-ACK and have index +/// [ (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq, +/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq + nof_ue_pucch_f0_f1_res_harq ). /// - The next resource in the list is the PUCCH F0/F1 resource for SR, which have index: -/// nof_harq_pucch_sets * nof_ue_pucch_f0_or_f1_res_harq + du_sr_res_idx % nof_cell_pucch_f0_f1_res_sr. -/// - The next \ref nof_ue_pucch_f2_res_harq are the PUCCH F2 resources for HARQ-ACK and have index -/// [ nof_harq_pucch_sets * nof_ue_pucch_f0_or_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + -/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_res_harq, -/// nof_harq_pucch_sets * nof_ue_pucch_f0_or_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + -/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_res_harq + nof_ue_pucch_f2_res_harq). -/// - The last resource in the list is the PUCCH F2 resource for CSI, which has index: -//// nof_harq_pucch_sets * nof_ue_pucch_f0_or_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + -/// nof_ue_pucch_f2_res_harq * nof_harq_pucch_sets + du_csi_res_idx % nof_cell_pucch_f2_res_csi. +/// nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + du_sr_res_idx % nof_cell_pucch_f0_f1_res_sr. +/// - The next \ref nof_ue_pucch_f2_f3_res_harq are the PUCCH F2/F3 resources for HARQ-ACK and have index +/// [ nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + +/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_res_harq, +/// nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + +/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_res_harq + +/// nof_ue_pucch_f2_f3_res_harq). +/// - The last resource in the list is the PUCCH F2/F3 resource for CSI, which has index: +//// nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + +/// nof_ue_pucch_f2_f3_res_harq * nof_harq_pucch_sets + du_csi_res_idx % +/// nof_cell_pucch_f2_f3_res_csi. /// /// \param[in,out] serv_cell_cfg default \c ServingCellConfig that will be overwritten by this function. /// \param[in] res_list cell PUCCH resource list from which the function picks the UE PUCCH resources. @@ -101,9 +106,10 @@ std::vector generate_cell_pucch_res_list(unsigned /// \param[in] du_csi_res_idx defines which PUCCH resource for CSI to be assigned to this UE among /// \ref nof_cell_pucch_f2_res_csi possible ones. Values: {0, ..., nof_cell_pucch_f2_res_csi-1}. /// \param[in] nof_ue_pucch_f0_f1_res_harq desired number of UE PUCCH F0/F1 resources (HARQ-ACK) in UE configuration. -/// \param[in] nof_ue_pucch_f2_res_harq desired number of UE PUCCH F2 resources (HARQ-ACK) in UE configuration. +/// \param[in] nof_ue_pucch_f2_f3_res_harq desired number of UE PUCCH F2/F3 resources (HARQ-ACK) in UE configuration. +/// \param[in] nof_harq_pucch_sets number of possible HARQ sets available in the cell. /// \param[in] nof_cell_pucch_f0_f1_res_sr number of PUCCH F0/F1 resources for SR available in the cell. -/// \param[in] nof_cell_pucch_f2_res_csi number of PUCCH F2 resources for CSI available in the cell. +/// \param[in] nof_cell_pucch_f2_f3_res_csi number of PUCCH F2/F3 resources for CSI available in the cell. /// \return true if the building is successful, false otherwise. bool ue_pucch_config_builder(serving_cell_config& serv_cell_cfg, const std::vector& res_list, @@ -111,8 +117,8 @@ bool ue_pucch_config_builder(serving_cell_config& unsigned du_sr_res_idx, unsigned du_csi_res_idx, bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_res_harq, + bounded_integer nof_ue_pucch_f2_f3_res_harq, unsigned nof_harq_pucch_sets, unsigned nof_cell_pucch_f0_f1_res_sr, - unsigned nof_cell_pucch_f2_res_csi = 1); + unsigned nof_cell_pucch_f2_f3_res_csi = 1); } // namespace srsran::srs_du diff --git a/lib/du/du_update_config_helpers.cpp b/lib/du/du_update_config_helpers.cpp index a1c5d0082e..6309f38bd2 100644 --- a/lib/du/du_update_config_helpers.cpp +++ b/lib/du/du_update_config_helpers.cpp @@ -68,10 +68,10 @@ srsran::config_helpers::find_largest_prb_interval_without_pucch(const srs_du::pu const std::vector& res_list = srs_du::generate_cell_pucch_res_list( user_params.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_sr_resources, - user_params.nof_ue_pucch_f2_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + + user_params.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_csi_resources, user_params.f0_or_f1_params, - user_params.f2_params, + user_params.f2_or_f3_params, bwp_size, user_params.max_nof_symbols); srsran_assert(not res_list.empty(), "The PUCCH resource list cannot be empty"); diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index 94893bedae..4f7597e0f5 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -126,7 +126,7 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_common_parameters(mac_pdu.format, f3.slot_repetition, f3.pi_2_bpsk); // Scrambling. - builder.set_scrambling_parameters(f3.n_id_scambling); + builder.set_scrambling_parameters(f3.n_id_scrambling); // DM-RS. builder.set_dmrs_parameters(f3.additional_dmrs, f3.n_id_0_scrambling, f3.m_0_cyclic_shift); diff --git a/lib/scheduler/config/sched_cell_config_helpers.cpp b/lib/scheduler/config/sched_cell_config_helpers.cpp index 62066ddb99..55f638cc06 100644 --- a/lib/scheduler/config/sched_cell_config_helpers.cpp +++ b/lib/scheduler/config/sched_cell_config_helpers.cpp @@ -23,10 +23,10 @@ srsran::config_helpers::build_pucch_guardbands_list(const srs_du::pucch_builder_ std::vector res_list = srs_du::generate_cell_pucch_res_list( user_params.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_sr_resources, - user_params.nof_ue_pucch_f2_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + + user_params.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_csi_resources, user_params.f0_or_f1_params, - user_params.f2_params, + user_params.f2_or_f3_params, bwp_size, user_params.max_nof_symbols); @@ -42,20 +42,16 @@ srsran::config_helpers::build_pucch_guardbands_list(const srs_du::pucch_builder_ srsran_assert(std::holds_alternative(pucch_res.format_params) or std::holds_alternative(pucch_res.format_params) or std::holds_alternative(pucch_res.format_params), - "Only PUCCH format 0, 1 and 2 are currently supported"); + "Only PUCCH format 0, 1 and 2 and 3 are currently supported"); unsigned starting_sym = 0; unsigned nof_symbols = 0; - if (std::holds_alternative(pucch_res.format_params)) { - starting_sym = std::get(pucch_res.format_params).starting_sym_idx; - nof_symbols = std::get(pucch_res.format_params).nof_symbols; - } else if (std::holds_alternative(pucch_res.format_params)) { - starting_sym = std::get(pucch_res.format_params).starting_sym_idx; - nof_symbols = std::get(pucch_res.format_params).nof_symbols; - } else { - starting_sym = std::get(pucch_res.format_params).starting_sym_idx; - nof_symbols = std::get(pucch_res.format_params).nof_symbols; - } + std::visit( + [&starting_sym, &nof_symbols](const auto& format_params) { + starting_sym = format_params.starting_sym_idx; + nof_symbols = format_params.nof_symbols; + }, + pucch_res.format_params); // For PUCCH format 1, the resource has 1 PRB only. const unsigned nof_prbs = std::holds_alternative(pucch_res.format_params) diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index b7625a381e..3a3a14e79c 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -601,7 +601,7 @@ class du_high_bench // Increase nof. PUCCH resources to accommodate more UEs. cfg.ran.cells[0].pucch_cfg.nof_sr_resources = 30; cfg.ran.cells[0].pucch_cfg.nof_csi_resources = 30; - cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f2_res_harq = 8; + cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = 8; cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 8; cfg.ran.cells[0].pucch_cfg.nof_cell_harq_pucch_res_sets = 4; auto& f1_params = cfg.ran.cells[0].pucch_cfg.f0_or_f1_params.emplace(); diff --git a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp index 783bd2813b..31ac866fbb 100644 --- a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp @@ -79,12 +79,13 @@ class multi_ue_sched_simulator sch(create_scheduler(scheduler_config{expert_cfg, cfg_notif, metric_notif})), next_sl_tx(builder_params.scs_common, 0) { - du_cell_cfgs = {config_helpers::make_default_du_cell_config(builder_params)}; - du_cell_cfgs[0].pucch_cfg.f2_params.max_code_rate = max_pucch_code_rate::dot_35; - du_cell_cfgs[0].pucch_cfg.nof_csi_resources = 4; - du_cell_cfgs[0].pucch_cfg.nof_sr_resources = 2; + du_cell_cfgs = {config_helpers::make_default_du_cell_config(builder_params)}; + std::get(du_cell_cfgs[0].pucch_cfg.f2_or_f3_params).max_code_rate = + max_pucch_code_rate::dot_35; + du_cell_cfgs[0].pucch_cfg.nof_csi_resources = 4; + du_cell_cfgs[0].pucch_cfg.nof_sr_resources = 2; du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 3; - du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f2_res_harq = 6; + du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = 6; sched_cell_configuration_request_message cell_cfg_msg = sched_config_helper::make_default_sched_cell_configuration_request(builder_params); diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index 829bc3ca21..552e6acb62 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -32,7 +32,7 @@ static du_high_env_sim_params create_custom_params() tdd_ul_dl_config_common{subcarrier_spacing::kHz30, {10, 8, 5, 1, 4}}; params.pucch_cfg.emplace(); params.pucch_cfg->nof_ue_pucch_f0_or_f1_res_harq = 8; - params.pucch_cfg->nof_ue_pucch_f2_res_harq = 8; + params.pucch_cfg->nof_ue_pucch_f2_or_f3_res_harq = 8; params.pucch_cfg->nof_sr_resources = 1; // Set the PRACH frequency start to avoid PRACH collisions with the PUCCH on the upper RBs of the BWP (this would // trigger an error and abort the test). diff --git a/tests/test_doubles/scheduler/scheduler_config_helper.cpp b/tests/test_doubles/scheduler/scheduler_config_helper.cpp index b0f33df811..f5b8409343 100644 --- a/tests/test_doubles/scheduler/scheduler_config_helper.cpp +++ b/tests/test_doubles/scheduler/scheduler_config_helper.cpp @@ -46,7 +46,7 @@ sched_cell_configuration_request_message srsran::sched_config_helper::make_defau srs_du::pucch_builder_params default_pucch_builder_params = srs_du::du_cell_config{}.pucch_cfg; default_pucch_builder_params.nof_ue_pucch_f0_or_f1_res_harq = 3; - default_pucch_builder_params.nof_ue_pucch_f2_res_harq = 6; + default_pucch_builder_params.nof_ue_pucch_f2_or_f3_res_harq = 6; default_pucch_builder_params.nof_sr_resources = 2; sched_req.pucch_guardbands = config_helpers::build_pucch_guardbands_list( diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 97f1aa535c..67e8a6806e 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -116,9 +116,10 @@ class du_ran_resource_manager_tester_base const du_cell_config& du_cfg = cell_cfg_list[0]; const unsigned nof_sr_f1_res_per_ue = 1U; const unsigned nof_csi_f2_res_per_ue = 1U; - bool pucch_checker = pucch_cfg.pucch_res_list.size() == du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + - du_cfg.pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint() + - nof_sr_f1_res_per_ue + nof_csi_f2_res_per_ue; + bool pucch_checker = + pucch_cfg.pucch_res_list.size() == du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + + du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() + + nof_sr_f1_res_per_ue + nof_csi_f2_res_per_ue; // Check whether the SR resource point to the correct one (we give a range where the SR resource is located), each // UE can have different values within this range. @@ -133,7 +134,7 @@ class du_ran_resource_manager_tester_base pucch_checker = pucch_checker and csi_pucch_res.value() >= du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + du_cfg.pucch_cfg.nof_sr_resources + - du_cfg.pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint(); + du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint(); } return pucch_checker; @@ -325,7 +326,7 @@ static du_cell_config make_custom_du_cell_config(const pucch_cfg_builder_params& du_cell_config du_cfg = config_helpers::make_default_du_cell_config(); auto& pucch_params = du_cfg.pucch_cfg; pucch_params.nof_ue_pucch_f0_or_f1_res_harq = pucch_params_.nof_res_f1_harq; - pucch_params.nof_ue_pucch_f2_res_harq = pucch_params_.nof_res_f2_harq; + pucch_params.nof_ue_pucch_f2_or_f3_res_harq = pucch_params_.nof_res_f2_harq; pucch_params.nof_sr_resources = pucch_params_.nof_res_sr; pucch_params.nof_csi_resources = pucch_params_.nof_res_csi; pucch_params.nof_cell_harq_pucch_res_sets = pucch_params_.nof_harq_cfg; @@ -365,7 +366,7 @@ class du_ran_res_mng_multiple_cfg_tester : public du_ran_resource_manager_tester const auto& pucch_res_set = pucch_cfg.pucch_res_set[pucch_res_set_id].pucch_res_id_list; const unsigned expected_pucch_res_set_size = format == pucch_format::FORMAT_1 ? cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() - : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint(); + : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint(); if (expected_pucch_res_set_size != pucch_res_set.size()) { return {}; } @@ -386,7 +387,7 @@ class du_ran_res_mng_multiple_cfg_tester : public du_ran_resource_manager_tester { const unsigned expected_nof_pucch_res = format == pucch_format::FORMAT_1 ? cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() - : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_res_harq.to_uint(); + : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint(); if (expected_nof_pucch_res == 0) { return interval{}; @@ -798,7 +799,7 @@ static du_cell_config make_custom_pucch_srs_du_cell_config(bool pucch_has_more_r du_cell_config du_cfg = config_helpers::make_default_du_cell_config(); auto& pucch_params = du_cfg.pucch_cfg; pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6U; - pucch_params.nof_ue_pucch_f2_res_harq = 6U; + pucch_params.nof_ue_pucch_f2_or_f3_res_harq = 6U; pucch_params.nof_sr_resources = pucch_has_more_res_than_srs ? 10U : 1U; pucch_params.nof_csi_resources = pucch_has_more_res_than_srs ? 10U : 1U; pucch_params.nof_cell_harq_pucch_res_sets = 1U; diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index 0830d75658..bda12b7f3e 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -12,6 +12,7 @@ #include "tests/test_doubles/scheduler/scheduler_config_helper.h" #include "srsran/du/du_cell_config_helpers.h" #include "srsran/support/test_utils.h" +#include "fmt/ostream.h" #include using namespace srsran; @@ -23,6 +24,7 @@ struct pucch_gen_params { unsigned nof_res_f0; unsigned nof_res_f1; unsigned nof_res_f2; + unsigned nof_res_f3; bounded_integer f0_nof_symbols{2}; bool f0_intraslot_freq_hopping{false}; nof_cyclic_shifts nof_cyc_shifts{nof_cyclic_shifts::no_cyclic_shift}; @@ -34,24 +36,80 @@ struct pucch_gen_params { std::optional max_payload_bits; max_pucch_code_rate max_code_rate{max_pucch_code_rate::dot_25}; bool f2_intraslot_freq_hopping{false}; + bounded_integer f3_nof_symbols{4}; + bool f3_intraslot_freq_hopping{false}; + bool f3_additional_dmrs{false}; + bool f3_pi2_bpsk{false}; }; -// Dummy function overload of template void testing::internal::PrintTo(const T& value, ::std::ostream* os). -// This prevents valgrind from complaining about uninitialized variables. -void PrintTo(const pucch_gen_params& value, ::std::ostream* os) +std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) { - return; + std::string f0_f1_str; + if (params.nof_res_f0 != 0) { + f0_f1_str = fmt::format("F0: nof_res={} nof_symbols={} freq_hop={} nof_cyc_shifts={} occ_supported={}", + params.nof_res_f0, + params.f0_nof_symbols, + params.f0_intraslot_freq_hopping, + params.nof_cyc_shifts, + params.occ_supported); + } else { + f0_f1_str = fmt::format("F1: nof_res={} nof_symbols={} freq_hop={}", + params.nof_res_f1, + params.f1_nof_symbols, + params.f1_intraslot_freq_hopping); + } + std::string f2_f3_str; + if (params.nof_res_f2 != 0) { + f2_f3_str = + fmt::format("F2: nof_res={} nof_symbols={} max_nof_rbs={} max_payload_bits={} max_code_rate={} freq_hop={}", + params.nof_res_f2, + params.f2_nof_symbols, + params.max_nof_rbs, + params.max_payload_bits, + params.max_code_rate, + params.f2_intraslot_freq_hopping); + } else { + f2_f3_str = fmt::format("F3: nof_res={} nof_symbols={} max_nof_rbs={} max_payload_bits={} max_code_rate={} " + "freq_hop={} add_dmrs={} pi2_bpsk={}", + params.nof_res_f3, + params.f3_nof_symbols, + params.max_nof_rbs, + params.max_payload_bits, + params.max_code_rate, + params.f3_intraslot_freq_hopping, + params.f3_additional_dmrs, + params.f3_pi2_bpsk); + } + fmt::print(os, "{} {}", f0_f1_str, f2_f3_str); + + return os; } struct pucch_cfg_builder_params { unsigned nof_res_f0_harq = 0; unsigned nof_res_f1_harq = 3; unsigned nof_res_f2_harq = 6; + unsigned nof_res_f3_harq = 6; unsigned nof_harq_cfg = 1; unsigned nof_res_sr = 2; unsigned nof_res_csi = 1; }; +std::ostream& operator<<(std::ostream& os, const pucch_cfg_builder_params& params) +{ + fmt::print(os, + "f0_harq={} f1_harq={} f2_harq={} f3_harq={} nof_harq_cfg={} nof_sr={} nof_csi={}", + params.nof_res_f0_harq, + params.nof_res_f1_harq, + params.nof_res_f2_harq, + params.nof_res_f3_harq, + params.nof_harq_cfg, + params.nof_res_sr, + params.nof_res_csi); + + return os; +} + } // namespace du_pucch_gen using namespace du_pucch_gen; @@ -281,15 +339,16 @@ class pucch_grid } } } - } else if (res.format == srsran::pucch_format::FORMAT_2) { + } else if (res.format == pucch_format::FORMAT_2 or res.format == pucch_format::FORMAT_3) { srsran_assert(std::holds_alternative(res.format_params), "Expected PUCCH Format 2"); - const auto& res_f2 = std::get(res.format_params); + const auto& res_f2_f3 = std::get(res.format_params); // Intra-slot frequency hopping. if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2.starting_sym_idx; sym_idx < res_f2.starting_sym_idx + res_f2.nof_symbols / 2; + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2_f3.nof_prbs; ++rb_idx) { + for (unsigned sym_idx = res_f2_f3.starting_sym_idx; + sym_idx < res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols / 2; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -298,10 +357,10 @@ class pucch_grid } } // Second hop. - for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + res_f2.nof_prbs; + for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + res_f2_f3.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2.starting_sym_idx + res_f2.nof_symbols / 2; - sym_idx < res_f2.starting_sym_idx + res_f2.nof_symbols; + for (unsigned sym_idx = res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols / 2; + sym_idx < res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -312,8 +371,9 @@ class pucch_grid } // No intra-slot frequency hopping. else { - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2.starting_sym_idx; sym_idx < res_f2.starting_sym_idx + res_f2.nof_symbols; + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2_f3.nof_prbs; ++rb_idx) { + for (unsigned sym_idx = res_f2_f3.starting_sym_idx; + sym_idx < res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -376,6 +436,7 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) const unsigned nof_res_f0 = GetParam().nof_res_f0; const unsigned nof_res_f1 = GetParam().nof_res_f1; const unsigned nof_res_f2 = GetParam().nof_res_f2; + const unsigned nof_res_f3 = GetParam().nof_res_f3; ASSERT_FALSE(nof_res_f0 != 0 and nof_res_f1 != 0) << "PUCCH Format 0 and Format 1 resources cannot be used together"; @@ -393,22 +454,40 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) .max_code_rate = GetParam().max_code_rate, .intraslot_freq_hopping = GetParam().f2_intraslot_freq_hopping}; - std::vector res_list; + pucch_f3_params params_f3{.nof_symbols = GetParam().f3_nof_symbols, + .max_nof_rbs = GetParam().max_nof_rbs, + .max_payload_bits = GetParam().max_payload_bits, + .max_code_rate = GetParam().max_code_rate, + .intraslot_freq_hopping = GetParam().f3_intraslot_freq_hopping, + .additional_dmrs = GetParam().f3_additional_dmrs, + .pi2_bpsk = GetParam().f3_pi2_bpsk}; + + std::variant f0_f1_params; + unsigned nof_res_f0_f1; if (nof_res_f0 != 0) { - res_list = generate_cell_pucch_res_list( - nof_res_f0, nof_res_f2, params_f0, params_f2, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + f0_f1_params.emplace(params_f0); + nof_res_f0_f1 = nof_res_f0; } else { - res_list = generate_cell_pucch_res_list( - nof_res_f1, nof_res_f2, params_f1, params_f2, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + f0_f1_params.emplace(params_f1); + nof_res_f0_f1 = nof_res_f1; } - ASSERT_TRUE(res_list.size() > 0); - if (nof_res_f0 != 0) { - ASSERT_EQ(nof_res_f0 + nof_res_f2, res_list.size()); + std::variant f2_f3_params; + unsigned nof_res_f2_f3; + if (nof_res_f2 != 0) { + f2_f3_params.emplace(params_f2); + nof_res_f2_f3 = nof_res_f2; } else { - ASSERT_EQ(nof_res_f1 + nof_res_f2, res_list.size()); + f2_f3_params.emplace(params_f3); + nof_res_f2_f3 = nof_res_f3; } + std::vector res_list = generate_cell_pucch_res_list( + nof_res_f0_f1, nof_res_f2_f3, f0_f1_params, f2_f3_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + + ASSERT_TRUE(res_list.size() > 0); + ASSERT_EQ(nof_res_f0_f1 + nof_res_f2_f3, res_list.size()); + for (const auto& pucch_res : res_list) { ASSERT_FALSE(grid.verify_collision(pucch_res)); grid.add_resource(pucch_res); @@ -564,7 +643,90 @@ INSTANTIATE_TEST_SUITE_P(test_res_generation_given_number, .max_nof_rbs = 7, .max_payload_bits = 11, .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f2_intraslot_freq_hopping = true})); + .f2_intraslot_freq_hopping = true}, + // Format 3 test cases. + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f3 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f3 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f3 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f3 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 11, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 137, + .nof_res_f3 = 25, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = true, + .f1_nof_symbols = 14, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 36, + .nof_res_f3 = 27, + .nof_cyc_shifts = nof_cyclic_shifts::three, + .occ_supported = true, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 34, + .nof_res_f3 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::two, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f3 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true})); /////////////////// @@ -575,6 +737,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParamfront().serv_cell_cfg) { if (GetParam().nof_res_f0_harq != 0) { auto& pucch_res_list = serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg->pucch_res_list; for (auto& res : pucch_res_list) { - if (res.format == srsran::pucch_format::FORMAT_1) { - res.format = srsran::pucch_format::FORMAT_0; + if (res.format == pucch_format::FORMAT_1) { + res.format = pucch_format::FORMAT_0; res.format_params.emplace(); } } } + if (GetParam().nof_res_f3_harq != 0) { + auto& pucch_res_list = serv_cell_cfg.ul_config.value().init_ul_bwp.pucch_cfg->pucch_res_list; + for (auto& res : pucch_res_list) { + if (res.format == pucch_format::FORMAT_2) { + res.format = pucch_format::FORMAT_3; + } + } + } + if (GetParam().nof_res_csi == 0) { serv_cell_cfg.csi_meas_cfg.reset(); } @@ -622,36 +800,38 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam 0; const unsigned nof_f0_f1_res_harq_per_ue = has_f0_res ? nof_f0_res_harq_per_ue : nof_f1_res_harq_per_ue; + const bool has_f2_res = nof_f2_res_harq_per_ue > 0; + const unsigned nof_f2_f3_res_harq_per_ue = has_f2_res ? nof_f2_res_harq_per_ue : nof_f3_res_harq_per_ue; bool test_result = true; // Check the number of resources in the PUCCH resource list is correct. - if (has_f0_res) { + if (has_f0_res and has_f2_res) { // For Format 0, the pucch_res_list contains 2 extra resources, 1 per PUCCH resource set. const unsigned extra_resources = has_csi ? 2U : 1U; - test_result = pucch_cfg.pucch_res_list.size() == nof_f0_f1_res_harq_per_ue + nof_f2_res_harq_per_ue + + test_result = pucch_cfg.pucch_res_list.size() == nof_f0_f1_res_harq_per_ue + nof_f2_f3_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue + extra_resources; } else { test_result = pucch_cfg.pucch_res_list.size() == - nof_f0_f1_res_harq_per_ue + nof_f2_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue; + nof_f0_f1_res_harq_per_ue + nof_f2_f3_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue; } // Check the number of PUCCH F1 resources in the PUCCH resource sets is correct. - if (has_f0_res) { + if (has_f0_res and has_f2_res) { // For Format 0, each PUCCH resource set contains extra resources. If CSI is enabled, then each PUCCH resource set // contains 1 (new) PUCCH resource that is added to the pucch_res_list plus 1 that maps to the SR (in set 0) or // CSI (in set 1). If CSI is not enabled, 1 PUCCH then each PUCCH resource set contains 1 PUCCH resource only. const unsigned extra_res_per_set = has_csi ? 2U : 1U; test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == nof_f0_f1_res_harq_per_ue + extra_res_per_set; - test_result = test_result && - pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_res_harq_per_ue + extra_res_per_set; + test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == + nof_f2_f3_res_harq_per_ue + extra_res_per_set; } else { test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == nof_f0_f1_res_harq_per_ue; - test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_res_harq_per_ue; + test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_f3_res_harq_per_ue; } - // Helper to retrive a given PUCCH resource given its ID from the PUCCH resource list. + // Helper to retrieve a given PUCCH resource given its ID from the PUCCH resource list. auto get_pucch_resource_with_id = [&pucch_cfg](pucch_res_id_t res_id) { return std::find_if(pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), @@ -693,18 +873,20 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam= nof_f0_f1_res_harq_per_ue * harq_cfg_idx and res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * (harq_cfg_idx + 1); - // The PUCCH resource ID for the ASN1 message for PUCCH + // The PUCCH resource ID for the ASN1 message for PUCCH. // F1 resources is expected to be from 0 to nof_f0_f1_res_harq_per_ue for all UEs. const bool pucch_ue_res_id_test = res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue; const bool pucch_ue_cell_res_id_test = @@ -793,18 +975,18 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * harq_cfg_idx and + nof_f2_f3_res_harq_per_ue * harq_cfg_idx and res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * (harq_cfg_idx + 1); + nof_f2_f3_res_harq_per_ue * (harq_cfg_idx + 1); // The PUCCH resource ID for the ASN1 message for PUCCH // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + // nof_f2_res_harq_per_ue) for all UEs. const bool pucch_ue_res_id_test = res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1 and - res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_res_harq_per_ue; + res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_f3_res_harq_per_ue; // Check if the PUCCH cell resourece ID is set correspondingly to the PUCCH UE resource ID. const bool pucch_ue_cell_res_id_test = res_idx.cell_res_id - (nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_res_harq_per_ue * harq_cfg_idx) == + nof_f2_f3_res_harq_per_ue * harq_cfg_idx) == res_idx.ue_res_id - (nof_f0_f1_res_harq_per_ue + 1); test_result = test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and pucch_ue_cell_res_id_test and @@ -813,24 +995,19 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam(sr_pucch_res_cfg.format_params), "SR PUCCH resource must be of Format 0 if any of the PUCCH resources from set 0 has Format 0."); @@ -886,10 +1063,11 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam res_list; ASSERT_FALSE(nof_f0_res_harq_per_ue != 0 and nof_f1_res_harq_per_ue != 0) << "PUCCH Format 0 and Format 1 resources cannot be used together"; + ASSERT_FALSE(nof_f2_res_harq_per_ue != 0 and nof_f3_res_harq_per_ue != 0) + << "PUCCH Format 2 and Format 3 resources cannot be used together"; + + ASSERT_FALSE(nof_f0_res_harq_per_ue != 0 and nof_f3_res_harq_per_ue != 0) + << "PUCCH Format 0 and Format 3 resources cannot be used together"; + + unsigned nof_res_f0_f1; + unsigned nof_ue_pucch_f0_f1_res_harq; + std::variant f0_f1_params; if (nof_f0_res_harq_per_ue != 0) { - res_list = generate_cell_pucch_res_list( - nof_f0_res, nof_f2_res, f0_params, f2_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + nof_res_f0_f1 = nof_f0_res; + nof_ue_pucch_f0_f1_res_harq = nof_f0_res_harq_per_ue; + f0_f1_params.emplace(f0_params); + } else { + nof_res_f0_f1 = nof_f1_res; + nof_ue_pucch_f0_f1_res_harq = nof_f1_res_harq_per_ue; + f0_f1_params.emplace(f1_params); + } + + unsigned nof_res_f2_f3; + unsigned nof_ue_pucch_f2_f3_res_harq; + std::variant f2_f3_params; + if (nof_f2_res_harq_per_ue != 0) { + nof_res_f2_f3 = nof_f2_res; + nof_ue_pucch_f2_f3_res_harq = nof_f2_res_harq_per_ue; + f2_f3_params.emplace(f2_params); } else { - res_list = generate_cell_pucch_res_list( - nof_f1_res, nof_f2_res, f1_params, f2_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + nof_res_f2_f3 = nof_f3_res; + nof_ue_pucch_f2_f3_res_harq = nof_f3_res_harq_per_ue; + f2_f3_params.emplace(f3_params); } + res_list = generate_cell_pucch_res_list( + nof_res_f0_f1, nof_res_f2_f3, f0_f1_params, f2_f3_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + const auto harq_idx_cfg = test_rgen::uniform_int(0, nof_harq_cfg_per_ue - 1); const auto sr_idx_cfg = test_rgen::uniform_int(0, nof_sr_res_per_cell - 1); const auto csi_idx_cfg = test_rgen::uniform_int(0, nof_csi_res_per_cell - 1); @@ -929,8 +1136,8 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) harq_idx_cfg, sr_idx_cfg, csi_idx_cfg, - nof_f0_res_harq_per_ue != 0 ? nof_f0_res_harq_per_ue : nof_f1_res_harq_per_ue, - nof_f2_res_harq_per_ue, + nof_ue_pucch_f0_f1_res_harq, + nof_ue_pucch_f2_f3_res_harq, nof_harq_cfg_per_ue, nof_sr_res_per_cell, nof_csi_res_per_cell); @@ -941,32 +1148,42 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) INSTANTIATE_TEST_SUITE_P(ue_pucch_config_builder, test_ue_pucch_config_builder, // clang-format off - // nof: f0 | f1 | f2 | harq | sr | csi - // nof: f0 | f1 | f2 | cfg | sr | csi + // nof: f0 | f1 | f2 | f3 | harq | sr | csi + // nof: f0 | f1 | f2 | f3 | cfg | sr | csi ::testing::Values( - pucch_cfg_builder_params{ 0, 3, 6, 1, 2, 1 }, - pucch_cfg_builder_params{ 0, 7, 3, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 8, 8, 1, 4, 1 }, - pucch_cfg_builder_params{ 0, 1, 1, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 7, 7, 1, 3, 1 }, - pucch_cfg_builder_params{ 0, 8, 8, 4, 4, 4 }, - pucch_cfg_builder_params{ 0, 5, 2, 8, 2, 7 }, - pucch_cfg_builder_params{ 0, 2, 7, 3, 7, 3 }, - pucch_cfg_builder_params{ 0, 6, 4, 5, 6, 2 }, - pucch_cfg_builder_params{ 6, 0, 6, 1, 8, 8 }, - pucch_cfg_builder_params{ 5, 0, 3, 1, 1, 1 }, - pucch_cfg_builder_params{ 6, 0, 6, 1, 4, 1 }, - pucch_cfg_builder_params{ 2, 0, 2, 1, 1, 1 }, - pucch_cfg_builder_params{ 3, 0, 5, 1, 3, 1 }, - pucch_cfg_builder_params{ 3, 0, 5, 1, 1, 3 }, - pucch_cfg_builder_params{ 6, 0, 6, 4, 4, 4 }, - pucch_cfg_builder_params{ 5, 0, 2, 10, 2, 7 }, - pucch_cfg_builder_params{ 2, 0, 5, 10, 2, 7 }, - pucch_cfg_builder_params{ 2, 0, 5, 10, 7, 2 }, - pucch_cfg_builder_params{ 4, 0, 4, 10, 21, 14 }, - pucch_cfg_builder_params{ 2, 0, 6, 3, 7, 3 }, - pucch_cfg_builder_params{ 6, 0, 4, 5, 6, 2 }, - pucch_cfg_builder_params{ 6, 0, 6, 3, 6, 0 } + pucch_cfg_builder_params{ 0, 3, 6, 0, 1, 2, 1 }, + pucch_cfg_builder_params{ 0, 7, 3, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 8, 8, 0, 1, 4, 1 }, + pucch_cfg_builder_params{ 0, 1, 1, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 7, 7, 0, 1, 3, 1 }, + pucch_cfg_builder_params{ 0, 8, 8, 0, 4, 4, 4 }, + pucch_cfg_builder_params{ 0, 5, 2, 0, 8, 2, 7 }, + pucch_cfg_builder_params{ 0, 2, 7, 0, 3, 7, 3 }, + pucch_cfg_builder_params{ 0, 6, 4, 0, 5, 6, 2 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 1, 8, 8 }, + pucch_cfg_builder_params{ 5, 0, 3, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 1, 4, 1 }, + pucch_cfg_builder_params{ 2, 0, 2, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 3, 0, 5, 0, 1, 3, 1 }, + pucch_cfg_builder_params{ 3, 0, 5, 0, 1, 1, 3 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 4, 4, 4 }, + pucch_cfg_builder_params{ 5, 0, 2, 0, 10, 2, 7 }, + pucch_cfg_builder_params{ 2, 0, 5, 0, 10, 2, 7 }, + pucch_cfg_builder_params{ 2, 0, 5, 0, 10, 7, 2 }, + pucch_cfg_builder_params{ 4, 0, 4, 0, 10, 21, 14 }, + pucch_cfg_builder_params{ 2, 0, 6, 0, 3, 7, 3 }, + pucch_cfg_builder_params{ 6, 0, 4, 0, 5, 6, 2 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 3, 6, 0 }, + // Format 3 test cases. + pucch_cfg_builder_params{ 0, 3, 0, 6, 1, 2, 1 }, + pucch_cfg_builder_params{ 0, 7, 0, 3, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 8, 0, 8, 1, 4, 1 }, + pucch_cfg_builder_params{ 0, 1, 0, 1, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 7, 0, 7, 1, 3, 1 }, + pucch_cfg_builder_params{ 0, 8, 0, 8, 4, 4, 4 }, + pucch_cfg_builder_params{ 0, 5, 0, 2, 8, 2, 7 }, + pucch_cfg_builder_params{ 0, 2, 0, 7, 3, 7, 3 }, + pucch_cfg_builder_params{ 0, 6, 0, 4, 5, 6, 2 } ) // clang-format on ); diff --git a/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp b/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp index 3d4f27d3a5..b2236ee3a8 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp +++ b/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp @@ -683,7 +683,7 @@ pucch_info_test_helper srsran::unittests::build_valid_pucch_format_3_pdu() pucch.format_3.harq_ack_nof_bits = 100; pucch.format_3.sr_bits = sr_nof_bits::one; pucch.format_3.n_id_0_scrambling = 256; - pucch.format_3.n_id_scambling = 382; + pucch.format_3.n_id_scrambling = 382; pucch.format_3.n_id_hopping = 180; pucch.format_3.additional_dmrs = false; pucch.format_3.pi_2_bpsk = true; diff --git a/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp b/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp index db5b58e52e..39a50fdb9e 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp +++ b/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp @@ -119,7 +119,7 @@ TEST(mac_fapi_ul_pucch_format3_pdu_conversor_test, ul_pucch_format3_pdu_valid_sh const pucch_format_3& f3 = mac_pdu.format_3; ASSERT_EQ(static_cast(f3.max_code_rate), fapi_pdu.pucch_maintenance_v3.max_code_rate); ASSERT_EQ(f3.n_id_0_scrambling, fapi_pdu.nid0_pucch_dmrs_scrambling); - ASSERT_EQ(f3.n_id_scambling, fapi_pdu.nid_pucch_scrambling); + ASSERT_EQ(f3.n_id_scrambling, fapi_pdu.nid_pucch_scrambling); ASSERT_EQ(f3.n_id_hopping, fapi_pdu.nid_pucch_hopping); ASSERT_EQ(static_cast(f3.sr_bits), fapi_pdu.sr_bit_len); ASSERT_EQ(f3.harq_ack_nof_bits, fapi_pdu.bit_len_harq); diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index e2d65b759c..8284c48690 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -119,7 +119,7 @@ class scheduler_impl_tester bench->sched_res = &bench->sch.slot_indication(current_slot, to_du_cell_index(0)); srs_du::pucch_builder_params pucch_basic_params{.nof_ue_pucch_f0_or_f1_res_harq = 8, - .nof_ue_pucch_f2_res_harq = 8, + .nof_ue_pucch_f2_or_f3_res_harq = 8, .nof_sr_resources = 8, .nof_csi_resources = 8}; auto& f1_params = pucch_basic_params.f0_or_f1_params.emplace(); diff --git a/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp b/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp index ad8cfc1e78..945eb38764 100644 --- a/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp +++ b/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp @@ -86,7 +86,7 @@ TEST_P(sched_pucch_res_builder_tester, when_ues_are_added_their_cfg_have_differe // Each UE should have 2 PUCCH resource sets configured ASSERT_EQ(ue_pucch_cfg.pucch_res_set.size(), 2); ASSERT_EQ(ue_pucch_cfg.pucch_res_set[0].pucch_res_id_list.size(), pucch_params.nof_ue_pucch_f0_or_f1_res_harq); - ASSERT_EQ(ue_pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), pucch_params.nof_ue_pucch_f2_res_harq); + ASSERT_EQ(ue_pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), pucch_params.nof_ue_pucch_f2_or_f3_res_harq); // Make sure UE has all PUCCH resources with different cell_res_id. { std::set pucch_res_idxs; diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 5a2241b246..f086113ebe 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -205,7 +205,7 @@ test_bench::test_bench(const test_bench_params& params, if (use_format_0) { srs_du::pucch_builder_params pucch_params{}; pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6; - pucch_params.nof_ue_pucch_f2_res_harq = 6; + pucch_params.nof_ue_pucch_f2_or_f3_res_harq = 6; pucch_params.f0_or_f1_params.emplace(); pucch_builder.setup( cell_cfg.ul_cfg_common.init_ul_bwp, params.is_tdd ? cell_cfg.tdd_cfg_common : std::nullopt, pucch_params); From f487187930ea8ea676a9d3373b7c43147026f726 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 3 Dec 2024 17:49:53 +0100 Subject: [PATCH 049/227] mac: review pucch f3 in pucch_resource_generator --- .../o_du_high/du_high/du_high_config.h | 10 +- .../du_high/du_high_config_cli11_schema.cpp | 6 +- .../du_high/du_high_config_translators.cpp | 21 ++-- .../du_high/du_high_config_validator.cpp | 95 ++++++++++++------ include/srsran/du/du_cell_config.h | 2 +- include/srsran/ran/pucch/pucch_info.h | 98 ++++++++++--------- .../pucch_resource_generator.cpp | 21 ++-- .../pucch_resource_generator_test.cpp | 39 ++++---- 8 files changed, 173 insertions(+), 119 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 9fac09b1b3..32aafa3b30 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -260,7 +260,7 @@ struct du_high_unit_pucch_config { /// \c PUCCH-Config parameters. /// Force Format 0 for the PUCCH resources belonging to PUCCH resource set 0. bool use_format_0 = false; - /// Select the format for the PUCCH resources belonging to PUCCH resource set 1 {2, 3, 4}. + /// Select the format for the PUCCH resources belonging to PUCCH resource set 1. Values: {2, 3, 4}. unsigned set1_format = 2; /// Number of PUCCH resources per UE (per PUCCH resource set) for HARQ-ACK reporting. /// Values {3,...,8} if \c use_format_0 is set. Else, Values {1,...,8}. @@ -305,8 +305,8 @@ struct du_high_unit_pucch_config { /// @{ /// Max number of PRBs for PUCCH Format 2. Values {1,...,16}. unsigned f2_max_nof_rbs = 1; - /// \brief Maximum payload in bits that can be carried by PUCCH Format 2. Values {-1,...,11}. - /// Value -1 to unset. If this is set, \ref f2_max_nof_rbs is ignored. + /// \brief Maximum payload in bits that can be carried by PUCCH Format 2. Values {1,...,11}. + /// If this is set, \ref f2_max_nof_rbs is ignored. std::optional f2_max_payload_bits; /// Max code rate for PUCCH Format 2. max_pucch_code_rate f2_max_code_rate = max_pucch_code_rate::dot_35; @@ -320,8 +320,8 @@ struct du_high_unit_pucch_config { /// @{ /// Max number of PRBs for PUCCH Format 3. Values {1,...,16}. unsigned f3_max_nof_rbs = 1; - /// \brief Maximum payload in bits that can be carried by PUCCH Format 3. Values {-1,...,11}. - /// Value -1 to unset. If this is set, \ref f2_max_nof_rbs is ignored. + /// \brief Maximum payload in bits that can be carried by PUCCH Format 3. Values {1,...,11}. + /// If this is set, \ref f2_max_nof_rbs is ignored. std::optional f3_max_payload_bits; /// Max code rate for PUCCH Format 3. max_pucch_code_rate f3_max_code_rate = max_pucch_code_rate::dot_35; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 8af39271fb..030ee51b0c 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -853,9 +853,9 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option(app, "--use_format_0", pucch_params.use_format_0, "Use Format 0 for PUCCH resources from resource set 0") ->capture_default_str(); add_option(app, - "--set1_format", + "--pucch_set1_format", pucch_params.set1_format, - "Format to use for the resources from resource set 1 {2, 3, 4}. Default: 2") + "Format to use for the resources from resource set 1. Values: {2, 3, 4}. Default: 2") ->capture_default_str() ->check(CLI::Range(2, 4)); add_option(app, @@ -935,7 +935,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& ->capture_default_str(); add_option(app, "--f3_max_nof_rbs", pucch_params.f3_max_nof_rbs, "Max number of RBs for PUCCH F3 resources") ->capture_default_str() - ->check(CLI::Range(1, 16)); + ->check(CLI::IsMember({1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16})); add_option( app, "--f3_max_payload", pucch_params.f3_max_payload_bits, "Max number payload bits for PUCCH F3 resources") ->check(CLI::Range(1, 11)); diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index 0c73f2396b..fab0696daa 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -536,7 +536,7 @@ std::vector srsran::generate_du_cell_config(const du_hig du_pucch_cfg.nof_sr_resources = user_pucch_cfg.nof_cell_sr_resources; du_pucch_cfg.nof_csi_resources = param.csi_rs_enabled ? user_pucch_cfg.nof_cell_csi_resources : 0U; - if (user_pucch_cfg.use_format_0) { + if (user_pucch_cfg.use_format_0 and user_pucch_cfg.set1_format == 2) { auto& f0_params = du_pucch_cfg.f0_or_f1_params.emplace(); // Subtract 2 PUCCH resources from value: with Format 0, 2 extra resources will be added by the DU resource // allocator when the DU create the UE configuration. @@ -559,8 +559,7 @@ std::vector srsran::generate_du_cell_config(const du_hig f2_params.max_nof_rbs = user_pucch_cfg.f2_max_nof_rbs; f2_params.intraslot_freq_hopping = user_pucch_cfg.f2_intraslot_freq_hopping; f2_params.max_payload_bits = user_pucch_cfg.f2_max_payload_bits; - break; - } + } break; case 3: { auto& f3_params = du_pucch_cfg.f2_or_f3_params.emplace(); f3_params.max_code_rate = user_pucch_cfg.f3_max_code_rate; @@ -569,8 +568,7 @@ std::vector srsran::generate_du_cell_config(const du_hig f3_params.max_payload_bits = user_pucch_cfg.f3_max_payload_bits; f3_params.additional_dmrs = user_pucch_cfg.f3_additional_dmrs; f3_params.pi2_bpsk = user_pucch_cfg.f3_pi2_bpsk; - break; - } + } break; default: break; } @@ -683,10 +681,15 @@ std::vector srsran::generate_du_cell_config(const du_hig // the configuration; therefore, the maximum number of symbols for PUCCH resources is computed only for periodic // SRS. du_pucch_cfg.max_nof_symbols = config_helpers::compute_max_nof_pucch_symbols(du_srs_cfg); - if (user_srs_cfg.srs_period_ms.has_value() and - std::holds_alternative(du_pucch_cfg.f0_or_f1_params)) { - auto& f1_params = std::get(du_pucch_cfg.f0_or_f1_params); - f1_params.nof_symbols = std::min(du_pucch_cfg.max_nof_symbols.to_uint(), f1_params.nof_symbols.to_uint()); + if (user_srs_cfg.srs_period_ms.has_value()) { + if (std::holds_alternative(du_pucch_cfg.f0_or_f1_params)) { + auto& f1_params = std::get(du_pucch_cfg.f0_or_f1_params); + f1_params.nof_symbols = std::min(du_pucch_cfg.max_nof_symbols.to_uint(), f1_params.nof_symbols.to_uint()); + } + if (std::holds_alternative(du_pucch_cfg.f2_or_f3_params)) { + auto& f3_params = std::get(du_pucch_cfg.f2_or_f3_params); + f3_params.nof_symbols = std::min(du_pucch_cfg.max_nof_symbols.to_uint(), f3_params.nof_symbols.to_uint()); + } } if (update_msg1_frequency_start) { rach_cfg.rach_cfg_generic.msg1_frequency_start = config_helpers::compute_prach_frequency_start( diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index 29caad4cba..7632002a4b 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -399,13 +399,13 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& const du_high_unit_pucch_config& pucch_cfg = config.pucch_cfg; if (not config.csi_cfg.csi_rs_enabled and pucch_cfg.nof_cell_csi_resources > 0) { fmt::print( - "Number of PUCCH Format 2 cell resources for CSI must be zero when CSI-RS and CSI report are disabled.\n"); + "Number of PUCCH Format 2/3 cell resources for CSI must be zero when CSI-RS and CSI report are disabled.\n"); return false; } if (config.csi_cfg.csi_rs_enabled and pucch_cfg.nof_cell_csi_resources == 0) { - fmt::print("Number of PUCCH Format 2 cell resources for CSI must be greater than 0 when CSI-RS and CSI report are " - "enabled.\n"); + fmt::print("Number of PUCCH Format 2/3 cell resources for CSI must be greater than 0 when CSI-RS and CSI report " + "are enabled.\n"); return false; } @@ -437,7 +437,7 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& } // We need to count pucch_cfg.nof_ue_pucch_res_harq_per_set twice, as we have 2 sets of PUCCH resources for HARQ-ACK - // (PUCCH Resource Set Id 0 with Format 0/1 and PUCCH Resource Set Id 1 with Format 2). + // (PUCCH Resource Set Id 0 with Format 0/1 and PUCCH Resource Set Id 1 with Format 2/3). if (pucch_cfg.nof_ue_pucch_res_harq_per_set * 2U * pucch_cfg.nof_cell_harq_pucch_sets + pucch_cfg.nof_cell_sr_resources + pucch_cfg.nof_cell_csi_resources > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { @@ -463,7 +463,7 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& pucch_cfg.nof_cell_sr_resources) / static_cast(nof_f0_per_block))); // With intraslot_freq_hopping, the nof of RBs is an even number. - if (config.pucch_cfg.f0_intraslot_freq_hopping) { + if (pucch_cfg.f0_intraslot_freq_hopping) { nof_f0_f1_rbs = static_cast(std::ceil(static_cast(nof_f0_f1_rbs) / 2.0F)) * 2; } } else { @@ -471,47 +471,78 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& // symbols available for PUCCH within a slot. const unsigned pucch_f1_nof_symbols = max_nof_pucch_symbols; const unsigned nof_occ_codes = - config.pucch_cfg.f1_enable_occ ? format1_symb_to_spreading_factor(pucch_f1_nof_symbols) : 1U; + pucch_cfg.f1_enable_occ ? format1_symb_to_spreading_factor(pucch_f1_nof_symbols) : 1U; // We define a block as a set of Resources (either F0/F1 or F2) aligned over the same starting PRB. - const unsigned nof_f1_per_block = nof_occ_codes * config.pucch_cfg.f1_nof_cyclic_shifts; + const unsigned nof_f1_per_block = nof_occ_codes * pucch_cfg.f1_nof_cyclic_shifts; // Each PUCCH resource F0/F1 occupies 1 RB (per block). - nof_f0_f1_rbs = static_cast(std::ceil( - static_cast(config.pucch_cfg.nof_ue_pucch_res_harq_per_set * pucch_cfg.nof_cell_harq_pucch_sets + - pucch_cfg.nof_cell_sr_resources) / - static_cast(nof_f1_per_block))); + nof_f0_f1_rbs = static_cast( + std::ceil(static_cast(pucch_cfg.nof_ue_pucch_res_harq_per_set * pucch_cfg.nof_cell_harq_pucch_sets + + pucch_cfg.nof_cell_sr_resources) / + static_cast(nof_f1_per_block))); // With intraslot_freq_hopping, the nof of RBs is an even number. - if (config.pucch_cfg.f1_intraslot_freq_hopping) { + if (pucch_cfg.f1_intraslot_freq_hopping) { nof_f0_f1_rbs = static_cast(std::ceil(static_cast(nof_f0_f1_rbs) / 2.0F)) * 2; } } - // The number of symbols per PUCCH resource F2 is not exposed to the DU user interface and set by default to 2. - constexpr unsigned pucch_f2_nof_symbols = 2U; - const unsigned f2_max_rbs = - config.pucch_cfg.f2_max_payload_bits.has_value() - ? get_pucch_format2_max_nof_prbs(config.pucch_cfg.f2_max_payload_bits.value(), - pucch_f2_nof_symbols, - to_max_code_rate_float(config.pucch_cfg.f2_max_code_rate)) - : config.pucch_cfg.f2_max_nof_rbs; - - const unsigned nof_f2_blocks = max_nof_pucch_symbols / pucch_f2_nof_symbols; - unsigned nof_f2_rbs = - static_cast(std::ceil( - static_cast(config.pucch_cfg.nof_ue_pucch_res_harq_per_set * pucch_cfg.nof_cell_harq_pucch_sets + - pucch_cfg.nof_cell_csi_resources) / - static_cast(nof_f2_blocks))) * - f2_max_rbs; - // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. - if (config.pucch_cfg.f2_intraslot_freq_hopping) { - nof_f2_rbs = static_cast(std::ceil(static_cast(nof_f2_rbs) / 2.0F)) * 2; + unsigned nof_f2_f3_f4_rbs; + const unsigned nof_res_f2_f3_f4 = + pucch_cfg.nof_ue_pucch_res_harq_per_set * pucch_cfg.nof_cell_harq_pucch_sets + pucch_cfg.nof_cell_csi_resources; + switch (pucch_cfg.set1_format) { + case 2: { + // The number of symbols per PUCCH resource F2 is not exposed to the DU user interface and set by default to 2. + constexpr unsigned pucch_f2_nof_symbols = 2U; + const unsigned f2_max_rbs = + pucch_cfg.f2_max_payload_bits.has_value() + ? get_pucch_format2_max_nof_prbs(pucch_cfg.f2_max_payload_bits.value(), + pucch_f2_nof_symbols, + to_max_code_rate_float(pucch_cfg.f2_max_code_rate)) + : pucch_cfg.f2_max_nof_rbs; + + const unsigned nof_f2_blocks = max_nof_pucch_symbols / pucch_f2_nof_symbols; + nof_f2_f3_f4_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f2_blocks))) * + f2_max_rbs; + // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. + if (pucch_cfg.f2_intraslot_freq_hopping) { + nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; + } + } break; + case 3: { + // The number of symbols per PUCCH resource is not exposed to the DU user interface; for PUCCH F3, we use all + // symbols available for PUCCH within a slot. + const unsigned pucch_f3_nof_symbols = max_nof_pucch_symbols; + const unsigned f3_max_rbs = + pucch_cfg.f3_max_payload_bits.has_value() + ? get_pucch_format3_max_nof_prbs(pucch_cfg.f3_max_payload_bits.value(), + pucch_f3_nof_symbols, + to_max_code_rate_float(pucch_cfg.f3_max_code_rate), + // Since we are forcing 14 symbols intraslot_freq_hopping doesn't matter. + false, + pucch_cfg.f3_additional_dmrs, + pucch_cfg.f3_pi2_bpsk) + : pucch_cfg.f3_max_nof_rbs; + + const unsigned nof_f3_blocks = max_nof_pucch_symbols / pucch_f3_nof_symbols; + nof_f2_f3_f4_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f3_blocks))) * + f3_max_rbs; + // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. + if (pucch_cfg.f3_intraslot_freq_hopping) { + nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; + } + } break; + default: + fmt::print("Invalid PUCCH format for Set Id 1.\n"); + return false; } // Verify the number of RBs for the PUCCH resources does not exceed the BWP size. // [Implementation-defined] We do not allow the PUCCH resources to occupy more than 50% of the BWP. This is an extreme // case, and ideally the PUCCH configuration should result in a much lower PRBs usage. constexpr float max_allowed_prbs_usage = 0.5F; - if (static_cast(nof_f0_f1_rbs + nof_f2_rbs) / static_cast(nof_crbs) >= max_allowed_prbs_usage) { + if (static_cast(nof_f0_f1_rbs + nof_f2_f3_f4_rbs) / static_cast(nof_crbs) >= max_allowed_prbs_usage) { fmt::print("With the given parameters, the number of PRBs for PUCCH exceeds the 50% of the BWP PRBs.\n"); return false; } diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index a1c57af1a2..594e468679 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -69,7 +69,7 @@ struct pucch_f2_params { /// Collects the parameters for PUCCH Format 3 that can be configured. struct pucch_f3_params { - bounded_integer nof_symbols{14}; + bounded_integer nof_symbols{4}; unsigned max_nof_rbs{1}; /// Maximum payload in bits that can be carried by PUCCH Format 3. When this field is set, \c max_nof_rbs is ignored /// and the maximum number of RBs is computed according to \ref get_pucch_format3_max_nof_prbs. diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index 1d7b662695..ec440ceb15 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/adt/bounded_integer.h" +#include "srsran/adt/to_array.h" #include "srsran/phy/constants.h" #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/ran/resource_block.h" @@ -19,26 +20,26 @@ namespace srsran { -/// \brief Calculates the total rate matching output sequence length \f$E_{UCI}\f$, as per TS38.212 Table 6.3.1.4-1. +/// \brief Calculates the total rate matching output sequence length \f$E_{UCI}\f$, as per TS 38.212 Table 6.3.1.4-1. inline unsigned get_pucch_format2_E_total(unsigned nof_prb, unsigned nof_symbols) { return 16U * nof_symbols * nof_prb; } -/// \brief Calculates the total rate matching output sequence length \f$E_{UCI}\f$, as per TS38.212 Table 6.3.1.4-1. +/// \brief Calculates the total rate matching output sequence length \f$E_{UCI}\f$, as per TS 38.212 Table 6.3.1.4-1. inline unsigned get_pucch_format3_E_total(unsigned nof_prb, unsigned nof_symbols, bool pi2_bpsk) { return (pi2_bpsk ? 12U : 24U) * nof_symbols * nof_prb; } -/// \brief Calculates the total rate matching output sequence length \f$E_{UCI}\f$, as per TS38.212 Table 6.3.1.4-1. +/// \brief Calculates the total rate matching output sequence length \f$E_{UCI}\f$, as per TS 38.212 Table 6.3.1.4-1. inline unsigned get_pucch_format4_E_total(unsigned spreading_factor, unsigned nof_symbols, bool pi2_bpsk) { return (pi2_bpsk ? 12U : 24U) * nof_symbols / spreading_factor; } /// \brief Calculates the effective code rate for a PUCCH Format 2 transmission, for CSI of 1 part only. -/// \param[in] nof_prb Transmission bandwidth in PRB. +/// \param[in] nof_prb Transmission bandwidth in PRBs. /// \param[in] nof_symbols Transmission duration in symbols. /// \param[in] nof_payload_bits Total number of payload bits. /// \return The effective code rate of the PUCCH Format 2 transmission. @@ -61,7 +62,7 @@ inline float pucch_format2_code_rate(unsigned nof_prb, unsigned nof_symbols, uns } /// \brief Calculates the effective code rate for a PUCCH Format 3 transmission, for CSI Part 1 only. -/// \param[in] nof_prb Transmission bandwidth in PRB. +/// \param[in] nof_prb Transmission bandwidth in PRBs. /// \param[in] nof_data_symbols Number of symbols in the resource that contain data. /// \param[in] nof_payload_bits Total number of payload bits. /// \return The effective code rate of the PUCCH Format 3 transmission. @@ -72,7 +73,7 @@ pucch_format3_code_rate(unsigned nof_prb, unsigned nof_data_symbols, bool pi2_bp // \f$E_{UCI}\f$ = \f$E_{tot}\f$. const unsigned e_uci = get_pucch_format3_E_total(nof_prb, nof_data_symbols, pi2_bpsk); - // As per TS38.212 Sections 6.3.1.2.1 and 6.3.1.4.1, the parameter \f$E\f$ used to derive the number of + // As per TS 38.212 Sections 6.3.1.2.1 and 6.3.1.4.1, the parameter \f$E\f$ used to derive the number of // code-blocks is \f$E_{UCI}\f$. const unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); @@ -92,7 +93,7 @@ pucch_format3_code_rate(unsigned nof_prb, unsigned nof_data_symbols, bool pi2_bp inline float pucch_format4_code_rate(unsigned spreading_factor, unsigned nof_data_symbols, bool pi2_bpsk, unsigned nof_payload_bits) { - // As per TS38.212 Table 6.3.1.4.1-1, for UCI of transmissions of CSI of one part only, + // As per TS 38.212 Table 6.3.1.4.1-1, for UCI of transmissions of CSI of one part only, // \f$E_{UCI}\f$ = \f$E_{tot}\f$. const unsigned e_uci = get_pucch_format4_E_total(spreading_factor, nof_data_symbols, pi2_bpsk); @@ -116,6 +117,7 @@ pucch_format4_code_rate(unsigned spreading_factor, unsigned nof_data_symbols, bo /// \return The number of PRBs required for the transmission of nof_payload_bits with PUCCH format 2. /// \remark The returned number of PRBs is not capped to the maximum value of \ref FORMAT2_MAX_NPRB; it's up to the /// caller to perform this check. +/// \remark In case nof_payload_bits or nof_symbols is set to 0, the function returns 0. inline unsigned get_pucch_format2_max_nof_prbs(unsigned nof_payload_bits, unsigned nof_symbols, float max_code_rate) { if (nof_payload_bits == 0 or nof_symbols == 0) { @@ -172,14 +174,14 @@ get_pucch_format2_nof_prbs(unsigned nof_payload_bits, unsigned max_nof_prbs, uns } /// \brief Calculates the maximum payload for a PUCCH Format 2 transmission. -/// \param[in] nof_prb Transmission bandwidth in PRB. +/// \param[in] nof_prb Transmission bandwidth in PRBs. /// \param[in] nof_symbols Transmission duration in symbols. -/// \param[in] max_code_rate Maximum allowed PUCCH Format2 code rate. +/// \param[in] max_code_rate Maximum allowed PUCCH Format 2 code rate. /// \return The maximum payload for a PUCCH Format 2 transmission. inline unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate) { const unsigned NOF_BITS_QPSK_SYMBOL = 2; - // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213; the + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.2, TS 38.213; the // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and // max_code_rate. // NOTE: The maximum number of bits that can be carried by a PUCCH Format 2 resource is 409, which is obtained for 16 @@ -215,9 +217,11 @@ inline unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned no /// \brief Calculates the number of OFDM symbols filled with DM-RS in a PUCCH Format 3/4 resource. /// \param[in] nof_symbols Transmission duration in OFDM symbols. -/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. -/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. -/// \return The number of DM-RS OFDM symbols within the PUCCH Format 3/4 transmission. +/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. Only used if +/// nof_symbols == 4. +/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. Only used if nof_symbols > 10. +/// \return The number of DM-RS OFDM symbols within the PUCCH Format 3/4 transmission, as per TS 38.211 +/// Table 6.4.1.3.3.2-1. inline unsigned get_pucch_format3_4_nof_dmrs_symbols(bounded_integer nof_symbols, bool intraslot_freq_hopping, bool additional_dmrs) @@ -238,18 +242,32 @@ inline unsigned get_pucch_format3_4_nof_dmrs_symbols(bounded_integer nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) { - if (nof_payload_bits == 0 or nof_symbols == 0) { + static constexpr auto valid_num_prbs = to_array({1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16}); + const auto round_to_valid_nof_prbs = [](unsigned& value) { + if (value > pucch_constants::FORMAT3_MAX_NPRB) { + return; + } + + // Round up to the nearest valid number of PRBs for PUCCH Format 3. + const int* it = std::lower_bound(valid_num_prbs.begin(), valid_num_prbs.end(), value); + if (it != valid_num_prbs.end()) { + value = *it; + } + }; + + if (nof_payload_bits == 0) { return 0; } @@ -258,59 +276,51 @@ inline unsigned get_pucch_format3_max_nof_prbs(unsigned nof_payload_bits, const unsigned mod_order = pi2_bpsk ? 1 : 2; // Compute the number of PRBs first without taking into account the CRC bits. - // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213. The + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.2, TS 38.213. The // ceil operation guarantees that the number of PRBs is enough to satisfy the effective code rate constraint. unsigned nof_prbs = static_cast( std::ceil(static_cast(nof_payload_bits) / - (static_cast((nof_symbols - nof_dmrs_symbols) * NRE * mod_order) * max_code_rate))); + (static_cast((nof_symbols.value() - nof_dmrs_symbols) * NRE * mod_order) * max_code_rate))); - static const std::set valid_num_prbs = {1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16}; - auto round_to_valid_nof_prbs = [](unsigned value) { - // Round up to the nearest valid number of PRBs for PUCCH Format 3. - while (valid_num_prbs.find(value) == valid_num_prbs.end()) { - value++; - } - return value; - }; + round_to_valid_nof_prbs(nof_prbs); // The resulting number of PRBs is too big for PUCCH Format 3, so just return. if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { return nof_prbs; } - // Since the number of PRBs was rounded up there's no need to check that the CRC bits actually fit into the resource. - if (unsigned rounded_nof_prbs = round_to_valid_nof_prbs(nof_prbs); rounded_nof_prbs != nof_prbs) { - return rounded_nof_prbs; - } - // Compute the total number of bits (including CRC) using the resulting PRB number. - const unsigned e_uci = get_pucch_format2_E_total(nof_prbs, nof_symbols); + unsigned e_uci = get_pucch_format3_E_total(nof_prbs, nof_symbols.value(), pi2_bpsk); // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of // code-blocks is \f$E_{UCI}\f$. unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); // Check that the number of PRBs can hold the total number of bits after rate matching. - if (static_cast(std::ceil(static_cast(payload_plus_crc_bits) / max_code_rate)) > - (nof_dmrs_symbols * NRE * nof_prbs * mod_order)) { - nof_prbs++; + while (static_cast(std::ceil(static_cast(payload_plus_crc_bits) / max_code_rate)) > + (nof_dmrs_symbols * NRE * nof_prbs * mod_order)) { + round_to_valid_nof_prbs(++nof_prbs); // The resulting number of PRBs is too big for PUCCH Format 3, so just return. if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { return nof_prbs; } - return round_to_valid_nof_prbs(nof_prbs); + // Compute the total number of bits (including CRC) using the resulting PRB number. + e_uci = get_pucch_format3_E_total(nof_prbs, nof_symbols.value(), pi2_bpsk); + // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of + // code-blocks is \f$E_{UCI}\f$. + payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); } return nof_prbs; } /// \brief Calculates the maximum payload for a PUCCH Format 3 transmission. -/// \param[in] max_nof_prbs Transmission bandwidth in PRB. +/// \param[in] max_nof_prbs Transmission bandwidth in PRBs. /// \param[in] nof_symbols Transmission duration in symbols. -/// \param[in] max_code_rate Maximum allowed PUCCH Format2 code rate. +/// \param[in] max_code_rate Maximum allowed PUCCH Format 3 code rate. /// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. /// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. -/// \param[in] pi2_bpsk Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] pi2_bpsk Flag indicating if pi/2-BPSK modulation is used. /// \return The maximum payload for a PUCCH Format 3 transmission. inline unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, diff --git a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp index 93bd72e4f1..3bf3975e45 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -96,7 +96,7 @@ static std::vector compute_f0_res(unsigned } } } - // With intraslot freq. hopping. + // Without intraslot freq. hopping. else { for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1U; ++rb_idx) { const prb_interval prbs_low_spectrum{rb_idx, rb_idx + 1U}; @@ -119,7 +119,8 @@ static std::vector compute_f0_res(unsigned // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of // the BWP. - for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= 14; sym_idx += nof_f0_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + sym_idx += nof_f0_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f0_symbols}; res_list.emplace_back( pucch_grant{.format = srsran::pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs_hi_spectrum}); @@ -310,7 +311,7 @@ static std::vector compute_f2_res(unsigned } } } - // With intraslot freq. hopping. + // Without intraslot freq. hopping. else { for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f2_max_rbs; rb_idx += f2_max_rbs) { const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f2_max_rbs}; @@ -333,7 +334,8 @@ static std::vector compute_f2_res(unsigned // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of // the BWP. - for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= 14; sym_idx += nof_f2_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + sym_idx += nof_f2_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f2_symbols}; res_list.emplace_back( pucch_grant{.format = srsran::pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs_hi_spectrum}); @@ -403,7 +405,7 @@ static std::vector compute_f3_res(unsigned } } } - // With intraslot freq. hopping. + // Without intraslot freq. hopping. else { for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f3_max_rbs; rb_idx += f3_max_rbs) { const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f3_max_rbs}; @@ -426,7 +428,8 @@ static std::vector compute_f3_res(unsigned // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of // the BWP. - for (unsigned sym_idx = 0; sym_idx + nof_f3_symbols <= 14; sym_idx += nof_f3_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f3_symbols <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + sym_idx += nof_f3_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f3_symbols}; res_list.emplace_back( pucch_grant{.format = pucch_format::FORMAT_3, .symbols = symbols, .prbs = prbs_hi_spectrum}); @@ -453,7 +456,6 @@ error_type srs_du::pucch_parameters_validator(unsigned { const bool has_f0 = std::holds_alternative(f0_f1_params); unsigned nof_f0_f1_rbs = 0; - srsran_assert(max_nof_symbols.to_uint() <= NOF_OFDM_SYM_PER_SLOT_NORMAL_CP, "Invalid number of symbols"); if (has_f0) { const auto& f0_params = std::get(f0_f1_params); @@ -524,6 +526,10 @@ error_type srs_du::pucch_parameters_validator(unsigned } } else { const auto& f3_params = std::get(f2_f3_params); + if (f3_params.nof_symbols.to_uint() > max_nof_symbols.to_uint()) { + return make_unexpected("The number of symbols for PUCCH Format 3 exceeds the maximum number of symbols available " + "for PUCCH resources"); + } const unsigned f3_max_rbs = f3_params.max_payload_bits.has_value() ? get_pucch_format3_max_nof_prbs(f3_params.max_payload_bits.value(), @@ -656,6 +662,7 @@ merge_f0_f1_f2_f3_resource_lists(const std::vector& pucch_f0_f1_res } } + // TODO: when the list is empty, we are assuming F3. const bool has_f2 = not pucch_f2_f3_resource_list.empty() ? pucch_f2_f3_resource_list[0].format == pucch_format::FORMAT_2 : false; diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index bda12b7f3e..35ab10fb58 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -42,6 +42,8 @@ struct pucch_gen_params { bool f3_pi2_bpsk{false}; }; +// Dummy function overload of template void testing::internal::PrintTo(const T& value, ::std::ostream* os). +// This prevents valgrind from complaining about uninitialized variables. std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) { std::string f0_f1_str; @@ -60,25 +62,26 @@ std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) } std::string f2_f3_str; if (params.nof_res_f2 != 0) { - f2_f3_str = - fmt::format("F2: nof_res={} nof_symbols={} max_nof_rbs={} max_payload_bits={} max_code_rate={} freq_hop={}", - params.nof_res_f2, - params.f2_nof_symbols, - params.max_nof_rbs, - params.max_payload_bits, - params.max_code_rate, - params.f2_intraslot_freq_hopping); + f2_f3_str = fmt::format( + "F2: nof_res={} nof_symbols={} max_nof_rbs={} {} max_code_rate={} freq_hop={}", + params.nof_res_f2, + params.f2_nof_symbols, + params.max_nof_rbs, + params.max_payload_bits.has_value() ? fmt::format("max_payload_bits={}", params.max_payload_bits.value()) : "", + to_max_code_rate_float(params.max_code_rate), + params.f2_intraslot_freq_hopping); } else { - f2_f3_str = fmt::format("F3: nof_res={} nof_symbols={} max_nof_rbs={} max_payload_bits={} max_code_rate={} " - "freq_hop={} add_dmrs={} pi2_bpsk={}", - params.nof_res_f3, - params.f3_nof_symbols, - params.max_nof_rbs, - params.max_payload_bits, - params.max_code_rate, - params.f3_intraslot_freq_hopping, - params.f3_additional_dmrs, - params.f3_pi2_bpsk); + f2_f3_str = fmt::format( + "F3: nof_res={} nof_symbols={} max_nof_rbs={} max_payload_bits={} max_code_rate={} " + "freq_hop={} add_dmrs={} pi2_bpsk={}", + params.nof_res_f3, + params.f3_nof_symbols, + params.max_nof_rbs, + params.max_payload_bits.has_value() ? fmt::format("max_payload_bits={}", params.max_payload_bits.value()) : "", + to_max_code_rate_float(params.max_code_rate), + params.f3_intraslot_freq_hopping, + params.f3_additional_dmrs, + params.f3_pi2_bpsk); } fmt::print(os, "{} {}", f0_f1_str, f2_f3_str); From 19276f2c35fac65426198e3307e88d9e72e4dcbe Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Thu, 5 Dec 2024 13:50:55 +0100 Subject: [PATCH 050/227] mac: refactor pucch_info.h to cpp --- include/srsran/ran/pucch/pucch_info.h | 187 +++----------------------- lib/ran/CMakeLists.txt | 1 + lib/ran/pucch/pucch_info.cpp | 184 +++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 172 deletions(-) create mode 100644 lib/ran/pucch/pucch_info.cpp diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index ec440ceb15..2a01a5219f 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -14,9 +14,7 @@ #include "srsran/adt/to_array.h" #include "srsran/phy/constants.h" #include "srsran/ran/pucch/pucch_constants.h" -#include "srsran/ran/resource_block.h" #include "srsran/ran/uci/uci_info.h" -#include namespace srsran { @@ -118,31 +116,7 @@ pucch_format4_code_rate(unsigned spreading_factor, unsigned nof_data_symbols, bo /// \remark The returned number of PRBs is not capped to the maximum value of \ref FORMAT2_MAX_NPRB; it's up to the /// caller to perform this check. /// \remark In case nof_payload_bits or nof_symbols is set to 0, the function returns 0. -inline unsigned get_pucch_format2_max_nof_prbs(unsigned nof_payload_bits, unsigned nof_symbols, float max_code_rate) -{ - if (nof_payload_bits == 0 or nof_symbols == 0) { - return 0; - } - - // We compute \ref e_uci using the max PRBs, as we don't know the actual nof PRBs (computing this is the objective of - // this function). NOTE: as per Table 6.3.1.4-1 and Table 6.3.1.4.1-1, TS 38.212, the maximum value of \f$E_{UCI}\f$ - // for PUCCH Format 2 is 512. As per Section 6.3.1.2.1, TS 38.212, any value less than 1088 is irrelevant for the CRC - // length computation, therefore using the maximum number of PRBs instead of the actual number doesn't affect the - // result. - const unsigned max_nof_pucch_f2_prbs = 16; - const unsigned e_uci = get_pucch_format2_E_total(max_nof_pucch_f2_prbs, nof_symbols); - - // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of - // code-blocks is \f$E_{UCI}\f$. - const unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); - - const unsigned NOF_BITS_QPSK_SYMBOL = 2; - // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213. The - // ceil operation guarantees that the number of PRBs is enough to satisfy the effective code rate constraint. - return static_cast(std::ceil( - static_cast(payload_plus_crc_bits) / - (static_cast(pucch_constants::FORMAT2_NOF_DATA_SC * nof_symbols * NOF_BITS_QPSK_SYMBOL) * max_code_rate))); -} +unsigned get_pucch_format2_max_nof_prbs(unsigned nof_payload_bits, unsigned nof_symbols, float max_code_rate); /// \brief Calculates the num. of PRBs (capped to the configured max nof PRBs) given the PUCCH Format 2 payload size. /// @@ -174,46 +148,11 @@ get_pucch_format2_nof_prbs(unsigned nof_payload_bits, unsigned max_nof_prbs, uns } /// \brief Calculates the maximum payload for a PUCCH Format 2 transmission. -/// \param[in] nof_prb Transmission bandwidth in PRBs. +/// \param[in] max_nof_prbs Transmission bandwidth in PRBs. /// \param[in] nof_symbols Transmission duration in symbols. /// \param[in] max_code_rate Maximum allowed PUCCH Format 2 code rate. /// \return The maximum payload for a PUCCH Format 2 transmission. -inline unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate) -{ - const unsigned NOF_BITS_QPSK_SYMBOL = 2; - // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.2, TS 38.213; the - // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and - // max_code_rate. - // NOTE: The maximum number of bits that can be carried by a PUCCH Format 2 resource is 409, which is obtained for 16 - // PRBs, 2 symbols and 0.8 max code rate. - unsigned estimated_pucch_f2_capacity = static_cast(std::floor( - static_cast(pucch_constants::FORMAT2_NOF_DATA_SC * nof_symbols * NOF_BITS_QPSK_SYMBOL * max_nof_prbs) * - max_code_rate)); - - // Get the payload depending on the estimated PUCCH F2 capacity (which we define as the nof bits that the PUCCH F2 can - // carry). - // NOTE: Given the max capacity of PUCCH, which is 409 bits (see above), the UCI in PUCCH F2 can have max 1 codeword - // (as per Section 6.3.1.2.1, TS 38.212); this implies only 6-bit and 11-bit can be added as CRC to the PUCCH F2 - // payload. - - // Case: no CRC for payload <= 11 bits. - const unsigned min_capacity_for_more_than_11_bit_payload = 18U; - const unsigned max_payload_without_crc_addition = 11U; - if (estimated_pucch_f2_capacity < min_capacity_for_more_than_11_bit_payload) { - return std::min(estimated_pucch_f2_capacity, max_payload_without_crc_addition); - } - // Case: 6-bit CRC for 12 <= payload <= 19 bits. - const unsigned min_capacity_for_more_than_19_bit_payload = 31U; - const unsigned max_payload_with_6_bit_crc_addition = 19U; - const unsigned short_crc_length = 6U; - if (estimated_pucch_f2_capacity < min_capacity_for_more_than_19_bit_payload) { - return std::min(estimated_pucch_f2_capacity - short_crc_length, max_payload_with_6_bit_crc_addition); - } - - // Case: 11-bit CRC for payload >= 20. - const unsigned long_crc_length = 11U; - return estimated_pucch_f2_capacity - long_crc_length; -} +unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate); /// \brief Calculates the number of OFDM symbols filled with DM-RS in a PUCCH Format 3/4 resource. /// \param[in] nof_symbols Transmission duration in OFDM symbols. @@ -247,72 +186,12 @@ inline unsigned get_pucch_format3_4_nof_dmrs_symbols(bounded_integer nof_symbols, - float max_code_rate, - bool intraslot_freq_hopping, - bool additional_dmrs, - bool pi2_bpsk) -{ - static constexpr auto valid_num_prbs = to_array({1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16}); - const auto round_to_valid_nof_prbs = [](unsigned& value) { - if (value > pucch_constants::FORMAT3_MAX_NPRB) { - return; - } - - // Round up to the nearest valid number of PRBs for PUCCH Format 3. - const int* it = std::lower_bound(valid_num_prbs.begin(), valid_num_prbs.end(), value); - if (it != valid_num_prbs.end()) { - value = *it; - } - }; - - if (nof_payload_bits == 0) { - return 0; - } - - const unsigned nof_dmrs_symbols = - get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); - const unsigned mod_order = pi2_bpsk ? 1 : 2; - - // Compute the number of PRBs first without taking into account the CRC bits. - // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.2, TS 38.213. The - // ceil operation guarantees that the number of PRBs is enough to satisfy the effective code rate constraint. - unsigned nof_prbs = static_cast( - std::ceil(static_cast(nof_payload_bits) / - (static_cast((nof_symbols.value() - nof_dmrs_symbols) * NRE * mod_order) * max_code_rate))); - - round_to_valid_nof_prbs(nof_prbs); - - // The resulting number of PRBs is too big for PUCCH Format 3, so just return. - if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { - return nof_prbs; - } - - // Compute the total number of bits (including CRC) using the resulting PRB number. - unsigned e_uci = get_pucch_format3_E_total(nof_prbs, nof_symbols.value(), pi2_bpsk); - // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of - // code-blocks is \f$E_{UCI}\f$. - unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); - - // Check that the number of PRBs can hold the total number of bits after rate matching. - while (static_cast(std::ceil(static_cast(payload_plus_crc_bits) / max_code_rate)) > - (nof_dmrs_symbols * NRE * nof_prbs * mod_order)) { - round_to_valid_nof_prbs(++nof_prbs); - - // The resulting number of PRBs is too big for PUCCH Format 3, so just return. - if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { - return nof_prbs; - } - - // Compute the total number of bits (including CRC) using the resulting PRB number. - e_uci = get_pucch_format3_E_total(nof_prbs, nof_symbols.value(), pi2_bpsk); - // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of - // code-blocks is \f$E_{UCI}\f$. - payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); - } - return nof_prbs; -} +unsigned get_pucch_format3_max_nof_prbs(unsigned nof_payload_bits, + bounded_integer nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk); /// \brief Calculates the maximum payload for a PUCCH Format 3 transmission. /// \param[in] max_nof_prbs Transmission bandwidth in PRBs. @@ -322,48 +201,12 @@ inline unsigned get_pucch_format3_max_nof_prbs(unsigned /// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. /// \param[in] pi2_bpsk Flag indicating if pi/2-BPSK modulation is used. /// \return The maximum payload for a PUCCH Format 3 transmission. -inline unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, - unsigned nof_symbols, - float max_code_rate, - bool intraslot_freq_hopping, - bool additional_dmrs, - bool pi2_bpsk) -{ - const unsigned nof_dmrs_symbols = - get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); - const unsigned mod_order = pi2_bpsk ? 1 : 2; - - // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213; the - // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and - // max_code_rate. - const unsigned estimated_pucch_f3_capacity = static_cast(std::floor( - static_cast((nof_symbols - nof_dmrs_symbols) * NRE * mod_order * max_nof_prbs) * max_code_rate)); - - // Get the payload depending on the estimated PUCCH F3 capacity (which we define as the nof bits that the PUCCH F3 can - // carry). - - // Case: no CRC for payload <= 11 bits. - constexpr unsigned min_capacity_for_more_than_11_bit_payload = 18U; - constexpr unsigned max_payload_without_crc_addition = 11U; - if (estimated_pucch_f3_capacity < min_capacity_for_more_than_11_bit_payload) { - return std::min(estimated_pucch_f3_capacity, max_payload_without_crc_addition); - } - - // Case: 6-bit CRC for 12 <= payload <= 19 bits. - constexpr unsigned min_capacity_for_more_than_19_bit_payload = 31U; - constexpr unsigned max_payload_with_6_bit_crc_addition = 19U; - constexpr unsigned short_crc_length = 6U; - if (estimated_pucch_f3_capacity < min_capacity_for_more_than_19_bit_payload) { - return std::min(estimated_pucch_f3_capacity - short_crc_length, max_payload_with_6_bit_crc_addition); - } - - // Case: 11-bit CRC for payload >= 20. - // Compute the total number of bits (including CRC) using the resulting PRB number. - const unsigned e_uci = get_pucch_format3_E_total(max_nof_prbs, nof_symbols, pi2_bpsk); - constexpr unsigned long_crc_length = 11U; - const unsigned nof_crc_bits = get_uci_nof_crc_bits(estimated_pucch_f3_capacity - long_crc_length, e_uci); - return std::min(estimated_pucch_f3_capacity - long_crc_length, estimated_pucch_f3_capacity - nof_crc_bits); -} +unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk); /// Returns the number of possible spreading factors which is a function of the number of symbols. inline unsigned format1_symb_to_spreading_factor(bounded_integer f1_symbols) diff --git a/lib/ran/CMakeLists.txt b/lib/ran/CMakeLists.txt index 8b14217e5e..ba76cf3a48 100644 --- a/lib/ran/CMakeLists.txt +++ b/lib/ran/CMakeLists.txt @@ -33,6 +33,7 @@ add_library(srsran_ran prach/prach_helper.cpp precoding/precoding_codebooks.cpp ptrs/ptrs_pattern.cpp + pucch/pucch_info.cpp pusch/pusch_antenna_port_mapping.cpp pusch/pusch_mcs.cpp pusch/pusch_tpmi_select.cpp diff --git a/lib/ran/pucch/pucch_info.cpp b/lib/ran/pucch/pucch_info.cpp new file mode 100644 index 0000000000..8dfad1ead0 --- /dev/null +++ b/lib/ran/pucch/pucch_info.cpp @@ -0,0 +1,184 @@ +/* + * + * 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/ran/pucch/pucch_info.h" + +unsigned srsran::get_pucch_format2_max_nof_prbs(unsigned nof_payload_bits, unsigned nof_symbols, float max_code_rate) +{ + if (nof_payload_bits == 0 or nof_symbols == 0) { + return 0; + } + + // We compute \ref e_uci using the max PRBs, as we don't know the actual nof PRBs (computing this is the objective of + // this function). NOTE: as per Table 6.3.1.4-1 and Table 6.3.1.4.1-1, TS 38.212, the maximum value of \f$E_{UCI}\f$ + // for PUCCH Format 2 is 512. As per Section 6.3.1.2.1, TS 38.212, any value less than 1088 is irrelevant for the CRC + // length computation, therefore using the maximum number of PRBs instead of the actual number doesn't affect the + // result. + const unsigned max_nof_pucch_f2_prbs = 16; + const unsigned e_uci = get_pucch_format2_E_total(max_nof_pucch_f2_prbs, nof_symbols); + + // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of + // code-blocks is \f$E_{UCI}\f$. + const unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); + + constexpr unsigned nof_bits_qpsk_symbol = 2; + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213. The + // ceil operation guarantees that the number of PRBs is enough to satisfy the effective code rate constraint. + return static_cast(std::ceil( + static_cast(payload_plus_crc_bits) / + (static_cast(pucch_constants::FORMAT2_NOF_DATA_SC * nof_symbols * nof_bits_qpsk_symbol) * max_code_rate))); +} + +unsigned srsran::get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate) +{ + constexpr unsigned nof_bits_qpsk_symbol = 2; + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.2, TS 38.213; the + // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and + // max_code_rate. + // NOTE: The maximum number of bits that can be carried by a PUCCH Format 2 resource is 409, which is obtained for 16 + // PRBs, 2 symbols and 0.8 max code rate. + unsigned estimated_pucch_f2_capacity = static_cast(std::floor( + static_cast(pucch_constants::FORMAT2_NOF_DATA_SC * nof_symbols * nof_bits_qpsk_symbol * max_nof_prbs) * + max_code_rate)); + + // Get the payload depending on the estimated PUCCH F2 capacity (which we define as the nof bits that the PUCCH F2 can + // carry). + // NOTE: Given the max capacity of PUCCH, which is 409 bits (see above), the UCI in PUCCH F2 can have max 1 codeword + // (as per Section 6.3.1.2.1, TS 38.212); this implies only 6-bit and 11-bit can be added as CRC to the PUCCH F2 + // payload. + + // Case: no CRC for payload <= 11 bits. + const unsigned min_capacity_for_more_than_11_bit_payload = 18U; + const unsigned max_payload_without_crc_addition = 11U; + if (estimated_pucch_f2_capacity < min_capacity_for_more_than_11_bit_payload) { + return std::min(estimated_pucch_f2_capacity, max_payload_without_crc_addition); + } + // Case: 6-bit CRC for 12 <= payload <= 19 bits. + const unsigned min_capacity_for_more_than_19_bit_payload = 31U; + const unsigned max_payload_with_6_bit_crc_addition = 19U; + const unsigned short_crc_length = 6U; + if (estimated_pucch_f2_capacity < min_capacity_for_more_than_19_bit_payload) { + return std::min(estimated_pucch_f2_capacity - short_crc_length, max_payload_with_6_bit_crc_addition); + } + + // Case: 11-bit CRC for payload >= 20. + const unsigned long_crc_length = 11U; + return estimated_pucch_f2_capacity - long_crc_length; +} + +unsigned srsran::get_pucch_format3_max_nof_prbs(unsigned nof_payload_bits, + bounded_integer nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) +{ + static constexpr auto valid_num_prbs = to_array({1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16}); + const auto round_to_valid_nof_prbs = [](unsigned& value) { + if (value > pucch_constants::FORMAT3_MAX_NPRB) { + return; + } + + // Round up to the nearest valid number of PRBs for PUCCH Format 3. + const int* it = std::lower_bound(valid_num_prbs.begin(), valid_num_prbs.end(), value); + if (it != valid_num_prbs.end()) { + value = *it; + } + }; + + if (nof_payload_bits == 0) { + return 0; + } + + const unsigned nof_dmrs_symbols = + get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); + const unsigned mod_order = pi2_bpsk ? 1 : 2; + + // Compute the number of PRBs first without taking into account the CRC bits. + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.2, TS 38.213. The + // ceil operation guarantees that the number of PRBs is enough to satisfy the effective code rate constraint. + unsigned nof_prbs = static_cast( + std::ceil(static_cast(nof_payload_bits) / + (static_cast((nof_symbols.value() - nof_dmrs_symbols) * NRE * mod_order) * max_code_rate))); + + round_to_valid_nof_prbs(nof_prbs); + + // The resulting number of PRBs is too big for PUCCH Format 3, so just return. + if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { + return nof_prbs; + } + + // Compute the total number of bits (including CRC) using the resulting PRB number. + unsigned e_uci = get_pucch_format3_E_total(nof_prbs, nof_symbols.value(), pi2_bpsk); + // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of + // code-blocks is \f$E_{UCI}\f$. + unsigned payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); + + // Check that the number of PRBs can hold the total number of bits after rate matching. + while (static_cast(std::ceil(static_cast(payload_plus_crc_bits) / max_code_rate)) > + (nof_dmrs_symbols * NRE * nof_prbs * mod_order)) { + round_to_valid_nof_prbs(++nof_prbs); + + // The resulting number of PRBs is too big for PUCCH Format 3, so just return. + if (nof_prbs > pucch_constants::FORMAT3_MAX_NPRB) { + return nof_prbs; + } + + // Compute the total number of bits (including CRC) using the resulting PRB number. + e_uci = get_pucch_format3_E_total(nof_prbs, nof_symbols.value(), pi2_bpsk); + // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of + // code-blocks is \f$E_{UCI}\f$. + payload_plus_crc_bits = nof_payload_bits + get_uci_nof_crc_bits(nof_payload_bits, e_uci); + } + return nof_prbs; +} + +unsigned srsran::get_pucch_format3_max_payload(unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) +{ + const unsigned nof_dmrs_symbols = + get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); + const unsigned mod_order = pi2_bpsk ? 1 : 2; + + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213; the + // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and + // max_code_rate. + const unsigned estimated_pucch_f3_capacity = static_cast(std::floor( + static_cast((nof_symbols - nof_dmrs_symbols) * NRE * mod_order * max_nof_prbs) * max_code_rate)); + + // Get the payload depending on the estimated PUCCH F3 capacity (which we define as the nof bits that the PUCCH F3 can + // carry). + + // Case: no CRC for payload <= 11 bits. + constexpr unsigned min_capacity_for_more_than_11_bit_payload = 18U; + constexpr unsigned max_payload_without_crc_addition = 11U; + if (estimated_pucch_f3_capacity < min_capacity_for_more_than_11_bit_payload) { + return std::min(estimated_pucch_f3_capacity, max_payload_without_crc_addition); + } + + // Case: 6-bit CRC for 12 <= payload <= 19 bits. + constexpr unsigned min_capacity_for_more_than_19_bit_payload = 31U; + constexpr unsigned max_payload_with_6_bit_crc_addition = 19U; + constexpr unsigned short_crc_length = 6U; + if (estimated_pucch_f3_capacity < min_capacity_for_more_than_19_bit_payload) { + return std::min(estimated_pucch_f3_capacity - short_crc_length, max_payload_with_6_bit_crc_addition); + } + + // Case: 11-bit CRC for payload >= 20. + // Compute the total number of bits (including CRC) using the resulting PRB number. + const unsigned e_uci = get_pucch_format3_E_total(max_nof_prbs, nof_symbols, pi2_bpsk); + constexpr unsigned long_crc_length = 11U; + const unsigned nof_crc_bits = get_uci_nof_crc_bits(estimated_pucch_f3_capacity - long_crc_length, e_uci); + return std::min(estimated_pucch_f3_capacity - long_crc_length, estimated_pucch_f3_capacity - nof_crc_bits); +} From 6228cac8433b6b7f284061b7c6af01de44642c87 Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 5 Dec 2024 15:06:40 +0100 Subject: [PATCH 051/227] sched: reduce error to warning due to test mode --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index f8b9d0599d..4a0bd212ab 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -146,7 +146,10 @@ void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) } auto& u = ues[ue_index]; if (not u.get_pcell().is_in_fallback_mode()) { - logger.error("ue={}: ConRes CE discarded. Cause: UE is not in fallback state", ue_index); + // Note: In Test mode, the UE can skip fallback mode. However, since it was created via UL-CCCH, there is still an + // attempt to schedule the ConRes CE. If we want to change this log to warning, we need to create test mode UEs + // in a different manner. + logger.info("ue={}: ConRes CE discarded. Cause: UE is not in fallback state", ue_index); return; } From 8dfd27dad38ecf7bdf8516db454850458f9e6a16 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Tue, 3 Dec 2024 18:58:36 +0100 Subject: [PATCH 052/227] ci: add e2e test with RIC --- tests/e2e/pyproject.toml | 1 + tests/e2e/tests/iperf.py | 74 ++++++++++++++++++++++++++++++++++- tests/e2e/tests/steps/stub.py | 28 ++++++++++++- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index 0f9c4df2d6..ba65f86c33 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -37,6 +37,7 @@ markers = [ "zmq_2x2_mimo", "zmq_4x4_mimo", "zmq_srsue", + "zmq_ric", "test_mode", "test_mode_acc100", "test_mode_not_crash", diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index ac0cf11955..ff08c194ce 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -22,6 +22,7 @@ from retina.protocol.base_pb2 import PLMN from retina.protocol.fivegc_pb2_grpc import FiveGCStub from retina.protocol.gnb_pb2_grpc import GNBStub +from retina.protocol.ric_pb2_grpc import NearRtRicStub from retina.protocol.ue_pb2 import IPerfDir, IPerfProto from retina.protocol.ue_pb2_grpc import UEStub @@ -205,6 +206,60 @@ def test_srsue( ) +@mark.parametrize( + "direction", + (param(IPerfDir.BIDIRECTIONAL, id="bidirectional", marks=mark.bidirectional),), +) +@mark.parametrize( + "protocol", + (param(IPerfProto.UDP, id="udp", marks=mark.udp),), +) +@mark.parametrize( + "band, common_scs, bandwidth", + (param(3, 15, 10, id="band:%s-scs:%s-bandwidth:%s"),), +) +@mark.zmq_ric +# pylint: disable=too-many-arguments,too-many-positional-arguments +def test_ric( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue: UEStub, # pylint: disable=invalid-name + fivegc: FiveGCStub, + gnb: GNBStub, + ric: NearRtRicStub, + band: int, + common_scs: int, + bandwidth: int, + protocol: IPerfProto, + direction: IPerfDir, +): + """ + ZMQ IPerfs + """ + + _iperf( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=(ue,), + gnb=gnb, + fivegc=fivegc, + band=band, + common_scs=common_scs, + bandwidth=bandwidth, + sample_rate=11520000, + iperf_duration=SHORT_DURATION, + protocol=protocol, + bitrate=MEDIUM_BITRATE, + direction=direction, + global_timing_advance=-1, + time_alignment_calibration=0, + always_download_artifacts=True, + common_search_space_enable=True, + prach_config_index=1, + ric=ric, + ) + + @mark.parametrize( "direction", ( @@ -682,6 +737,7 @@ def _iperf( nof_antennas_dl: int = 1, nof_antennas_ul: int = 1, inter_ue_start_period=INTER_UE_START_PERIOD, + ric: Optional[NearRtRicStub] = None, ): wait_before_power_off = 5 @@ -709,7 +765,13 @@ def _iperf( ) ue_attach_info_dict = start_and_attach( - ue_array, gnb, fivegc, gnb_post_cmd=gnb_post_cmd, plmn=plmn, inter_ue_start_period=inter_ue_start_period + ue_array, + gnb, + fivegc, + gnb_post_cmd=gnb_post_cmd, + plmn=plmn, + inter_ue_start_period=inter_ue_start_period, + ric=ric, ) iperf_parallel( @@ -723,4 +785,12 @@ def _iperf( ) sleep(wait_before_power_off) - stop(ue_array, gnb, fivegc, retina_data, ue_stop_timeout=ue_stop_timeout, warning_as_errors=warning_as_errors) + stop( + ue_array, + gnb, + fivegc, + retina_data, + ue_stop_timeout=ue_stop_timeout, + warning_as_errors=warning_as_errors, + ric=ric, + ) diff --git a/tests/e2e/tests/steps/stub.py b/tests/e2e/tests/steps/stub.py index 71269de2bd..35325ad983 100644 --- a/tests/e2e/tests/steps/stub.py +++ b/tests/e2e/tests/steps/stub.py @@ -28,8 +28,10 @@ from retina.protocol.exit_codes import exit_code_to_message from retina.protocol.fivegc_pb2 import FiveGCStartInfo, IPerfResponse from retina.protocol.fivegc_pb2_grpc import FiveGCStub +from retina.protocol.ric_pb2 import NearRtRicStartInfo from retina.protocol.gnb_pb2 import GNBStartInfo from retina.protocol.gnb_pb2_grpc import GNBStub +from retina.protocol.ric_pb2_grpc import NearRtRicStub from retina.protocol.ue_pb2 import ( HandoverInfo, IPerfDir, @@ -64,6 +66,7 @@ def start_and_attach( attach_timeout: int = ATTACH_TIMEOUT, plmn: Optional[PLMN] = None, inter_ue_start_period=INTER_UE_START_PERIOD, + ric: Optional[NearRtRicStub] = None, ) -> Dict[UEStub, UEAttachedInfo]: """ Start stubs & wait until attach @@ -77,6 +80,7 @@ def start_and_attach( gnb_pre_cmd, gnb_post_cmd, plmn=plmn, + ric=ric, ) return ue_start_and_attach( @@ -109,9 +113,10 @@ def start_network( gnb_pre_cmd: Tuple[str, ...] = tuple(), gnb_post_cmd: Tuple[str, ...] = tuple(), plmn: Optional[PLMN] = None, + ric: Optional[NearRtRicStub] = None, ): """ - Start Network (5GC + gNB) + Start Network (5GC + gNB + RIC(optional)) """ ue_def_for_gnb = UEDefinition() @@ -144,6 +149,19 @@ def start_network( ) ) + ric_definition = None + if ric: + ric_startup_timeout = fivegc_startup_timeout + with handle_start_error(name=f"RIC [{id(ric)}]"): + # Near-RT RIC Start + ric.Start( + NearRtRicStartInfo( + start_info=StartInfo(timeout=ric_startup_timeout), + ) + ) + ric_definition = ric.GetDefinition(Empty()) + logging.info("RIC: %s", MessageToString(ric_definition, indent=2)) + with handle_start_error(name=f"GNB [{id(gnb)}]"): # GNB Start gnb.Start( @@ -151,6 +169,7 @@ def start_network( plmn=plmn, ue_definition=ue_def_for_gnb, fivegc_definition=fivegc.GetDefinition(Empty()), + ric_definition=ric_definition, start_info=StartInfo( timeout=gnb_startup_timeout, pre_commands=gnb_pre_cmd, @@ -597,9 +616,10 @@ def stop( log_search: bool = True, warning_as_errors: bool = True, fail_if_kos: bool = False, + ric: Optional[NearRtRicStub] = None, ): """ - Stop ue(s), gnb and 5gc + Stop ue(s), gnb and 5gc, ric """ # Stop error_msg_array = [] @@ -628,6 +648,10 @@ def stop( ) error_msg_array.append(error_message) + if ric is not None: + error_message, _ = _stop_stub(ric, "RIC", retina_data, gnb_stop_timeout, log_search, warning_as_errors) + error_msg_array.append(error_message) + # Fail if stop errors error_msg_array = list(filter(bool, error_msg_array)) if error_msg_array: From 66de1aed0d630a79240eac8e8e1eca3c26fbc8a3 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 4 Dec 2024 16:27:47 +0100 Subject: [PATCH 053/227] ci,e2: add functions to start and stop kpm mon xapp, and validate ric report --- tests/e2e/tests/iperf.py | 18 +++++++++++- tests/e2e/tests/steps/stub.py | 53 ++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index ff08c194ce..6c4ad1a17c 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -27,7 +27,15 @@ from retina.protocol.ue_pb2_grpc import UEStub from .steps.configuration import configure_test_parameters, get_minimum_sample_rate_for_bandwidth, is_tdd -from .steps.stub import INTER_UE_START_PERIOD, iperf_parallel, start_and_attach, stop +from .steps.stub import ( + INTER_UE_START_PERIOD, + iperf_parallel, + ric_validate_e2_interface, + start_and_attach, + start_kpm_mon_xapp, + stop, + stop_kpm_mon_xapp, +) TINY_DURATION = 10 SHORT_DURATION = 20 @@ -774,6 +782,9 @@ def _iperf( ric=ric, ) + if ric: + start_kpm_mon_xapp(ric, report_service_style=1, metrics="DRB.UEThpDl,DRB.UEThpUl") + iperf_parallel( ue_attach_info_dict, fivegc, @@ -784,7 +795,12 @@ def _iperf( bitrate_threshold, ) + if ric: + stop_kpm_mon_xapp(ric) + sleep(wait_before_power_off) + if ric: + ric_validate_e2_interface(ric, kpm_expected=True) stop( ue_array, gnb, diff --git a/tests/e2e/tests/steps/stub.py b/tests/e2e/tests/steps/stub.py index 35325ad983..0b9e150217 100644 --- a/tests/e2e/tests/steps/stub.py +++ b/tests/e2e/tests/steps/stub.py @@ -28,9 +28,9 @@ from retina.protocol.exit_codes import exit_code_to_message from retina.protocol.fivegc_pb2 import FiveGCStartInfo, IPerfResponse from retina.protocol.fivegc_pb2_grpc import FiveGCStub -from retina.protocol.ric_pb2 import NearRtRicStartInfo from retina.protocol.gnb_pb2 import GNBStartInfo from retina.protocol.gnb_pb2_grpc import GNBStub +from retina.protocol.ric_pb2 import KpmMonXappRequest, NearRtRicStartInfo from retina.protocol.ric_pb2_grpc import NearRtRicStub from retina.protocol.ue_pb2 import ( HandoverInfo, @@ -221,6 +221,23 @@ def ue_start_and_attach( return ue_attach_info_dict +def start_kpm_mon_xapp(ric: NearRtRicStub, report_service_style: int = 1, metrics: str = "DRB.UEThpDl") -> None: + """ + Start KPM Monitor xAPP in RIC + """ + xapp_request = KpmMonXappRequest() + xapp_request.report_service_style = report_service_style + xapp_request.metrics = metrics + ric.StartKpmMonXapp(xapp_request) + + +def stop_kpm_mon_xapp(ric: NearRtRicStub) -> None: + """ + Stop KPM Monitor xAPP in RIC + """ + ric.StopKpmMonXapp(Empty()) + + @contextmanager def handle_start_error(name: str) -> Generator[None, None, None]: """ @@ -605,6 +622,40 @@ def validate_ue_registered_via_ims(ue_stub_array: Sequence[UEStub], core: FiveGC pytest.fail("IMS Registered Subscriber array mismatch!") +def ric_validate_e2_interface(ric: NearRtRicStub, kpm_expected: bool = False, rc_expected: bool = False) -> None: + """ + Fails if E2 was not operating correctly + """ + ric_summary = ric.GetNearRtRicSummary(Empty()) + logging.info("RIC summary: %s", MessageToString(ric_summary, indent=2)) + + if not ric_summary.nof_connected_agents: + pytest.fail("No E2 agent connected to RIC.") + + if kpm_expected: + if not ric_summary.nof_connected_xapps: + pytest.fail("No xApp connected, but expected.") + + if not ric_summary.nof_subscription_reqs or not ric_summary.nof_subscription_reps: + pytest.fail("No valid RIC subscription received, but expected.") + + if ric_summary.nof_subscription_reqs != ric_summary.nof_subscription_reps: + pytest.fail("Different number of Subscription Request and Replies.") + + if not ric_summary.nof_ric_indication: + pytest.fail("No RIC Indiation messages after a successful subscription.") + + if rc_expected: + if not ric_summary.nof_connected_xapps: + pytest.fail("No xApp connected, but expected.") + + if not ric_summary.nof_control_reqs or not ric_summary.nof_control_reps: + pytest.fail("No RIC Control Request received, but expected.") + + if ric_summary.nof_control_reqs != ric_summary.nof_control_reps: + pytest.fail("Different number of RIC Control Request and Replies.") + + def stop( ue_array: Sequence[UEStub], gnb: Optional[GNBStub], From 6e4d6bd143827a87d65dde42965aaa80b11a7659 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 5 Dec 2024 11:59:19 +0100 Subject: [PATCH 054/227] ci,e2: add functions to start and stop rc xapp --- tests/e2e/tests/iperf.py | 6 +++++- tests/e2e/tests/steps/stub.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 6c4ad1a17c..12c8396bab 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -33,8 +33,10 @@ ric_validate_e2_interface, start_and_attach, start_kpm_mon_xapp, + start_rc_xapp, stop, stop_kpm_mon_xapp, + stop_rc_xapp, ) TINY_DURATION = 10 @@ -783,6 +785,7 @@ def _iperf( ) if ric: + start_rc_xapp(ric, control_service_style=2, action_id=6) start_kpm_mon_xapp(ric, report_service_style=1, metrics="DRB.UEThpDl,DRB.UEThpUl") iperf_parallel( @@ -796,11 +799,12 @@ def _iperf( ) if ric: + stop_rc_xapp(ric) stop_kpm_mon_xapp(ric) sleep(wait_before_power_off) if ric: - ric_validate_e2_interface(ric, kpm_expected=True) + ric_validate_e2_interface(ric, kpm_expected=True, rc_expected=True) stop( ue_array, gnb, diff --git a/tests/e2e/tests/steps/stub.py b/tests/e2e/tests/steps/stub.py index 0b9e150217..4aed9406d8 100644 --- a/tests/e2e/tests/steps/stub.py +++ b/tests/e2e/tests/steps/stub.py @@ -30,7 +30,7 @@ from retina.protocol.fivegc_pb2_grpc import FiveGCStub from retina.protocol.gnb_pb2 import GNBStartInfo from retina.protocol.gnb_pb2_grpc import GNBStub -from retina.protocol.ric_pb2 import KpmMonXappRequest, NearRtRicStartInfo +from retina.protocol.ric_pb2 import KpmMonXappRequest, NearRtRicStartInfo, RcXappRequest from retina.protocol.ric_pb2_grpc import NearRtRicStub from retina.protocol.ue_pb2 import ( HandoverInfo, @@ -238,6 +238,37 @@ def stop_kpm_mon_xapp(ric: NearRtRicStub) -> None: ric.StopKpmMonXapp(Empty()) +def start_rc_xapp(ric: NearRtRicStub, control_service_style: int = 2, action_id: int = 6) -> None: + """ + Start RC xAPP in RIC, currently only Slice-level PRB quota (Control Style 2, Action Id 6) is supported in Flexric. + Also, Flexric does not parse the control parameters. + """ + xapp_request = RcXappRequest() + xapp_request.control_service_style = control_service_style + xapp_request.action_id = action_id + # Parameters + xapp_request.parameters[7].name = "PLMN Identity" + xapp_request.parameters[7].value = 1 + xapp_request.parameters[9].name = "SST" + xapp_request.parameters[9].value = 1 + xapp_request.parameters[10].name = "SD" + xapp_request.parameters[10].value = 1 + xapp_request.parameters[11].name = "Min PRB Policy Ratio" + xapp_request.parameters[11].value = 20 + xapp_request.parameters[12].name = "Max PRB Policy Ratio" + xapp_request.parameters[12].value = 60 + xapp_request.parameters[13].name = "Dedicated PRB Policy Ratio" + xapp_request.parameters[13].value = 80 + ric.StartRcXapp(xapp_request) + + +def stop_rc_xapp(ric: NearRtRicStub) -> None: + """ + Stop RC xAPP in RIC + """ + ric.StopRcXapp(Empty()) + + @contextmanager def handle_start_error(name: str) -> Generator[None, None, None]: """ From 56a1efa92d8da759b57c24421e1c74255a2e9ea4 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 5 Dec 2024 12:15:42 +0100 Subject: [PATCH 055/227] ci,e2: add/modify gitlab ci config files --- .gitlab/ci/e2e.yml | 7 ++ .gitlab/ci/e2e/.env | 3 +- .gitlab/ci/e2e/retina_request_zmq_ric.yml | 87 +++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 .gitlab/ci/e2e/retina_request_zmq_ric.yml diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 878589753c..e428d1f28d 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -293,6 +293,13 @@ cudu amari 64UE: RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" KEYWORDS: "ping and 64" +ric: + extends: .zmq + variables: + TESTBED: "zmq_ric" + MARKERS: "zmq_ric" + allow_failure: true + ################################################################################ # TEST MODE ################################################################################ diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 4b0924ec6f..83583bfeac 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,10 +1,11 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.56.14 +RETINA_VERSION=0.58.0 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 OPEN5GS_VERSION=2.7.0 +FLEXRIC_VERSION=br-flexric PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.3 DPDK_VERSION=23.11.1 diff --git a/.gitlab/ci/e2e/retina_request_zmq_ric.yml b/.gitlab/ci/e2e/retina_request_zmq_ric.yml new file mode 100644 index 0000000000..458afcc7c5 --- /dev/null +++ b/.gitlab/ci/e2e/retina_request_zmq_ric.yml @@ -0,0 +1,87 @@ +# +# Copyright 2013-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. +# + +- name: srs-ue + type: ue + image: ${RETINA_REGISTRY_PREFIX}/srsue:${SRSUE_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} + requirements: + arch: amd64 + cpu: + requests: 4 + limits: 4 + memory: + requests: "22G" + limits: "22G" + ephemeral-storage: + requests: "6G" + limits: "6G" + resources: + - type: zmq + environment: + - RETINA_AGENT_ARGS: --grpc.max_size_file_artifact 209715200 + +- name: srs-gnb + type: gnb + image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} + requirements: + arch: amd64 + cpu: + requests: 4 + limits: 4 + memory: + requests: "22G" + limits: "22G" + ephemeral-storage: + requests: "15G" + limits: "15G" + resources: + - type: zmq + environment: + - PATH: ${PATH}:/builds/softwareradiosystems/srsgnb/build/apps/gnb + shared_files: + - local_path: ${GNB_BINARY_PATH} + remote_path: /usr/local/bin/gnb + is_executable: true + +- name: open5gs + type: 5gc + requirements: + arch: amd64 + cpu: + requests: 1 + limits: 1 + memory: + requests: "8G" + limits: "8G" + ephemeral-storage: + requests: "6G" + limits: "6G" + image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} + +- name: flexric-ric + type: ric + requirements: + arch: amd64 + cpu: + requests: 1 + limits: 1 + memory: + requests: "8G" + limits: "8G" + ephemeral-storage: + requests: "6G" + limits: "6G" + image: ${RETINA_REGISTRY_PREFIX}/flexric:${FLEXRIC_VERSION}_${RETINA_VERSION} + labels: + - ${ZMQ_HOSTLABEL_0} From d4b44746bba0485b6693c63c7ca0476bbf27a498 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 5 Dec 2024 18:24:48 +0100 Subject: [PATCH 056/227] e2, rc: handle parameter 13 in prb-quota control request --- .../e2sm_rc_control_action_du_executor.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 7d75cc768a..7f27110fd5 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 @@ -181,6 +181,22 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( ran_param.ran_p_choice_elem_false().ran_param_value.value_int(); ctrl_cfg.param_list.push_back(cur_control_params); } + } else if (action_params[ran_param_id] == "Dedicated PRB Policy Ratio") { + if (ctrl_cfg.param_list.size()) { + if (!ctrl_cfg.param_list.back().rrm_policy_group.has_value()) { + ctrl_cfg.param_list.back().rrm_policy_group.emplace(); + } + ctrl_cfg.param_list.back().rrm_policy_group.value().ded_prb_policy_ratio.emplace(); + ctrl_cfg.param_list.back().rrm_policy_group.value().ded_prb_policy_ratio = + ran_param.ran_p_choice_elem_false().ran_param_value.value_int(); + } else { + srs_du::control_config_params cur_control_params = {}; + cur_control_params.rrm_policy_group.emplace(); + cur_control_params.rrm_policy_group.value().ded_prb_policy_ratio.emplace(); + cur_control_params.rrm_policy_group.value().ded_prb_policy_ratio = + ran_param.ran_p_choice_elem_false().ran_param_value.value_int(); + ctrl_cfg.param_list.push_back(cur_control_params); + } } else { logger.error("Unknown RAN parameter ID {}", ran_param_id); return; From 7cee3a17f39e64de6440307b928a46ccbe705c26 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 5 Dec 2024 18:25:54 +0100 Subject: [PATCH 057/227] e2, rc: reduce log level, the PLMN from RIC usually uses wrong encoding --- lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 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 7f27110fd5..f1a2b32ee2 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 @@ -109,8 +109,8 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( srs_du::control_config_params cur_control_params = {}; cur_control_params.rrm_policy_group.emplace(); 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); + logger.warning("E2SM-RC Slice-level PRB quota Control Request: PLMN (param_id={}) encoded not correctly.", + ran_param_id); return; } std::array plmn_bytes; From 4e5e865ab14722641a6f49af6dce1dc114263775 Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 5 Dec 2024 17:41:52 +0100 Subject: [PATCH 058/227] sched: fix bug with fallback scheduler removing the UE too early from the list of pending UL UEs --- lib/scheduler/cell/cell_harq_manager.h | 6 ++++-- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index bd63d2e6ed..aa24aa20e6 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -471,8 +471,10 @@ class unique_ue_harq_entity unsigned nof_ul_harqs() const { return get_ul_ue().harqs.size(); } /// Checks whether there are free HARQ processes. - bool has_empty_dl_harqs() const { return not get_dl_ue().free_harq_ids.empty(); } - bool has_empty_ul_harqs() const { return not get_ul_ue().free_harq_ids.empty(); } + bool has_empty_dl_harqs() const { return not get_dl_ue().free_harq_ids.empty(); } + bool has_empty_ul_harqs() const { return not get_ul_ue().free_harq_ids.empty(); } + size_t nof_empty_dl_harqs() const { return get_dl_ue().free_harq_ids.size(); } + size_t nof_empty_ul_harqs() const { return get_ul_ue().free_harq_ids.size(); } /// Deallocate UE HARQ entity. void reset(); diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 4a0bd212ab..4f5ed1b71e 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1855,8 +1855,9 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) ue_it = pending_ul_ues.erase(ue_it); continue; } - std::optional h_ul_retx = ue.get_pcell().harqs.find_pending_ul_retx(); - if (not h_ul_retx.has_value() and not ue.pending_ul_newtx_bytes()) { + const auto& harqs = ue.get_pcell().harqs; + bool all_harqs_are_empty = harqs.nof_ul_harqs() == harqs.nof_empty_ul_harqs(); + if (all_harqs_are_empty and ue.pending_ul_newtx_bytes() == 0) { // UE has no pending data. ue_it = pending_ul_ues.erase(ue_it); continue; From 149b07585b9cb575d0731d5ae48b578f668bd405 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 6 Dec 2024 11:08:16 +0100 Subject: [PATCH 059/227] sched: fix ul scheduling in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 20 ++++++++++--------- .../ue_scheduling/ue_fallback_scheduler.h | 3 +-- .../ue_scheduling/fallback_scheduler_test.cpp | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 4f5ed1b71e..ab438dfeb1 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -232,9 +232,8 @@ void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& { // Processes all the UL UEs at once, including UEs with new transmissions and UEs with retransmissions. for (auto next_ue = pending_ul_ues.begin(); next_ue != pending_ul_ues.end();) { - auto& u = ues[*next_ue]; - std::optional h_ul_retx = u.get_pcell().harqs.find_pending_ul_retx(); - ul_srb_sched_outcome outcome = schedule_ul_ue(res_alloc, u, h_ul_retx); + auto& u = ues[*next_ue]; + ul_srb_sched_outcome outcome = schedule_ul_ue(res_alloc, u); if (outcome == ul_srb_sched_outcome::stop_ul_scheduling) { // If there is no PDCCH space, then stop the scheduling for all UL UEs. return; @@ -1281,11 +1280,16 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u return std::make_pair(srb1_bytes_allocated, *h_dl); } -ue_fallback_scheduler::ul_srb_sched_outcome -ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, - ue& u, - std::optional h_ul_retx) +ue_fallback_scheduler::ul_srb_sched_outcome ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, + ue& u) { + std::optional h_ul_retx = u.get_pcell().harqs.find_pending_ul_retx(); + const bool is_retx = h_ul_retx.has_value(); + const unsigned pending_bytes = u.pending_ul_newtx_bytes(); + if (not is_retx and pending_bytes == 0) { + return ul_srb_sched_outcome::next_ue; + } + // The caller ensures the slot is Ul enabled. const cell_slot_resource_allocator& pdcch_alloc = res_alloc[0]; slot_point pdcch_slot = pdcch_alloc.slot; @@ -1294,8 +1298,6 @@ ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_ static_vector pusch_td_res_index_list = get_pusch_td_resource_indices(cell_cfg, pdcch_slot); - bool is_retx = h_ul_retx.has_value(); - if (is_retx) { srsran_sanity_check(h_ul_retx->get_grant_params().dci_cfg_type == dci_ul_rnti_config_type::c_rnti_f0_0, "Invalid DCI type for UL retransmission for fallback UE"); diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 27fbefdcc1..dc3731b212 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -112,8 +112,7 @@ class ue_fallback_scheduler /// \brief Tries to schedule UL SRB1 message for a UE iterating over the possible k2 values. Returns true if the /// scheduler should keep allocating the next UL UE, false if it should stop the UL allocation. - ul_srb_sched_outcome - schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u, std::optional h_ul_retx); + ul_srb_sched_outcome schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u); struct sched_srb_results { std::optional h_dl; diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 772d9e8e3e..fdc0b82696 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -1266,7 +1266,7 @@ class ul_fallback_scheduler_tester : public base_fallback_tester, parent->push_buffer_state_to_ul_ue(test_ue.ue_index, sl, srb_buffer); buffer_bytes = srb_buffer; initied_with_ul_traffic = true; - test_logger.info("rnti={}, slot={}: generating initial BSR indication", test_ue.crnti, sl); + test_logger.info("rnti={}, slot={}: generating initial BSR indication {}", test_ue.crnti, sl, srb_buffer); } for (uint8_t h_id_idx = 0; h_id_idx != std::underlying_type_t(MAX_HARQ_ID); ++h_id_idx) { From 070aafd593ab09d57ff00453bcb330d18427302e Mon Sep 17 00:00:00 2001 From: yagoda Date: Wed, 4 Dec 2024 17:25:51 +0100 Subject: [PATCH 060/227] ntn,harq: adjusting the alignment of slots in harq history buffer for NTN --- lib/scheduler/cell/cell_harq_manager.cpp | 15 ++++++------ .../ue_scheduling/ue_cell_grid_allocator.cpp | 6 ++--- .../ue_scheduling/ue_scheduler_impl.cpp | 6 ++++- .../scheduler/cell/cell_harq_manager_test.cpp | 23 +++++++++++-------- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index b34bfbf4ea..74e0674700 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -35,7 +35,7 @@ class base_ntn_harq_history harq_pool(parent_), ntn_cs_koffset(ntn_cs_koffset_) { srsran_assert(ntn_cs_koffset > 0 and ntn_cs_koffset <= NTN_CELL_SPECIFIC_KOFFSET_MAX, "Invalid NTN koffset"); - unsigned ring_size = get_allocator_ring_size_gt_min(ntn_cs_koffset); + unsigned ring_size = get_allocator_ring_size_gt_min(NTN_CELL_SPECIFIC_KOFFSET_MAX * 2); history.resize(ring_size); } @@ -48,7 +48,7 @@ class base_ntn_harq_history } // Clear old entries. - unsigned idx = get_current_index(sl_tx - 1); + unsigned idx = get_current_index(sl_tx - SCHEDULER_MAX_K1); history[idx].clear(); } @@ -99,10 +99,11 @@ class ntn_dl_harq_alloc_history : public base_ntn_harq_history std::optional find_dl_harq(du_ue_index_t ue_idx, slot_point uci_slot, unsigned harq_bit_idx) { - unsigned idx = get_offset_index(uci_slot); + auto adjusted_slot = uci_slot - ntn_cs_koffset; + unsigned idx = get_offset_index(adjusted_slot); for (dl_harq_process_impl& h_impl : history[idx]) { - if (h_impl.ue_idx == ue_idx and h_impl.status == harq_state_t::waiting_ack and h_impl.slot_ack == uci_slot and - h_impl.harq_bit_idx == harq_bit_idx) { + if (h_impl.ue_idx == ue_idx and h_impl.status == harq_state_t::waiting_ack and + h_impl.slot_ack == adjusted_slot and h_impl.harq_bit_idx == harq_bit_idx) { return dl_harq_process_handle{harq_pool, h_impl}; } } @@ -497,8 +498,8 @@ cell_harq_manager::cell_harq_manager(unsigned max_ timeout_notifier(notifier != nullptr and ntn_cs_koffset == 0 ? std::move(notifier) : std::make_unique()), logger(srslog::fetch_basic_logger("SCHED")), - dl(max_ues, max_ack_wait_timeout, max_harqs_per_ue, ntn_cs_koffset, *timeout_notifier, logger), - ul(max_ues, max_ack_wait_timeout, max_harqs_per_ue, ntn_cs_koffset, *timeout_notifier, logger) + dl(max_ues, max_ack_wait_timeout + ntn_cs_koffset, max_harqs_per_ue, ntn_cs_koffset, *timeout_notifier, logger), + ul(max_ues, max_ack_wait_timeout + ntn_cs_koffset, max_harqs_per_ue, ntn_cs_koffset, *timeout_notifier, logger) { } diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 16ed7f0a6e..a7a90f660d 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -873,17 +873,15 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice // Mark resources as occupied in the ResourceGrid. pusch_alloc.ul_res_grid.fill(grant_info{scs, pusch_td_cfg.symbols, crbs}); - // Remove NTN offset when adding slot to HARQ process. - slot_point harq_slot = pusch_alloc.slot - ue_cell_cfg.cell_cfg_common.ntn_cs_koffset; // Allocate UE UL HARQ. bool is_new_data = not is_retx; if (is_new_data) { // It is a new tx. - h_ul = ue_cc->harqs.alloc_ul_harq(harq_slot, expert_cfg.max_nof_harq_retxs); + h_ul = ue_cc->harqs.alloc_ul_harq(pusch_alloc.slot, expert_cfg.max_nof_harq_retxs); srsran_assert(h_ul.has_value(), "Failed to allocate HARQ"); } else { // It is a retx. - bool result = h_ul->new_retx(harq_slot); + bool result = h_ul->new_retx(pusch_alloc.slot); srsran_assert(result, "Failed to allocate HARQ retx"); } diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 2c28eeceb9..60deaabdc8 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -244,7 +244,11 @@ ue_scheduler_impl::cell::cell(const scheduler_ue_expert_config& expert_cfg, ue_repository& ues, cell_metrics_handler& metrics_handler) : cell_res_alloc(params.cell_res_alloc), - cell_harqs(MAX_NOF_DU_UES, MAX_NOF_HARQS, std::make_unique(metrics_handler)), + cell_harqs(MAX_NOF_DU_UES, + MAX_NOF_HARQS, + std::make_unique(metrics_handler), + cell_harq_manager::DEFAULT_ACK_TIMEOUT_SLOTS, + params.cell_res_alloc->cfg.ntn_cs_koffset), uci_sched(params.cell_res_alloc->cfg, *params.uci_alloc, ues), fallback_sched(expert_cfg, params.cell_res_alloc->cfg, *params.pdcch_sched, *params.pucch_alloc, ues), slice_sched(params.cell_res_alloc->cfg, ues), diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index 8a199ef57e..c2e51cd78e 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -122,7 +122,10 @@ class base_harq_manager_test class base_single_harq_entity_test : public base_harq_manager_test { protected: - base_single_harq_entity_test(unsigned ntn_cs_koffset = 0) : base_harq_manager_test(1, ntn_cs_koffset) {} + base_single_harq_entity_test(unsigned ntn_cs_koffset_ = 0) : base_harq_manager_test(1, ntn_cs_koffset_) + { + ntn_cs_koffset = ntn_cs_koffset_; + } const du_ue_index_t ue_index = to_du_ue_index(0); const rnti_t rnti = to_rnti(0x4601); @@ -132,6 +135,7 @@ class base_single_harq_entity_test : public base_harq_manager_test unsigned max_retxs = 4; unsigned k1 = 4; unsigned k2 = 6; + unsigned ntn_cs_koffset; }; // Test for multiple UEs managed by a single HARQ manager instance. @@ -152,7 +156,7 @@ class single_ue_harq_entity_test : public base_single_harq_entity_test, public : class single_harq_process_test : public base_single_harq_entity_test, public ::testing::Test { protected: - single_harq_process_test(unsigned ntn_cs_koffset = 0) : base_single_harq_entity_test(ntn_cs_koffset) + single_harq_process_test(unsigned ntn_cs_koffset_ = 0) : base_single_harq_entity_test(ntn_cs_koffset_) { pdsch_info = make_dummy_pdsch_info(); dl_harq_alloc_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; @@ -165,7 +169,7 @@ class single_harq_process_test : public base_single_harq_entity_test, public ::t pdsch_information pdsch_info; pusch_information pusch_info; dl_harq_process_handle h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; - ul_harq_process_handle h_ul{harq_ent.alloc_ul_harq(current_slot + k2, max_retxs).value()}; + ul_harq_process_handle h_ul{harq_ent.alloc_ul_harq(current_slot + k2 + ntn_cs_koffset, max_retxs).value()}; }; class dl_harq_process_multi_pucch_test : public base_single_harq_entity_test, public ::testing::Test @@ -1054,15 +1058,15 @@ TEST_F(single_ntn_ue_harq_process_test, harq_history_is_reachable_after_timeout) { slot_point uci_slot = current_slot + k1; slot_point pusch_slot = current_slot + k2; - slot_point slot_timeout = std::max(uci_slot, pusch_slot) + 1; + slot_point slot_timeout = current_slot + ntn_cs_koffset + k2 + 1; while (current_slot != slot_timeout) { run_slot(); } ASSERT_FALSE(harq_ent.dl_harq(to_harq_id(0)).has_value()); ASSERT_FALSE(harq_ent.ul_harq(to_harq_id(0)).has_value()); - h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot, 0).value(); - h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot).value(); + h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot + ntn_cs_koffset, 0).value(); + h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot + ntn_cs_koffset).value(); ASSERT_FALSE(h_dl.empty() and h_ul.empty()); ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, pusch_info.tb_size_bytes); @@ -1074,17 +1078,16 @@ TEST_F(single_ntn_ue_harq_process_test, when_harq_gets_acked_then_it_reports_the { slot_point pusch_slot = current_slot + k2; slot_point uci_slot = current_slot + k1; - slot_point slot_timeout = std::max(pusch_slot, uci_slot) + 1; + slot_point slot_timeout = current_slot + ntn_cs_koffset + k2 + 1; while (current_slot != slot_timeout) { run_slot(); } - h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot).value(); + h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot + ntn_cs_koffset).value(); ASSERT_EQ(harq_ent.total_ul_bytes_waiting_ack(), pusch_info.tb_size_bytes); ASSERT_EQ(h_ul.ul_crc_info(true), pusch_info.tb_size_bytes); ASSERT_EQ(harq_ent.total_ul_bytes_waiting_ack(), 0); - - h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot, 0).value(); + h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot + ntn_cs_koffset, 0).value(); ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), dl_harq_process_handle::status_update::acked); ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); From 545e66093eadb8f42b29cdfe0d763f19e7fdfd2d Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 5 Dec 2024 13:20:52 +0100 Subject: [PATCH 061/227] cu_cp,rrc: add srb to all logs --- lib/rrc/ue/rrc_ue_helpers.cpp | 8 ++++++- lib/rrc/ue/rrc_ue_helpers.h | 5 ++-- lib/rrc/ue/rrc_ue_message_handlers.cpp | 32 ++++++++++++-------------- lib/rrc/ue/rrc_ue_message_senders.cpp | 20 ++++++++-------- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/lib/rrc/ue/rrc_ue_helpers.cpp b/lib/rrc/ue/rrc_ue_helpers.cpp index 65665e747d..38008a11e5 100644 --- a/lib/rrc/ue/rrc_ue_helpers.cpp +++ b/lib/rrc/ue/rrc_ue_helpers.cpp @@ -24,6 +24,7 @@ void srsran::srs_cu_cp::log_rrc_message(rrc_ue_logger& logger, const direction_t dir, byte_buffer_view pdu, const T& msg, + srb_id_t srb_id, const char* msg_type) { if (logger.get_basic_logger().debug.enabled()) { @@ -31,8 +32,9 @@ void srsran::srs_cu_cp::log_rrc_message(rrc_ue_logger& logger, msg.to_json(js); logger.log_debug(pdu.begin(), pdu.end(), - "{} {} {} ({} B)", + "{} {} {} {} ({} B)", (dir == Rx) ? "Rx" : "Tx", + srb_id, msg_type, msg.msg.c1().type().to_string(), pdu.length()); @@ -47,22 +49,26 @@ template void srsran::srs_cu_cp::log_rrc_message(rr const direction_t dir, byte_buffer_view pdu, const asn1::rrc_nr::ul_ccch_msg_s& msg, + srb_id_t srb_id, const char* msg_type); template void srsran::srs_cu_cp::log_rrc_message(rrc_ue_logger& logger, const direction_t dir, byte_buffer_view pdu, const asn1::rrc_nr::ul_dcch_msg_s& msg, + srb_id_t srb_id, const char* msg_type); template void srsran::srs_cu_cp::log_rrc_message(rrc_ue_logger& logger, const direction_t dir, byte_buffer_view pdu, const asn1::rrc_nr::dl_ccch_msg_s& msg, + srb_id_t srb_id, const char* msg_type); template void srsran::srs_cu_cp::log_rrc_message(rrc_ue_logger& logger, const direction_t dir, byte_buffer_view pdu, const asn1::rrc_nr::dl_dcch_msg_s& msg, + srb_id_t srb_id, const char* msg_type); diff --git a/lib/rrc/ue/rrc_ue_helpers.h b/lib/rrc/ue/rrc_ue_helpers.h index a264f0c640..735d86a5db 100644 --- a/lib/rrc/ue/rrc_ue_helpers.h +++ b/lib/rrc/ue/rrc_ue_helpers.h @@ -19,7 +19,7 @@ namespace srsran { namespace srs_cu_cp { -// Helper to create PDU from RRC message +// Helper to create PDU from RRC message. template byte_buffer pack_into_pdu(const T& msg, const char* context_name = nullptr) { @@ -32,7 +32,7 @@ byte_buffer pack_into_pdu(const T& msg, const char* context_name = nullptr) return pdu; } -// Logging +// Logging. typedef enum { Rx = 0, Tx } direction_t; template @@ -40,6 +40,7 @@ void log_rrc_message(rrc_ue_logger& logger, const direction_t dir, byte_buffer_view pdu, const T& msg, + srb_id_t srb_id, const char* msg_type); } // namespace srs_cu_cp diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index d21f69a564..f4b72cd833 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -40,7 +40,7 @@ void rrc_ue_impl::handle_ul_ccch_pdu(byte_buffer pdu) } // Log Rx message. - log_rrc_message(logger, Rx, pdu, ul_ccch_msg, "CCCH UL"); + log_rrc_message(logger, Rx, pdu, ul_ccch_msg, srb_id_t::srb0, "CCCH UL"); // Handle message. switch (ul_ccch_msg.msg.c1().type().value) { @@ -131,10 +131,8 @@ void rrc_ue_impl::handle_pdu(const srb_id_t srb_id, byte_buffer rrc_pdu) } } - // Log Rx message - 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)); + // Log Rx message. + log_rrc_message(logger, Rx, rrc_pdu, ul_dcch_msg, srb_id, "DCCH UL"); switch (ul_dcch_msg.msg.c1().type().value) { case ul_dcch_msg_type_c::c1_c_::types_opts::options::ul_info_transfer: @@ -171,12 +169,11 @@ void rrc_ue_impl::handle_pdu(const srb_id_t srb_id, byte_buffer rrc_pdu) logger.log_error("Unsupported DCCH UL message type"); break; } - // TODO: Handle message } void rrc_ue_impl::handle_ul_dcch_pdu(const srb_id_t srb_id, byte_buffer pdcp_pdu) { - logger.log_debug(pdcp_pdu.begin(), pdcp_pdu.end(), "RX {} PDCP PDU", srb_id); + logger.log_debug(pdcp_pdu.begin(), pdcp_pdu.end(), "Rx {} PDCP PDU", srb_id); if (context.srbs.find(srb_id) == context.srbs.end()) { logger.log_error(pdcp_pdu.begin(), pdcp_pdu.end(), "Dropping UL-DCCH PDU. Rx {} is not set up", srb_id); @@ -301,7 +298,7 @@ rrc_ue_security_mode_command_context rrc_ue_impl::get_security_mode_command_cont smc_ctxt.sp_cell_id = context.cell.cgi; // Log Tx message. - log_rrc_message(logger, Tx, smc_ctxt.rrc_ue_security_mode_command_pdu, dl_dcch_msg, "DCCH DL"); + log_rrc_message(logger, Tx, smc_ctxt.rrc_ue_security_mode_command_pdu, dl_dcch_msg, srb_id_t::srb1, "DCCH DL"); return smc_ctxt; } @@ -315,7 +312,7 @@ async_task rrc_ue_impl::handle_security_mode_complete_expected(uint8_t tra CORO_BEGIN(ctx); logger.log_debug("Awaiting RRC Security Mode Complete (timeout={}ms)", timeout_ms.count()); - // create new transaction for RRC Security Mode Command procedure. + // Create new transaction for RRC Security Mode Command procedure. transaction = event_mng->transactions.create_transaction(transaction_id, timeout_ms); CORO_AWAIT(transaction); @@ -423,7 +420,7 @@ rrc_ue_impl::get_rrc_ue_handover_reconfiguration_context(const rrc_reconfigurati dl_dcch_msg.msg.set_c1().set_rrc_recfg().crit_exts.set_rrc_recfg(); fill_asn1_rrc_reconfiguration_msg(dl_dcch_msg.msg.c1().rrc_recfg(), ho_reconf_ctxt.transaction_id, request); - // Pack DL DCCH msg + // Pack DL DCCH msg. pdcp_tx_result pdcp_packing_result = context.srbs.at(srb_id_t::srb1).pack_rrc_pdu(pack_into_pdu(dl_dcch_msg, "RRCReconfiguration")); if (!pdcp_packing_result.is_successful()) { @@ -436,7 +433,8 @@ rrc_ue_impl::get_rrc_ue_handover_reconfiguration_context(const rrc_reconfigurati ho_reconf_ctxt.rrc_ue_handover_reconfiguration_pdu = pdcp_packing_result.pop_pdu(); // Log Tx message. - log_rrc_message(logger, Tx, ho_reconf_ctxt.rrc_ue_handover_reconfiguration_pdu, dl_dcch_msg, "DCCH DL"); + log_rrc_message( + logger, Tx, ho_reconf_ctxt.rrc_ue_handover_reconfiguration_pdu, dl_dcch_msg, srb_id_t::srb1, "DCCH DL"); return ho_reconf_ctxt; } @@ -509,7 +507,7 @@ bool rrc_ue_impl::store_ue_capabilities(byte_buffer ue_capabilities) async_task rrc_ue_impl::handle_rrc_ue_capability_transfer_request(const rrc_ue_capability_transfer_request& msg) { - // Launch RRC UE capability transfer procedure. + // Launch RRC UE capability transfer procedure. return launch_async(context, *this, *event_mng, logger); } @@ -538,11 +536,11 @@ rrc_ue_release_context rrc_ue_impl::get_rrc_ue_release_context(bool requires_rrc release_context.srb_id = srb_id_t::srb0; // Log Tx message. - log_rrc_message(logger, Tx, release_context.rrc_release_pdu, dl_ccch_msg, "CCCH DL"); + log_rrc_message(logger, Tx, release_context.rrc_release_pdu, dl_ccch_msg, srb_id_t::srb0, "CCCH DL"); } else { // Prepare SRB1 RRC Release PDU to return. if (context.srbs.find(srb_id_t::srb1) == context.srbs.end()) { - logger.log_error("Can't create RRCRelease PDU. RX {} is not set up", srb_id_t::srb1); + logger.log_error("Can't create RRCRelease PDU. Rx {} is not set up", srb_id_t::srb1); return release_context; } @@ -563,13 +561,13 @@ rrc_ue_release_context rrc_ue_impl::get_rrc_ue_release_context(bool requires_rrc release_context.srb_id = srb_id_t::srb1; // Log Tx message. - log_rrc_message(logger, Tx, release_context.rrc_release_pdu, dl_dcch_msg, "DCCH DL"); + log_rrc_message(logger, Tx, release_context.rrc_release_pdu, dl_dcch_msg, srb_id_t::srb1, "DCCH DL"); } // Log Tx message. logger.log_debug(release_context.rrc_release_pdu.begin(), release_context.rrc_release_pdu.end(), - "TX {} PDU", + "Tx {} PDU", release_context.srb_id); } @@ -680,7 +678,7 @@ byte_buffer rrc_ue_impl::handle_rrc_handover_command(byte_buffer cmd) ho_reconf_pdu = pdcp_packing_result.pop_pdu(); // Log Tx message. - log_rrc_message(logger, Tx, ho_reconf_pdu, dl_dcch_msg, "DCCH DL"); + log_rrc_message(logger, Tx, ho_reconf_pdu, dl_dcch_msg, srb_id_t::srb1, "DCCH DL"); return ho_reconf_pdu; } diff --git a/lib/rrc/ue/rrc_ue_message_senders.cpp b/lib/rrc/ue/rrc_ue_message_senders.cpp index 0faa75db1c..3682e70114 100644 --- a/lib/rrc/ue/rrc_ue_message_senders.cpp +++ b/lib/rrc/ue/rrc_ue_message_senders.cpp @@ -19,31 +19,31 @@ using namespace asn1::rrc_nr; void rrc_ue_impl::send_dl_ccch(const dl_ccch_msg_s& dl_ccch_msg) { - // pack DL CCCH msg + // Pack DL CCCH msg. byte_buffer pdu = pack_into_pdu(dl_ccch_msg, "DL-CCCH-Message"); // Log Tx message - log_rrc_message(logger, Tx, pdu, dl_ccch_msg, "CCCH DL"); + log_rrc_message(logger, Tx, pdu, dl_ccch_msg, srb_id_t::srb0, "CCCH DL"); - // send down the stack - logger.log_debug(pdu.begin(), pdu.end(), "TX {} PDU", srb_id_t::srb0); + // Send down the stack. + logger.log_debug(pdu.begin(), pdu.end(), "Tx {} PDU", srb_id_t::srb0); f1ap_pdu_notifier.on_new_rrc_pdu(srb_id_t::srb0, std::move(pdu)); } void rrc_ue_impl::send_dl_dcch(srb_id_t srb_id, const dl_dcch_msg_s& dl_dcch_msg) { if (context.srbs.find(srb_id) == context.srbs.end()) { - logger.log_error("Dropping DlDcchMessage. TX {} is not set up", srb_id); + logger.log_error("Dropping DlDcchMessage. Tx {} is not set up", srb_id); return; } - // pack DL CCCH msg + // Pack DL CCCH msg. byte_buffer pdu = pack_into_pdu(dl_dcch_msg, "DL-DCCH-Message"); - // Log Tx message - log_rrc_message(logger, Tx, pdu, dl_dcch_msg, "DCCH DL"); + // Log Tx message. + log_rrc_message(logger, Tx, pdu, dl_dcch_msg, srb_id, "DCCH DL"); - // pack PDCP PDU and send down the stack + // Pack PDCP PDU and send down the stack. auto pdcp_packing_result = context.srbs.at(srb_id).pack_rrc_pdu(std::move(pdu)); if (!pdcp_packing_result.is_successful()) { logger.log_info("Requesting UE release. Cause: PDCP packing failed with {}", @@ -53,6 +53,6 @@ void rrc_ue_impl::send_dl_dcch(srb_id_t srb_id, const dl_dcch_msg_s& dl_dcch_msg } byte_buffer pdcp_pdu = pdcp_packing_result.pop_pdu(); - logger.log_debug(pdcp_pdu.begin(), pdcp_pdu.end(), "TX {} PDU", context.ue_index, context.c_rnti, srb_id); + logger.log_debug(pdcp_pdu.begin(), pdcp_pdu.end(), "Tx {} PDU", context.ue_index, context.c_rnti, srb_id); f1ap_pdu_notifier.on_new_rrc_pdu(srb_id, std::move(pdcp_pdu)); } From f644eeb409aa126128525dddf861f8c501a64b90 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 3 Dec 2024 11:54:21 +0100 Subject: [PATCH 062/227] sched: use harq entity to maintain last pdsch and pusch slots for a given UE and cell --- lib/scheduler/cell/cell_harq_manager.cpp | 27 ++++++++++++++- lib/scheduler/cell/cell_harq_manager.h | 7 ++++ lib/scheduler/ue_context/ue.cpp | 18 ---------- lib/scheduler/ue_context/ue_cell.h | 5 --- .../ue_scheduling/ue_cell_grid_allocator.cpp | 34 +++++++++++-------- 5 files changed, 53 insertions(+), 38 deletions(-) diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 74e0674700..92f8a24692 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -286,6 +286,12 @@ typename cell_harq_repository::harq_type* cell_harq_repository::allo h.ack_on_timeout = false; h.retxs_cancelled = false; + // Set UE HARQ entity common params. + ue_harq_entity.last_slot_tx = + ue_harq_entity.last_slot_tx.valid() ? std::max(ue_harq_entity.last_slot_tx, sl_tx) : sl_tx; + ue_harq_entity.last_slot_ack = + ue_harq_entity.last_slot_ack.valid() ? std::max(ue_harq_entity.last_slot_ack, sl_ack) : sl_ack; + // Add HARQ to the timeout list. h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); @@ -311,8 +317,19 @@ void cell_harq_repository::dealloc_harq(harq_type& h) } h.status = harq_state_t::empty; - // Mark HARQ as available again. + // Check if common HARQ entity params need to be updated. ue_harq_entity_impl& ue_harq_entity = ues[h.ue_idx]; + if (ue_harq_entity.last_slot_tx.valid() and h.slot_tx >= ue_harq_entity.last_slot_tx) { + // If the HARQ being reset corresponds to the last recorded Tx, we also reset "last_slot_tx". This avoids + // encountering ambiguities with the slot wrap-around, when the UE stays for very long without being scheduled. + ue_harq_entity.last_slot_tx = {}; + } + if (ue_harq_entity.last_slot_ack.valid() and h.slot_ack >= ue_harq_entity.last_slot_ack) { + // We do the same with last_slot_ack as we did with last_slot_tx. + ue_harq_entity.last_slot_ack = {}; + } + + // Mark HARQ as available again. ue_harq_entity.free_harq_ids.push_back(h.h_id); } @@ -383,12 +400,20 @@ bool cell_harq_repository::handle_new_retx(harq_type& h, slot_point sl_tx, // Remove HARQ from pending Retx list. harq_pending_retx_list.pop(&h); + // Update HARQ common parameters. h.status = harq_state_t::waiting_ack; h.slot_tx = sl_tx; h.slot_ack = sl_ack; h.ack_on_timeout = false; h.nof_retxs++; + // Set UE HARQ entity common params. + ue_harq_entity_impl& ue_harq_entity = ues[h.ue_idx]; + ue_harq_entity.last_slot_tx = + ue_harq_entity.last_slot_tx.valid() ? std::max(ue_harq_entity.last_slot_tx, sl_tx) : sl_tx; + ue_harq_entity.last_slot_ack = + ue_harq_entity.last_slot_ack.valid() ? std::max(ue_harq_entity.last_slot_ack, sl_ack) : sl_ack; + // Add HARQ to the timeout list. h.slot_ack_timeout = sl_ack + max_ack_wait_in_slots; harq_timeout_wheel[h.slot_ack_timeout.to_uint() % harq_timeout_wheel.size()].push_front(&h); diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index aa24aa20e6..ca50be1b71 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -128,6 +128,8 @@ struct cell_harq_repository { struct ue_harq_entity_impl { std::vector harqs; std::vector free_harq_ids; + slot_point last_slot_tx; + slot_point last_slot_ack; }; cell_harq_repository(unsigned max_ues, @@ -476,6 +478,11 @@ class unique_ue_harq_entity size_t nof_empty_dl_harqs() const { return get_dl_ue().free_harq_ids.size(); } size_t nof_empty_ul_harqs() const { return get_ul_ue().free_harq_ids.size(); } + /// Check the last HARQ allocations for the given UE. + slot_point last_pdsch_slot() const { return get_dl_ue().last_slot_tx; } + slot_point last_ack_slot() const { return get_dl_ue().last_slot_ack; } + slot_point last_pusch_slot() const { return get_ul_ue().last_slot_tx; } + /// Deallocate UE HARQ entity. void reset(); diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 96657fa1b8..c459546611 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -43,24 +43,6 @@ ue::ue(const ue_creation_command& cmd) : void ue::slot_indication(slot_point sl_tx) { - for (ue_cell* ue_cc : ue_cells) { - // [Implementation-defined] - // Clear last PxSCH allocated slot if gap to current \c sl_tx is too large. This is done in order to circumvent - // the ambiguity caused by the slot_point wrap around while scheduling next PxSCHs. e.g. last PxSCH allocated - // slot=289.0 and next PxSCH to be allocated slot=(289.0 - SCHEDULER_MAX_K0/SCHEDULER_MAX_K2) after wrap around. - if (ue_cc->last_pdsch_allocated_slot.valid()) { - srsran_sanity_check(sl_tx >= ue_cc->last_pdsch_allocated_slot, "Invalid last PDSCH alloc slot"); - if (static_cast(sl_tx - ue_cc->last_pdsch_allocated_slot) > SCHEDULER_MAX_K0) { - ue_cc->last_pdsch_allocated_slot.clear(); - } - } - if (ue_cc->last_pusch_allocated_slot.valid()) { - if (sl_tx - ue_cc->last_pusch_allocated_slot > static_cast(SCHEDULER_MAX_K2)) { - ue_cc->last_pusch_allocated_slot.clear(); - } - } - } - ta_mgr.slot_indication(sl_tx); drx.slot_indication(sl_tx); } diff --git a/lib/scheduler/ue_context/ue_cell.h b/lib/scheduler/ue_context/ue_cell.h index 3ce23f2d1a..09ceb51e0a 100644 --- a/lib/scheduler/ue_context/ue_cell.h +++ b/lib/scheduler/ue_context/ue_cell.h @@ -48,11 +48,6 @@ class ue_cell unique_ue_harq_entity harqs; - // Slot at which PDSCH was allocated in the past for this UE in this cell. - slot_point last_pdsch_allocated_slot; - // Slot at which PUSCH was allocated in the past for this UE in this cell. - slot_point last_pusch_allocated_slot; - rnti_t rnti() const { return crnti_; } bwp_id_t active_bwp_id() const { return to_bwp_id(0); } diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index a7a90f660d..fda052d304 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -143,11 +143,17 @@ dl_alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& // Fetch PDSCH resource grid allocator. cell_slot_resource_allocator& pdsch_alloc = get_res_alloc(grant.cell_index)[pdsch_td_cfg.k0]; - // Verify only one PDSCH exists for an RNTI. - // See TS 38.214, clause 5.1, "For any HARQ process ID(s) in a given scheduled cell, the UE is not - // expected to receive a PDSCH that overlaps in time with another PDSCH". - if (ue_cc->last_pdsch_allocated_slot.valid() and pdsch_alloc.slot <= ue_cc->last_pdsch_allocated_slot) { - // Try next candidate. + // Verify only one PDSCH exists for the same RNTI in the same slot, and that the PDSCHs are in the same order as + // PDCCHs. + // [TS 38.214, 5.1] "For any HARQ process ID(s) in a given scheduled cell, the UE is not expected to receive a + // PDSCH that overlaps in time with another PDSCH". + // [TS 38.214, 5.1] "For any two HARQ process IDs in a given scheduled cell, if the UE is scheduled to start + // receiving a first PDSCH starting in symbol j by a PDCCH ending in symbol i, the UE is not expected to be + // scheduled to receive a PDSCH starting earlier than the end of the first PDSCH with a PDCCH that ends later + // than symbol i.". + slot_point last_pdsch_slot = ue_cc->harqs.last_pdsch_slot(); + if (last_pdsch_slot.valid() and pdsch_alloc.slot <= last_pdsch_slot) { + // Try next k0 candidate. continue; } @@ -465,8 +471,7 @@ dl_alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& ue_cc->link_adaptation_controller().calculate_dl_mcs(msg.pdsch_cfg.codewords[0].mcs_table); pdsch_sched_ctx.slice_id = slice_id; } - pdsch_sched_ctx.cqi = ue_cc->channel_state_manager().get_wideband_cqi(); - ue_cc->last_pdsch_allocated_slot = pdsch_alloc.slot; + pdsch_sched_ctx.cqi = ue_cc->channel_state_manager().get_wideband_cqi(); if (is_new_data) { // Set MAC logical channels to schedule in this PDU if it is a newtx. @@ -581,13 +586,15 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice // Fetch PUSCH resource grid allocators. cell_slot_resource_allocator& pusch_alloc = get_res_alloc(grant.cell_index)[pdcch_delay_in_slots + final_k2]; - // Verify only one PUSCH exists for an RNTI. - // See TS 38.214, clause 6.1, "For any HARQ process ID(s) in a given scheduled cell, the UE is not expected to - // transmit a PUSCH that overlaps in time with another PUSCH". - // "For any two HARQ process IDs in a given scheduled cell, if the UE is scheduled to start a first PUSCH - // transmission starting in symbol j by a PDCCH ending in symbol i, the UE is not expected to be scheduled to + // Verify that the order of PUSCHs for the same UE matches the order of PDCCHs and that there is at most one PUSCH + // per slot. + // [TS 38.214, 6.1] "For any HARQ process ID(s) in a given scheduled cell, the UE is not expected to transmit a + // PUSCH that overlaps in time with another PUSCH". + // [TS 38.214, 6.1] "For any two HARQ process IDs in a given scheduled cell, if the UE is scheduled to start a first + // PUSCH transmission starting in symbol j by a PDCCH ending in symbol i, the UE is not expected to be scheduled to // transmit a PUSCH starting earlier than the end of the first PUSCH by a PDCCH that ends later than symbol i". - if (ue_cc->last_pusch_allocated_slot.valid() and pusch_alloc.slot <= ue_cc->last_pusch_allocated_slot) { + slot_point last_pusch_slot = ue_cc->harqs.last_pusch_slot(); + if (last_pusch_slot.valid() and pusch_alloc.slot <= last_pusch_slot) { return {alloc_status::skip_ue}; } @@ -999,7 +1006,6 @@ ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& grant, ran_slice pusch_sched_ctx.olla_mcs = ue_cc->link_adaptation_controller().calculate_ul_mcs(msg.pusch_cfg.mcs_table); pusch_sched_ctx.slice_id = slice_id; } - ue_cc->last_pusch_allocated_slot = pusch_alloc.slot; // Update the number of PRBs used in the PUSCH allocation. ue_cc->get_ul_power_controller().update_pusch_pw_ctrl_state(pusch_alloc.slot, crbs.length()); From d76a13b6a17a535b217a5aa0508e5c437e77bfb6 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 3 Dec 2024 15:05:11 +0100 Subject: [PATCH 063/227] sched: remove linear search to find latest alloc in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 48 +++++-------------- .../ue_scheduling/ue_fallback_scheduler.h | 10 ---- 2 files changed, 12 insertions(+), 46 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index ab438dfeb1..84912e945d 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -362,26 +362,25 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // TODO: Make this compatible with k0 > 0. slot_point sched_ref_slot = res_alloc[0].slot; - std::optional most_recent_tx_ack_slots = get_most_recent_slot_tx(u.ue_index); + // Retrieve the slot of the last PDSCH for this UE. + slot_point last_pdsch_slot = u.get_pcell().harqs.last_pdsch_slot(); + slot_point last_slot_ack = u.get_pcell().harqs.last_ack_slot(); // This is to prevent the edge case of the scheduler trying to allocate an SRB PDSCH in the farthest possible slot // in the future when, in the same slot, there is already an SRB PDSCH allocated. This can happen, for example, if // there is a retransmission (previously) allocated at slot sched_ref_slot + max_dl_slots_ahead_sched, and then the // scheduler attempt to allocate a new TX on the same slot. - if (most_recent_tx_ack_slots.has_value() and - sched_ref_slot + max_dl_slots_ahead_sched <= most_recent_tx_ack_slots.value().most_recent_tx_slot) { + if (last_pdsch_slot.valid() and sched_ref_slot + max_dl_slots_ahead_sched <= last_pdsch_slot) { return dl_sched_outcome::next_ue; } // \ref starting_slot is the slot from which the SRB0 starts scheduling this given UE. Assuming the UE was assigned // a PDSCH grant for SRB1 that was fragmented, we want to avoid allocating the second part of SRB1 in a PDSCH that // is scheduled for an earlier slot than the PDSCH of the first part of the SRB1. - // NOTE: The \c most_recent_tx_slot is not necessarily more recent than sched_ref_slot; hence we need to check that - // most_recent_tx_ack_slots.value().most_recent_tx_slot >= sched_ref_slot. + // NOTE: The \c last_pdsch_slot is not necessarily more recent than sched_ref_slot; hence we need to check that + // last_pdsch_slot >= sched_ref_slot. slot_point starting_slot = - most_recent_tx_ack_slots.has_value() and most_recent_tx_ack_slots.value().most_recent_tx_slot > sched_ref_slot - ? most_recent_tx_ack_slots.value().most_recent_tx_slot - : sched_ref_slot; + last_pdsch_slot.valid() and last_pdsch_slot > sched_ref_slot ? last_pdsch_slot : sched_ref_slot; for (slot_point next_slot = starting_slot; next_slot <= sched_ref_slot + max_dl_slots_ahead_sched; next_slot = get_next_srb_slot(cell_cfg, next_slot)) { @@ -444,11 +443,11 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // the most recent already scheduled ACK slot (for the same UE), whenever we detect this is the case we skip the // allocation in advance. slot_point most_recent_ack_slot = pdsch_alloc.slot; - if (most_recent_tx_ack_slots.has_value()) { - if (pdsch_alloc.slot + dci_1_0_k1_values.back() <= most_recent_tx_ack_slots.value().most_recent_ack_slot) { + if (last_slot_ack.valid()) { + if (pdsch_alloc.slot + dci_1_0_k1_values.back() <= last_slot_ack) { continue; } - most_recent_ack_slot = most_recent_tx_ack_slots.value().most_recent_ack_slot; + most_recent_ack_slot = last_slot_ack; } sched_srb_results sched_res; @@ -501,7 +500,8 @@ static dci_dl_rnti_config_type get_dci_type(const ue& u, const std::optionalget_grant_params().dci_cfg_type; - } else if (u.is_conres_ce_pending()) { + } + if (u.is_conres_ce_pending()) { return dci_dl_rnti_config_type::tc_rnti_f1_0; } return dci_dl_rnti_config_type::c_rnti_f1_0; @@ -1667,30 +1667,6 @@ ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsch_config_common& return candidate_pdsch_time_res_idx; } -std::optional -ue_fallback_scheduler::get_most_recent_slot_tx(du_ue_index_t ue_idx) const -{ - std::optional most_recent_tx_ack_slot; - for (const auto& ue_proc : ongoing_ues_ack_retxs) { - if (ue_proc.ue_index == ue_idx) { - slot_point h_dl_slot_tx = ue_proc.h_dl->pdsch_slot(); - slot_point h_dl_slot_ack = ue_proc.h_dl->uci_slot(); - if (not most_recent_tx_ack_slot.has_value()) { - most_recent_tx_ack_slot.emplace( - most_recent_tx_slots{.most_recent_tx_slot = h_dl_slot_tx, .most_recent_ack_slot = h_dl_slot_ack}); - continue; - } - if (h_dl_slot_tx > most_recent_tx_ack_slot.value().most_recent_tx_slot) { - most_recent_tx_ack_slot.value().most_recent_tx_slot = h_dl_slot_tx; - } - if (h_dl_slot_ack > most_recent_tx_ack_slot.value().most_recent_ack_slot) { - most_recent_tx_ack_slot.value().most_recent_ack_slot = h_dl_slot_ack; - } - } - } - return most_recent_tx_ack_slot; -} - void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ue_index, std::optional h_dl, unsigned srb_payload_bytes, diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index dc3731b212..fa92fe2e70 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -91,12 +91,6 @@ class ue_fallback_scheduler /// Erase the UEs' HARQ processes that have been acked from the SRB scheduler cache. void slot_indication(slot_point sl); - // Holds the most recent slot with PDSCH for SRB0/SRB1 and the most recent slot with the corresponding PUCCH. - struct most_recent_tx_slots { - slot_point most_recent_tx_slot; - slot_point most_recent_ack_slot; - }; - /// \remark srb_pending => Only ConRes was scheduled and Msg4 is yet to be scheduled. enum class dl_sched_outcome { success, next_ue, stop_dl_scheduling, srb_pending }; @@ -242,10 +236,6 @@ class ue_fallback_scheduler unsigned srb_payload_bytes, std::optional is_srb0 = std::nullopt); - // If there are any pending SRB0, SRB1 transmissions or ConRes CE for the UE, the function returns the most recent - // slot with PDSCH for SRB0/SRB1/ConRes CE allocation and the most recent slot with the corresponding PUCCH. - std::optional get_most_recent_slot_tx(du_ue_index_t ue_idx) const; - // Returns the total number of bytes pending for SRB1 for a given UE, including MAC CE and MAC subheaders. unsigned get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) const; From 03bfe5c41758196021d85020c2a0abf2cbf7f127 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 3 Dec 2024 15:20:50 +0100 Subject: [PATCH 064/227] sched: simplify logic to derive the starting_slot in the ue_fallback_scheduler::schedule_dl_srb --- .../ue_scheduling/ue_fallback_scheduler.cpp | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 84912e945d..885e3ef605 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -363,24 +363,14 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res slot_point sched_ref_slot = res_alloc[0].slot; // Retrieve the slot of the last PDSCH for this UE. - slot_point last_pdsch_slot = u.get_pcell().harqs.last_pdsch_slot(); - slot_point last_slot_ack = u.get_pcell().harqs.last_ack_slot(); - - // This is to prevent the edge case of the scheduler trying to allocate an SRB PDSCH in the farthest possible slot - // in the future when, in the same slot, there is already an SRB PDSCH allocated. This can happen, for example, if - // there is a retransmission (previously) allocated at slot sched_ref_slot + max_dl_slots_ahead_sched, and then the - // scheduler attempt to allocate a new TX on the same slot. - if (last_pdsch_slot.valid() and sched_ref_slot + max_dl_slots_ahead_sched <= last_pdsch_slot) { - return dl_sched_outcome::next_ue; - } - - // \ref starting_slot is the slot from which the SRB0 starts scheduling this given UE. Assuming the UE was assigned - // a PDSCH grant for SRB1 that was fragmented, we want to avoid allocating the second part of SRB1 in a PDSCH that - // is scheduled for an earlier slot than the PDSCH of the first part of the SRB1. - // NOTE: The \c last_pdsch_slot is not necessarily more recent than sched_ref_slot; hence we need to check that - // last_pdsch_slot >= sched_ref_slot. + const slot_point last_pdsch_slot = u.get_pcell().harqs.last_pdsch_slot(); + const slot_point last_slot_ack = u.get_pcell().harqs.last_ack_slot(); + + // \ref starting_slot is the slot from which the scheduler will search for PDSCH space for a given UE. + // As per TS 38.214, clause 5.1, the PDSCHs need to follow the same order as PDCCHs for a given UE. Thus, we set the + // starting_slot to be always higher than the slot of the last PDSCH for the same UE (if it exists). slot_point starting_slot = - last_pdsch_slot.valid() and last_pdsch_slot > sched_ref_slot ? last_pdsch_slot : sched_ref_slot; + last_pdsch_slot.valid() ? std::max(get_next_srb_slot(cell_cfg, last_pdsch_slot), sched_ref_slot) : sched_ref_slot; for (slot_point next_slot = starting_slot; next_slot <= sched_ref_slot + max_dl_slots_ahead_sched; next_slot = get_next_srb_slot(cell_cfg, next_slot)) { @@ -1654,7 +1644,8 @@ ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsch_config_common& if (h_dl_retx->get_grant_params().nof_symbols != pdsch_td_cfg.symbols.length()) { continue; } - return candidate_pdsch_time_res_idx = time_res_idx; + candidate_pdsch_time_res_idx = time_res_idx; + return candidate_pdsch_time_res_idx; } // For new transmissions, we want to search for the PDSCH time domain resource with the largest number of symbols. if (candidate_pdsch_time_res_idx.has_value() and From c524c4de735dcc9a54754f0ca3acac8e7935db22 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 4 Dec 2024 10:31:20 +0100 Subject: [PATCH 065/227] sched: minor fixes in the fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 43 ++++++------------- .../ue_scheduling/ue_fallback_scheduler.h | 2 - .../scheduler_test_message_validators.cpp | 13 ++++++ .../scheduler_test_message_validators.h | 3 ++ .../test_utils/scheduler_test_suite.cpp | 4 +- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 885e3ef605..ad1e8210b2 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -360,7 +360,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // slot_indication(). // NOTE: we guarantee that \ref sched_ref_slot is a DL slot in the caller. // TODO: Make this compatible with k0 > 0. - slot_point sched_ref_slot = res_alloc[0].slot; + const slot_point sched_ref_slot = res_alloc[0].slot; // Retrieve the slot of the last PDSCH for this UE. const slot_point last_pdsch_slot = u.get_pcell().harqs.last_pdsch_slot(); @@ -420,18 +420,9 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res continue; } - // Check whether PDSCH for the UE already exists or not. - const auto* ue_pdsch_exists_it = - std::find_if(pdsch_alloc.result.dl.ue_grants.begin(), - pdsch_alloc.result.dl.ue_grants.end(), - [rnti = u.crnti](const dl_msg_alloc& pdsch) { return pdsch.pdsch_cfg.rnti == rnti; }); - if (ue_pdsch_exists_it != pdsch_alloc.result.dl.ue_grants.end()) { - return dl_sched_outcome::next_ue; - } - - // As it is not possible to schedule a PDSCH whose related PUCCH falls in a slot that is the same as or older than - // the most recent already scheduled ACK slot (for the same UE), whenever we detect this is the case we skip the - // allocation in advance. + // As per TS 38.214, clause 5.1, it is not possible to schedule a PDSCH whose related PUCCH falls in a slot that + // is the same as or older than the most recent already scheduled ACK slot (for the same UE). Whenever we detect + // this is the case we skip the allocation in advance. slot_point most_recent_ack_slot = pdsch_alloc.slot; if (last_slot_ack.valid()) { if (pdsch_alloc.slot + dci_1_0_k1_values.back() <= last_slot_ack) { @@ -444,19 +435,12 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res if (not is_srb0.has_value()) { sched_res = schedule_dl_conres_ce( u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); + } else if (is_srb0.value()) { + sched_res = schedule_dl_srb0( + u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); } else { - if (is_srb0.value()) { - sched_res = schedule_dl_srb0( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); - } else { - sched_res = schedule_dl_srb1(u, - sched_ref_slot, - res_alloc, - time_res_idx.value(), - offset_to_sched_ref_slot, - most_recent_ack_slot, - h_dl_retx); - } + sched_res = schedule_dl_srb1( + u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); } const bool alloc_successful = sched_res.h_dl.has_value(); @@ -550,7 +534,7 @@ ue_fallback_scheduler::schedule_dl_conres_ce(ue& const bool is_retx = h_dl_retx.has_value(); // Search for empty HARQ. - if (not h_dl_retx.has_value() and not ue_pcell.harqs.has_empty_dl_harqs()) { + if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { logger.warning("rnti={}: UE must have empty HARQs during ConRes CE allocation", u.crnti); return {}; } @@ -716,14 +700,14 @@ ue_fallback_scheduler::schedule_dl_srb0(ue& u, const bool is_retx = h_dl_retx.has_value(); - ue_fallback_scheduler::sched_srb_results result{}; - // Search for empty HARQ. if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { logger.warning("rnti={}: UE must have empty HARQs during SRB0 PDU allocation", u.crnti); return {}; } + sched_srb_results result{}; + dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 @@ -921,7 +905,6 @@ ue_fallback_scheduler::schedule_dl_srb0(ue& u, ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_srb1(ue& u, - slot_point sched_ref_slot, cell_resource_allocator& res_alloc, unsigned pdsch_time_res, unsigned slot_offset, @@ -1671,7 +1654,7 @@ void ue_fallback_scheduler::store_harq_tx(du_ue_index_t }), "This UE and HARQ process were already in the list"); - ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl, ues, srb_payload_bytes, is_srb0); + ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl, srb_payload_bytes, is_srb0); } unsigned ue_fallback_scheduler::get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) const diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index fa92fe2e70..0d6ba51098 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -145,7 +145,6 @@ class ue_fallback_scheduler /// \remark This function handles the following scenarios: /// - Schedules SRB1 (not empty) + ConRes CE (if pending). sched_srb_results schedule_dl_srb1(ue& u, - slot_point sched_ref_slot, cell_resource_allocator& res_alloc, unsigned pdsch_time_res, unsigned slot_offset, @@ -209,7 +208,6 @@ class ue_fallback_scheduler public: explicit ack_and_retx_tracker(du_ue_index_t ue_idx, const std::optional& h_dl_, - ue_repository& ues_, unsigned srb_payload_bytes_, std::optional is_srb0_ = std::nullopt) : ue_index(ue_idx), is_srb0(is_srb0_), h_dl(h_dl_), srb1_payload_bytes(srb_payload_bytes_) diff --git a/tests/test_doubles/scheduler/scheduler_test_message_validators.cpp b/tests/test_doubles/scheduler/scheduler_test_message_validators.cpp index 1cad0128ce..9d91c7a59a 100644 --- a/tests/test_doubles/scheduler/scheduler_test_message_validators.cpp +++ b/tests/test_doubles/scheduler/scheduler_test_message_validators.cpp @@ -113,3 +113,16 @@ bool test_helper::is_valid_ul_sched_info(const ul_sched_info& grant) return true; } + +bool test_helper::is_valid_dl_msg_alloc_list(span grants) +{ + static_vector rntis; + for (const auto& grant : grants) { + // Ensure uniqueness of RNTI. + TRUE_OR_RETURN(std::count(rntis.begin(), rntis.end(), grant.pdsch_cfg.rnti) == 0, + "Duplicate RNTI in list of PDSCHs", + grant.pdsch_cfg.rnti); + rntis.push_back(grant.pdsch_cfg.rnti); + } + return true; +} diff --git a/tests/test_doubles/scheduler/scheduler_test_message_validators.h b/tests/test_doubles/scheduler/scheduler_test_message_validators.h index fe76f89c86..6bda2bc23d 100644 --- a/tests/test_doubles/scheduler/scheduler_test_message_validators.h +++ b/tests/test_doubles/scheduler/scheduler_test_message_validators.h @@ -25,5 +25,8 @@ bool is_valid_dl_msg_alloc(const dl_msg_alloc& grant); /// \brief Determine if the PUSCH grant for a given UE has valid content. bool is_valid_ul_sched_info(const ul_sched_info& grant); +/// \brief Determine if the UE PDSCH grants for a given slot are valid. +bool is_valid_dl_msg_alloc_list(span grants); + } // namespace test_helper } // namespace srsran diff --git a/tests/unittests/scheduler/test_utils/scheduler_test_suite.cpp b/tests/unittests/scheduler/test_utils/scheduler_test_suite.cpp index 233bd1bd6c..e323a6ec35 100644 --- a/tests/unittests/scheduler/test_utils/scheduler_test_suite.cpp +++ b/tests/unittests/scheduler/test_utils/scheduler_test_suite.cpp @@ -257,9 +257,7 @@ void srsran::test_pdsch_rar_consistency(const cell_configuration& cell_cfg, span void srsran::test_pdsch_ue_consistency(const cell_configuration& cell_cfg, span grants) { - for (const dl_msg_alloc& grant : grants) { - ASSERT_TRUE(test_helper::is_valid_dl_msg_alloc(grant)); - } + ASSERT_TRUE(test_helper::is_valid_dl_msg_alloc_list(grants)); } void srsran::test_pusch_ue_consistency(const cell_configuration& cell_cfg, span grants) From ce40e12a72c1bb6f597539a74da75d28232ff13c Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 4 Dec 2024 16:00:19 +0100 Subject: [PATCH 066/227] sched: refactor conres ce + srb0 allocation in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 235 +++++++++++++++++- .../ue_scheduling/ue_fallback_scheduler.h | 13 + 2 files changed, 244 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index ad1e8210b2..bc99184ad0 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -433,11 +433,11 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res sched_srb_results sched_res; if (not is_srb0.has_value()) { - sched_res = schedule_dl_conres_ce( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); + sched_res = alloc_grant( + u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx, is_srb0); } else if (is_srb0.value()) { - sched_res = schedule_dl_srb0( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); + sched_res = alloc_grant( + u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx, is_srb0); } else { sched_res = schedule_dl_srb1( u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); @@ -519,6 +519,233 @@ allocate_ue_fallback_pucch(ue& u, return std::make_pair(std::nullopt, last_valid_k1); } +ue_fallback_scheduler::sched_srb_results +ue_fallback_scheduler::alloc_grant(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx, + std::optional is_srb0) +{ + ue_cell& ue_pcell = u.get_pcell(); + const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; + const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); + const bool is_retx = h_dl_retx.has_value(); + + // Search for empty HARQ in case of newTx. + if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { + logger.warning("rnti={}: UE must have empty HARQs during ConRes CE allocation", u.crnti); + return {}; + } + + const dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); + const pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 + ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) + : get_pdsch_config_f1_0_c_rnti(cell_cfg, nullptr, pdsch_td_cfg); + + // For DCI 1-0 scrambled with TC-RNTI, as per TS 38.213, Section 7.3.1.2.1, we should consider the size of CORESET#0 + // as the size for the BWP. + // For DCI 1-0 scrambled with C-RNTI, if the DCI is monitored in a common search space and CORESET#0 is configured + // for the cell, as per TS 38.213, Section 7.3.1.0, we should consider the size of CORESET#0 as the size for the + // BWP. + cell_slot_resource_allocator& pdsch_alloc = res_alloc[slot_offset + pdsch_td_cfg.k0]; + auto cset0_crbs_lim = pdsch_helper::get_ra_crb_limits_common(cell_cfg.dl_cfg_common.init_dl_bwp, ss_cfg.get_id()); + prb_bitmap used_crbs = + pdsch_alloc.dl_res_grid.used_crbs(initial_active_dl_bwp.scs, cset0_crbs_lim, pdsch_cfg.symbols); + + crb_interval unused_crbs = + rb_helper::find_next_empty_interval(used_crbs, cset0_crbs_lim.start(), cset0_crbs_lim.stop()); + if (unused_crbs.empty()) { + logger.debug("rnti={}: Postponed PDU scheduling for slot={}. Cause: No space in PDSCH.", u.crnti, pdsch_alloc.slot); + // If there is no free PRBs left on this slot for this UE, then this slot should be avoided by the other UEs too. + slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; + return {}; + } + + crb_interval ue_grant_crbs; + sch_prbs_tbs prbs_tbs{}; + sch_mcs_index mcs_idx = 0; + bool pending_bytes_segmented = false; + if (is_retx) { + // Use the same MCS, nof PRBs and TBS as the last allocation. + mcs_idx = h_dl_retx->get_grant_params().mcs; + prbs_tbs.nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); + prbs_tbs.tbs_bytes = h_dl_retx->get_grant_params().tbs_bytes; + + if (unused_crbs.length() < prbs_tbs.nof_prbs) { + // In case of HARQ retxs, the number of RBs cannot change. + logger.debug("rnti={}: Fallback retx postponed. Cause: Not enough RBs for PDSCH", u.crnti); + return {}; + } + ue_grant_crbs = {unused_crbs.start(), unused_crbs.start() + prbs_tbs.nof_prbs}; + + } else { + const unsigned only_conres_bytes = u.pending_conres_ce_bytes(); + const unsigned only_srb0_bytes = u.pending_dl_newtx_bytes(LCID_SRB0); + const unsigned only_srb1_bytes = u.pending_dl_newtx_bytes(LCID_SRB1); + const unsigned pending_bytes = only_conres_bytes + only_srb0_bytes + only_srb1_bytes; + // There must be space for ConRes CE, if it is pending. If only SRB0 is pending, there must be space for it, as it + // cannot be segmented. + const unsigned min_pending_bytes = + only_conres_bytes > 0 ? only_conres_bytes : (only_srb0_bytes > 0 ? only_srb0_bytes : 0); + srsran_assert(pending_bytes > 0, "Unexpected number of pending bytes"); + + std::tuple result = + select_mcs(pdsch_cfg, pending_bytes, unused_crbs.length()); + unsigned chosen_tbs = std::get<2>(result).value(); + if (chosen_tbs < min_pending_bytes) { + // We could not even fulfill the minimum pending bytes. + logger.debug( + "rnti={}: Postpone fallback allocation. Cause: Pending non-segmentable bytes exceed TBS calculated ({})", + u.crnti, + min_pending_bytes, + chosen_tbs); + if (only_conres_bytes > 0) { + // In case not even a ConRes CE can fit, we can start ignoring this slot. + slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; + } + return {}; + } + if (chosen_tbs < pending_bytes) { + // We will need to break down the pending bytes in multiple grants. + if (only_conres_bytes > 0 and only_srb0_bytes > 0) { + // In case of both ConResCE and SRB0 are pending, we recompute the MCS, this time, just for scheduling ConRes + // CE. + result = select_mcs(pdsch_cfg, min_pending_bytes, unused_crbs.length()); + chosen_tbs = std::get<2>(result).value(); + srsran_assert(chosen_tbs >= min_pending_bytes, "Unexpected result for TBS"); + } + pending_bytes_segmented = true; + } + + // Selection of Nof RBs, TBS and MCS complete. + prbs_tbs = {std::get<0>(result), std::get<2>(result).value()}; + mcs_idx = std::get<1>(result); + ue_grant_crbs = {unused_crbs.start(), unused_crbs.start() + prbs_tbs.nof_prbs}; + } + + // Allocate PDCCH resources. + cell_slot_resource_allocator& pdcch_alloc = res_alloc[slot_offset]; + pdcch_dl_information* pdcch = + pdcch_sch.alloc_dl_pdcch_common(pdcch_alloc, u.crnti, ss_cfg.get_id(), aggregation_level::n4); + if (pdcch == nullptr) { + logger.debug("rnti={}: Postponed PDU scheduling for slot={}. Cause: No space in PDCCH.", u.crnti, pdcch_alloc.slot); + // If there is no PDCCH space on this slot for this UE, then this slot should be avoided by the other UEs too. + slots_with_no_pdxch_space[pdcch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; + return {}; + } + + // Allocate PUCCH resources. + // NOTEs: + // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) + // could have a complete configuration; if so, (i) the UCI scheduler can start allocating SRs and CSIs in advance, as + // the scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs; (ii) if the actual UE has + // received the RRCSetup (with configuration) but the GNB doesn't receive an ACK = 1, the UE can use the PUCCH + // dedicated resource to ack the RRCSetup retx (as per TS 38.213, Section 9.2.1, "If a UE has dedicated PUCCH resource + // configuration, the UE is provided by higher layers with one or more PUCCH resources [...]"). + // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), + // don't use the PUCCH ded. resources. + const bool use_common_and_ded_res = + u.ue_cfg_dedicated()->is_ue_cfg_complete() and (is_retx or dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0); + // TODO: Fix use_common_and_ded_res check + auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, + res_alloc, + pucch_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common_and_ded_res); + if (not pucch_res_indicator.has_value()) { + if (chosen_k1.has_value()) { + // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. + logger.debug("rnti={}: Failed to allocate fallback PDSCH for slot={}. Cause: No space in PUCCH", + u.crnti, + pdsch_alloc.slot); + } + pdcch_sch.cancel_last_pdcch(pdcch_alloc); + slots_with_no_pdxch_space[pdcch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; + return {}; + } + + // Mark resources as occupied in the ResourceGrid. + pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); + + // Update DRX controller state. + u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); + + // Fill ConRes and/or SRB grant. + auto [nof_srb1_scheduled_bytes, h_dl] = fill_dl_srb_grant(u, + pdsch_alloc.slot, + h_dl_retx, + *pdcch, + dci_type, + pdsch_alloc.result.dl.ue_grants.emplace_back(), + pucch_res_indicator.value(), + pdsch_time_res, + chosen_k1.value(), + mcs_idx, + ue_grant_crbs, + pdsch_cfg, + prbs_tbs.tbs_bytes, + is_retx, + is_srb0); + + return sched_srb_results{.h_dl = h_dl, + .is_srb_data_pending = pending_bytes_segmented, + .nof_srb1_scheduled_bytes = nof_srb1_scheduled_bytes}; +} + +std::tuple +ue_fallback_scheduler::select_mcs(const pdsch_config_params& pdsch_cfg, + unsigned pending_bytes, + unsigned nof_rbs_available) +{ + sch_mcs_index chosen_mcs_idx = 0; + sch_prbs_tbs prbs_tbs{}; + + unsigned nof_dmrs_per_rb = calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs); + + // Try to find least MCS to fit PDU. + sch_mcs_index next_mcs_idx = 0; + do { + // As per TS 38.214, clause 5.1.3.1, if the PDSCH is scheduled by a PDCCH with CRC scrambled by TC-RNTI, the UE + // use "Table 5.1.3.1-1: MCS index table 1" for MCS mapping. This is not stated explicitly, but can be inferred + // from the sentence "... the UE shall use I_MCS and Table 5.1.3.1-1 to determine the modulation order (Qm) and + // Target code rate (R) used in the physical downlink shared channel.". + + // At this point, xOverhead is not configured yet. As per TS 38.214, Clause 5.1.3.2, xOverhead is assumed to be + // 0. + const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_mcs_table::qam64, next_mcs_idx); + prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, + pdsch_cfg.symbols.length(), + nof_dmrs_per_rb, + pdsch_cfg.nof_oh_prb, + mcs_config, + pdsch_cfg.nof_layers}); + chosen_mcs_idx = next_mcs_idx; + ++next_mcs_idx; + } while (next_mcs_idx <= expert_cfg.max_msg4_mcs and nof_rbs_available < prbs_tbs.nof_prbs); + + if (prbs_tbs.nof_prbs > nof_rbs_available) { + // Could not find an MCS for which pending bytes < TBS, given nof_rbs_available. In this case, we just compute + // the TBS for nof_rbs=nof_rbs_available and mcs=max_msg4_mcs. + + tbs_calculator_configuration tbs_cfg{pdsch_cfg.symbols.length(), + nof_dmrs_per_rb, + pdsch_cfg.nof_oh_prb, + pdsch_mcs_get_config(pdsch_mcs_table::qam64, expert_cfg.max_msg4_mcs), + pdsch_cfg.nof_layers, + pdsch_cfg.tb_scaling_field, + nof_rbs_available}; + unsigned tbs_bits = tbs_calculator_calculate(tbs_cfg); + return std::make_tuple(nof_rbs_available, expert_cfg.max_msg4_mcs, units::bits{tbs_bits}.round_up_to_bytes()); + } + + return std::make_tuple(prbs_tbs.nof_prbs, chosen_mcs_idx, units::bytes{prbs_tbs.tbs_bytes}); +} + ue_fallback_scheduler::sched_srb_results ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, cell_resource_allocator& res_alloc, diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 0d6ba51098..d4a1fd4111 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -117,6 +117,19 @@ class ue_fallback_scheduler unsigned nof_srb1_scheduled_bytes = 0; }; + /// \brief For a number of pending bytes, select the appropriate MCS. + std::tuple + select_mcs(const pdsch_config_params& pdsch_cfg, unsigned pending_bytes, unsigned nof_rbs_available); + + /// \brief Allocate DL grant for a UE and for a specific PDSCH slot. + sched_srb_results alloc_grant(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx, + std::optional is_srb0); + /// \brief Tries to schedule DL ConRes CE for a UE and for a specific PDSCH slot. /// \remark This function handles the following scenarios: /// - Schedules ConRes CE only if ConRes indication is received from MAC but no buffer status update is received From 8d63d5a130556b849aab67b64bc6ce2b36048836 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 4 Dec 2024 17:39:40 +0100 Subject: [PATCH 067/227] sched: use same method for srb0, conres and srb1 allocation in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 721 +++--------------- .../ue_scheduling/ue_fallback_scheduler.h | 40 +- 2 files changed, 89 insertions(+), 672 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index bc99184ad0..c539e27235 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -431,17 +431,8 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res most_recent_ack_slot = last_slot_ack; } - sched_srb_results sched_res; - if (not is_srb0.has_value()) { - sched_res = alloc_grant( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx, is_srb0); - } else if (is_srb0.value()) { - sched_res = alloc_grant( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx, is_srb0); - } else { - sched_res = schedule_dl_srb1( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); - } + sched_srb_results sched_res = alloc_grant( + u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx, is_srb0); const bool alloc_successful = sched_res.h_dl.has_value(); if (alloc_successful) { @@ -582,18 +573,27 @@ ue_fallback_scheduler::alloc_grant(ue& u, } else { const unsigned only_conres_bytes = u.pending_conres_ce_bytes(); - const unsigned only_srb0_bytes = u.pending_dl_newtx_bytes(LCID_SRB0); - const unsigned only_srb1_bytes = u.pending_dl_newtx_bytes(LCID_SRB1); - const unsigned pending_bytes = only_conres_bytes + only_srb0_bytes + only_srb1_bytes; - // There must be space for ConRes CE, if it is pending. If only SRB0 is pending, there must be space for it, as it - // cannot be segmented. + const unsigned only_srb0_bytes = is_srb0.has_value() and is_srb0.value() ? u.pending_dl_newtx_bytes(LCID_SRB0) : 0; + unsigned pending_bytes = only_conres_bytes + only_srb0_bytes; + std::optional fixed_mcs; + if (is_srb0.has_value() and not is_srb0.value()) { + pending_bytes = std::max(pending_bytes, get_srb1_pending_tot_bytes(u.ue_index)); + fixed_mcs = map_cqi_to_mcs(expert_cfg.initial_cqi, pdsch_cfg.mcs_table); + srsran_assert(fixed_mcs.has_value(), "Invalid Initial CQI {}", expert_cfg.initial_cqi); + } + srsran_assert(pending_bytes > 0, "Unexpected number of pending bytes"); + // There must be space for ConRes CE, if it is pending. If only SRB0 is pending (no ConRes), there must be space + // for it, as the SRB0 cannot be segmented. const unsigned min_pending_bytes = only_conres_bytes > 0 ? only_conres_bytes : (only_srb0_bytes > 0 ? only_srb0_bytes : 0); - srsran_assert(pending_bytes > 0, "Unexpected number of pending bytes"); std::tuple result = - select_mcs(pdsch_cfg, pending_bytes, unused_crbs.length()); + select_tbs(pdsch_cfg, pending_bytes, unused_crbs, fixed_mcs); unsigned chosen_tbs = std::get<2>(result).value(); + if (chosen_tbs == 0) { + logger.error("rnti={}: Unable to compute TBS for fallback allocation", u.crnti); + return {}; + } if (chosen_tbs < min_pending_bytes) { // We could not even fulfill the minimum pending bytes. logger.debug( @@ -612,9 +612,12 @@ ue_fallback_scheduler::alloc_grant(ue& u, if (only_conres_bytes > 0 and only_srb0_bytes > 0) { // In case of both ConResCE and SRB0 are pending, we recompute the MCS, this time, just for scheduling ConRes // CE. - result = select_mcs(pdsch_cfg, min_pending_bytes, unused_crbs.length()); + result = select_tbs(pdsch_cfg, min_pending_bytes, unused_crbs, std::nullopt); chosen_tbs = std::get<2>(result).value(); - srsran_assert(chosen_tbs >= min_pending_bytes, "Unexpected result for TBS"); + if (chosen_tbs == 0) { + logger.error("rnti={}: Unable to compute TBS for fallback allocation", u.crnti); + return {}; + } } pending_bytes_segmented = true; } @@ -647,7 +650,8 @@ ue_fallback_scheduler::alloc_grant(ue& u, // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), // don't use the PUCCH ded. resources. const bool use_common_and_ded_res = - u.ue_cfg_dedicated()->is_ue_cfg_complete() and (is_retx or dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0); + u.ue_cfg_dedicated()->is_ue_cfg_complete() and + (is_retx or (is_srb0.has_value() and not is_srb0.value() and dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0)); // TODO: Fix use_common_and_ded_res check auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, res_alloc, @@ -698,292 +702,70 @@ ue_fallback_scheduler::alloc_grant(ue& u, } std::tuple -ue_fallback_scheduler::select_mcs(const pdsch_config_params& pdsch_cfg, - unsigned pending_bytes, - unsigned nof_rbs_available) +ue_fallback_scheduler::select_tbs(const pdsch_config_params& pdsch_cfg, + unsigned pending_bytes, + const crb_interval& unused_crbs, + const std::optional& fixed_mcs) const { - sch_mcs_index chosen_mcs_idx = 0; - sch_prbs_tbs prbs_tbs{}; + sch_mcs_index chosen_mcs_idx = 0; + sch_prbs_tbs prbs_tbs{}; + const unsigned nof_dmrs_per_rb = calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs); - unsigned nof_dmrs_per_rb = calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs); + if (fixed_mcs.has_value()) { + // For the case where the MCS is already selected. - // Try to find least MCS to fit PDU. - sch_mcs_index next_mcs_idx = 0; - do { - // As per TS 38.214, clause 5.1.3.1, if the PDSCH is scheduled by a PDCCH with CRC scrambled by TC-RNTI, the UE - // use "Table 5.1.3.1-1: MCS index table 1" for MCS mapping. This is not stated explicitly, but can be inferred - // from the sentence "... the UE shall use I_MCS and Table 5.1.3.1-1 to determine the modulation order (Qm) and - // Target code rate (R) used in the physical downlink shared channel.". - - // At this point, xOverhead is not configured yet. As per TS 38.214, Clause 5.1.3.2, xOverhead is assumed to be - // 0. - const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_mcs_table::qam64, next_mcs_idx); + chosen_mcs_idx = *fixed_mcs; + const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_cfg.mcs_table, *fixed_mcs); prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, pdsch_cfg.symbols.length(), nof_dmrs_per_rb, pdsch_cfg.nof_oh_prb, mcs_config, - pdsch_cfg.nof_layers}); - chosen_mcs_idx = next_mcs_idx; - ++next_mcs_idx; - } while (next_mcs_idx <= expert_cfg.max_msg4_mcs and nof_rbs_available < prbs_tbs.nof_prbs); - - if (prbs_tbs.nof_prbs > nof_rbs_available) { - // Could not find an MCS for which pending bytes < TBS, given nof_rbs_available. In this case, we just compute - // the TBS for nof_rbs=nof_rbs_available and mcs=max_msg4_mcs. - - tbs_calculator_configuration tbs_cfg{pdsch_cfg.symbols.length(), - nof_dmrs_per_rb, - pdsch_cfg.nof_oh_prb, - pdsch_mcs_get_config(pdsch_mcs_table::qam64, expert_cfg.max_msg4_mcs), - pdsch_cfg.nof_layers, - pdsch_cfg.tb_scaling_field, - nof_rbs_available}; - unsigned tbs_bits = tbs_calculator_calculate(tbs_cfg); - return std::make_tuple(nof_rbs_available, expert_cfg.max_msg4_mcs, units::bits{tbs_bits}.round_up_to_bytes()); - } - - return std::make_tuple(prbs_tbs.nof_prbs, chosen_mcs_idx, units::bytes{prbs_tbs.tbs_bytes}); -} - -ue_fallback_scheduler::sched_srb_results -ue_fallback_scheduler::schedule_dl_conres_ce(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx) -{ - ue_cell& ue_pcell = u.get_pcell(); - const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; - const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); - - const bool is_retx = h_dl_retx.has_value(); - - // Search for empty HARQ. - if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { - logger.warning("rnti={}: UE must have empty HARQs during ConRes CE allocation", u.crnti); - return {}; - } - - dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); - srsran_assert(dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0, - "Only DCI 1_0 with TC-RNTI is supported for ConRes CE scheduling"); - - pdsch_config_params pdsch_cfg = get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg); - - cell_slot_resource_allocator& pdsch_alloc = res_alloc[slot_offset + pdsch_td_cfg.k0]; - auto cset0_crbs_lim = pdsch_helper::get_ra_crb_limits_common(cell_cfg.dl_cfg_common.init_dl_bwp, ss_cfg.get_id()); - prb_bitmap used_crbs = - pdsch_alloc.dl_res_grid.used_crbs(initial_active_dl_bwp.scs, cset0_crbs_lim, pdsch_cfg.symbols); - - sch_prbs_tbs prbs_tbs{}; - sch_mcs_index mcs_idx = 0; - if (is_retx) { - // Use the same MCS, nof PRBs and TBS as the last allocation. - mcs_idx = h_dl_retx->get_grant_params().mcs; - prbs_tbs.nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); - prbs_tbs.tbs_bytes = h_dl_retx->get_grant_params().tbs_bytes; - } else { - // Fetch the pending MAC Contention Resolution CEs bytes. - const unsigned pending_bytes = u.pending_conres_ce_bytes(); - - crb_interval unused_crbs = - rb_helper::find_next_empty_interval(used_crbs, cset0_crbs_lim.start(), cset0_crbs_lim.stop()); + pdsch_cfg.nof_layers}, + unused_crbs.length()); - if (unused_crbs.empty()) { - logger.debug( - "rnti={}: Postponed ConRes CE scheduling for slot {}. Cause: No space in PDSCH.", u.crnti, pdsch_alloc.slot); - // If there is no free PRBs left on this slot for this UE, then this slot should be avoided by the other UEs - // too. - slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - return {}; - } - - // Try to find least MCS to fit ConRes CE. - while (mcs_idx <= expert_cfg.max_msg4_mcs) { - // As per TS 38.214, clause 5.1.3.1, if the PDSCH is scheduled by a PDCCH with CRC scrambled by TC-RNTI, the UE - // use "Table 5.1.3.1-1: MCS index table 1" for MCS mapping. This is not stated explicitly, but can be inferred - // from the sentence "... the UE shall use I_MCS and Table 5.1.3.1-1 to determine the modulation order (Qm) and - // Target code rate (R) used in the physical downlink shared channel.". - - // At this point, xOverhead is not configured yet. As per TS 38.214, Clause 5.1.3.2, xOverhead is assumed to be - // 0. - const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_mcs_table::qam64, mcs_idx); - prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, - static_cast(pdsch_cfg.symbols.length()), - calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), - pdsch_cfg.nof_oh_prb, - mcs_config, - pdsch_cfg.nof_layers}); - if (unused_crbs.length() >= prbs_tbs.nof_prbs) { - break; + // [Implementation-defined] In case of partial slots and nof. PRBs allocated equals to 1 probability of KO is + // high due to code not being able to cope with interference. So the solution is to increase the PRB allocation + // to greater than 1 PRB. + const bool set_min_nof_prbs = + prbs_tbs.nof_prbs == 1 and pdsch_cfg.symbols.length() < NOF_OFDM_SYM_PER_SLOT_NORMAL_CP; + if (set_min_nof_prbs) { + if (unused_crbs.length() <= 1) { + return std::make_tuple(0, *fixed_mcs, units::bytes{0}); } - ++mcs_idx; - } - - if (prbs_tbs.tbs_bytes < pending_bytes) { - logger.debug( - "rnti={}: ConRes CE size ({}) exceeds TBS calculated ({})", pending_bytes, prbs_tbs.tbs_bytes, u.crnti); - return {}; + prbs_tbs.nof_prbs = 2; + tbs_calculator_configuration tbs_cfg{pdsch_cfg.symbols.length(), + nof_dmrs_per_rb, + pdsch_cfg.nof_oh_prb, + pdsch_mcs_get_config(pdsch_cfg.mcs_table, chosen_mcs_idx), + pdsch_cfg.nof_layers, + pdsch_cfg.tb_scaling_field, + prbs_tbs.nof_prbs}; + prbs_tbs.tbs_bytes = units::bits{tbs_calculator_calculate(tbs_cfg)}.round_up_to_bytes().value(); } - if (mcs_idx > expert_cfg.max_msg4_mcs) { - logger.debug( - "rnti={}: Postponing ConRes CE allocation. Cause: MCS index chosen ({}) for ConRes CE exceeds maximum" - " allowed MCS index ({})", - u.crnti, - mcs_idx, - expert_cfg.max_msg4_mcs); - return {}; + // As \c txDirectCurrentLocation, in \c SCS-SpecificCarrier, TS 38.331, "If this field (\c + // txDirectCurrentLocation) is absent for downlink within ServingCellConfigCommon and ServingCellConfigCommonSIB, + // the UE assumes the default value of 3300 (i.e. "Outside the carrier")". + crb_interval grant_crbs{unused_crbs.start(), unused_crbs.start() + prbs_tbs.nof_prbs}; + bool contains_dc = false; + if (cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.has_value()) { + contains_dc = dc_offset_helper::is_contained( + cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.value(), grant_crbs); } - } - - crb_interval ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, prbs_tbs.nof_prbs, 0); - if (ue_grant_crbs.length() < prbs_tbs.nof_prbs) { - logger.debug("rnti={}: Postponed ConRes CE scheduling. Cause: Not enough PRBs ({} < {})", - u.crnti, - ue_grant_crbs.length(), - prbs_tbs.nof_prbs); - return {}; - } - - // Allocate PDCCH resources. - cell_slot_resource_allocator& pdcch_alloc = res_alloc[slot_offset]; - pdcch_dl_information* pdcch = - pdcch_sch.alloc_dl_pdcch_common(pdcch_alloc, u.crnti, ss_cfg.get_id(), aggregation_level::n4); - if (pdcch == nullptr) { - logger.debug( - "rnti={}: Postponed ConRes CE scheduling for slot={}. Cause: No space in PDCCH.", u.crnti, pdsch_alloc.slot); - // If there is no PDCCH space on this slot for this UE, then this slot should be avoided by the other UEs too. - slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - return {}; - } - - // Allocate PUCCH resources. - // NOTEs: - // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) - // could have a complete configuration; if so, the UCI scheduler can start allocating SRs and CSIs in advance, as the - // scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs. - // - If the UE object in the scheduler doesn't have a complete configuration, don't use the PUCCH ded. resources. - const bool use_common_and_ded_res = is_retx and u.ue_cfg_dedicated()->is_ue_cfg_complete(); - auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, - res_alloc, - pucch_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common_and_ded_res); - - if (not pucch_res_indicator.has_value()) { - if (chosen_k1.has_value()) { - // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. - logger.debug("rnti={}: Failed to allocate PDSCH for ConRes CE for slot={}. Cause: No space in PUCCH", - u.crnti, - pdsch_alloc.slot); + std::optional mcs_tbs = compute_dl_mcs_tbs(pdsch_cfg, chosen_mcs_idx, prbs_tbs.nof_prbs, contains_dc); + if (mcs_tbs.has_value()) { + chosen_mcs_idx = mcs_tbs.value().mcs; + prbs_tbs.tbs_bytes = mcs_tbs.value().tbs; + } else { + return std::make_tuple(0, *fixed_mcs, units::bytes{0}); } - pdcch_sch.cancel_last_pdcch(pdcch_alloc); - return {}; - } - - // Mark resources as occupied in the Resource grid. - pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); - - // Update DRX controller state. - u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); - - auto result = fill_dl_srb_grant(u, - pdsch_alloc.slot, - h_dl_retx, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - mcs_idx, - ue_grant_crbs, - pdsch_cfg, - prbs_tbs.tbs_bytes, - is_retx, - std::nullopt); - - // No need to pass the nof SRB scheduled bytes. - return sched_srb_results{.h_dl = result.second}; -} - -ue_fallback_scheduler::sched_srb_results -ue_fallback_scheduler::schedule_dl_srb0(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx) -{ - ue_cell& ue_pcell = u.get_pcell(); - const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; - const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); - - const bool is_retx = h_dl_retx.has_value(); - - // Search for empty HARQ. - if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { - logger.warning("rnti={}: UE must have empty HARQs during SRB0 PDU allocation", u.crnti); - return {}; - } - - sched_srb_results result{}; - - dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); - - pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 - ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) - : get_pdsch_config_f1_0_c_rnti(cell_cfg, nullptr, pdsch_td_cfg); - - // For DCI 1-0 scrambled with TC-RNTI, as per TS 38.213, Section 7.3.1.2.1, we should consider the size of CORESET#0 - // as the size for the BWP. - // For DCI 1-0 scrambled with C-RNTI, if the DCI is monitored in a common search space and CORESET#0 is configured - // for the cell, as per TS 38.213, Section 7.3.1.0, we should consider the size of CORESET#0 as the size for the - // BWP. - cell_slot_resource_allocator& pdsch_alloc = res_alloc[slot_offset + pdsch_td_cfg.k0]; - auto cset0_crbs_lim = pdsch_helper::get_ra_crb_limits_common(cell_cfg.dl_cfg_common.init_dl_bwp, ss_cfg.get_id()); - prb_bitmap used_crbs = - pdsch_alloc.dl_res_grid.used_crbs(initial_active_dl_bwp.scs, cset0_crbs_lim, pdsch_cfg.symbols); - - sch_prbs_tbs prbs_tbs{}; - sch_mcs_index mcs_idx = 0; - if (is_retx) { - // Use the same MCS, nof PRBs and TBS as the last allocation. - mcs_idx = h_dl_retx->get_grant_params().mcs; - prbs_tbs.nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); - prbs_tbs.tbs_bytes = h_dl_retx->get_grant_params().tbs_bytes; } else { - // Required PRBs and TBS information for scheduling only ConRes CE in case PDSCH does not have enough space to - // accommodate ConRes CE + SRB0. - sch_prbs_tbs only_conres_prbs_tbs{}; - // MCS index to use for scheduling only ConRes CE in case PDSCH does not have enough space to accommodate ConRes CE - // + SRB0. - std::optional only_conres_mcs_idx; - - // Fetch the pending bytes. - const unsigned only_conres_pending_bytes = u.pending_conres_ce_bytes(); - unsigned pending_bytes = u.pending_dl_newtx_bytes(LCID_SRB0) + only_conres_pending_bytes; + // Dynamic MCS (without CQI) - crb_interval unused_crbs = - rb_helper::find_next_empty_interval(used_crbs, cset0_crbs_lim.start(), cset0_crbs_lim.stop()); - - if (unused_crbs.empty()) { - logger.debug( - "rnti={}: Postponed SRB0 PDU scheduling for slot {}. Cause: No space in PDSCH.", u.crnti, pdsch_alloc.slot); - // If there is no free PRBs left on this slot for this UE, then this slot should be avoided by the other UEs - // too. - slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - return {}; - } - - // Try to find least MCS to fit SRB0 message. - while (mcs_idx <= expert_cfg.max_msg4_mcs) { + // Try to find lowest MCS to fit pending bytes. + sch_mcs_index next_mcs_idx = 0; + do { // As per TS 38.214, clause 5.1.3.1, if the PDSCH is scheduled by a PDCCH with CRC scrambled by TC-RNTI, the UE // use "Table 5.1.3.1-1: MCS index table 1" for MCS mapping. This is not stated explicitly, but can be inferred // from the sentence "... the UE shall use I_MCS and Table 5.1.3.1-1 to determine the modulation order (Qm) and @@ -991,357 +773,24 @@ ue_fallback_scheduler::schedule_dl_srb0(ue& u, // At this point, xOverhead is not configured yet. As per TS 38.214, Clause 5.1.3.2, xOverhead is assumed to be // 0. - const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_mcs_table::qam64, mcs_idx); + const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_mcs_table::qam64, next_mcs_idx); prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, - static_cast(pdsch_cfg.symbols.length()), - calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), + pdsch_cfg.symbols.length(), + nof_dmrs_per_rb, pdsch_cfg.nof_oh_prb, mcs_config, - pdsch_cfg.nof_layers}); - // If MCS index to use to schedule only ConRes CE is not set compute required PRBs and TBS information. - // NOTE: The \c only_conres_prbs_tbs and \c only_conres_mcs_idx is used in case PDSCH does not have enough space - // to accommodate ConRes CE + SRB0. - if (u.is_conres_ce_pending() and not only_conres_mcs_idx.has_value()) { - only_conres_prbs_tbs = - get_nof_prbs(prbs_calculator_sch_config{only_conres_pending_bytes, - static_cast(pdsch_cfg.symbols.length()), - calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), - pdsch_cfg.nof_oh_prb, - mcs_config, - pdsch_cfg.nof_layers}); - if (unused_crbs.length() >= only_conres_prbs_tbs.nof_prbs) { - only_conres_mcs_idx = mcs_idx; - } - } - - if (unused_crbs.length() >= prbs_tbs.nof_prbs) { - break; - } - ++mcs_idx; - } - - crb_interval ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, prbs_tbs.nof_prbs, 0); - - // Check whether SRB0 can be scheduled along with ConRes CE or not. - if (u.is_conres_ce_pending() and (prbs_tbs.tbs_bytes < pending_bytes or mcs_idx > expert_cfg.max_msg4_mcs or - ue_grant_crbs.length() < prbs_tbs.nof_prbs)) { - // Schedule only ConRes CE. - result.is_srb_data_pending = true; - prbs_tbs = only_conres_prbs_tbs; - mcs_idx = only_conres_mcs_idx.value(); - pending_bytes = only_conres_pending_bytes; - } - - if (prbs_tbs.tbs_bytes < pending_bytes) { - logger.debug( - "rnti={}: SRB0 PDU size ({}) exceeds TBS calculated ({})", pending_bytes, prbs_tbs.tbs_bytes, u.crnti); - return {}; - } - - if (mcs_idx > expert_cfg.max_msg4_mcs) { - logger.debug("rnti={}: Postponing SRB0 PDU allocation. Cause: MCS index chosen ({}) for SRB0 exceeds maximum" - " allowed MCS index ({})", - u.crnti, - mcs_idx, - expert_cfg.max_msg4_mcs); - return {}; - } - } - - crb_interval ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, prbs_tbs.nof_prbs, 0); - if (ue_grant_crbs.length() < prbs_tbs.nof_prbs) { - logger.debug("rnti={}: Postponed SRB0 PDU scheduling. Cause: Not enough PRBs ({} < {})", - u.crnti, - ue_grant_crbs.length(), - prbs_tbs.nof_prbs); - return {}; - } - - // Allocate PDCCH resources. - cell_slot_resource_allocator& pdcch_alloc = res_alloc[slot_offset]; - pdcch_dl_information* pdcch = - pdcch_sch.alloc_dl_pdcch_common(pdcch_alloc, u.crnti, ss_cfg.get_id(), aggregation_level::n4); - if (pdcch == nullptr) { - logger.debug( - "rnti={}: Postponed SRB0 PDU scheduling for slot={}. Cause: No space in PDCCH.", u.crnti, pdsch_alloc.slot); - // If there is no PDCCH space on this slot for this UE, then this slot should be avoided by the other UEs too. - slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - return {}; + pdsch_cfg.nof_layers}, + unused_crbs.length()); + chosen_mcs_idx = next_mcs_idx; + ++next_mcs_idx; + } while (next_mcs_idx <= expert_cfg.max_msg4_mcs and prbs_tbs.tbs_bytes < pending_bytes); } - // Allocate PUCCH resources. - // NOTEs: - // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) - // could have a complete configuration; if so, (i) the UCI scheduler can start allocating SRs and CSIs in advance, as - // the scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs; (ii) if the actual UE has - // received the RRCSetup (with configuration) but the GNB doesn't receive an ACK = 1, the UE can use the PUCCH - // dedicated resource to ack the RRCSetup retx (as per TS 38.213, Section 9.2.1, "If a UE has dedicated PUCCH resource - // configuration, the UE is provided by higher layers with one or more PUCCH resources [...]"). - // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), - // don't use the PUCCH ded. resources. - const bool use_common_and_ded_res = is_retx and u.ue_cfg_dedicated()->is_ue_cfg_complete(); - auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, - res_alloc, - pucch_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common_and_ded_res); - if (not pucch_res_indicator.has_value()) { - if (chosen_k1.has_value()) { - // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. - logger.debug("rnti={}: Failed to allocate PDSCH for SRB0 for slot={}. Cause: No space in PUCCH", - u.crnti, - pdsch_alloc.slot); - } - pdcch_sch.cancel_last_pdcch(pdcch_alloc); - return {}; + if (prbs_tbs.nof_prbs == 0) { + // No found solution found. + return std::make_tuple(0, *fixed_mcs, units::bytes{0}); } - - // Mark resources as occupied in the ResourceGrid. - pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); - - // Update DRX controller state. - u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); - - std::optional is_srb0; - if (not result.is_srb_data_pending) { - is_srb0 = true; - } - auto outcome = fill_dl_srb_grant(u, - pdsch_alloc.slot, - h_dl_retx, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - mcs_idx, - ue_grant_crbs, - pdsch_cfg, - prbs_tbs.tbs_bytes, - is_retx, - is_srb0); - - // No need to pass the nof SRB scheduled bytes with SRB0. - result.h_dl = outcome.second; - return result; -} - -ue_fallback_scheduler::sched_srb_results -ue_fallback_scheduler::schedule_dl_srb1(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx) -{ - ue_cell& ue_pcell = u.get_pcell(); - const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; - const pdsch_time_domain_resource_allocation& pdsch_td_cfg = get_pdsch_td_cfg(pdsch_time_res); - - const bool is_retx = h_dl_retx.has_value(); - - // Search for empty HARQ. - if (not h_dl_retx.has_value() and not ue_pcell.harqs.has_empty_dl_harqs()) { - return {}; - } - - dci_dl_rnti_config_type dci_type = get_dci_type(u, h_dl_retx); - - pdsch_config_params pdsch_cfg = dci_type == dci_dl_rnti_config_type::tc_rnti_f1_0 - ? get_pdsch_config_f1_0_tc_rnti(cell_cfg, pdsch_td_cfg) - : get_pdsch_config_f1_0_c_rnti(cell_cfg, nullptr, pdsch_td_cfg); - - // For DCI 1-0 scrambled with TC-RNTI, as per TS 38.213, Section 7.3.1.2.1, we should consider the size of CORESET#0 - // as the size for the BWP. - // For DCI 1-0 scrambled with C-RNTI, if the DCI is monitored in a common search space and CORESET#0 is configured - // for the cell, as per TS 38.213, Section 7.3.1.0, we should consider the size of CORESET#0 as the size for the - // BWP. - cell_slot_resource_allocator& pdsch_alloc = res_alloc[slot_offset + pdsch_td_cfg.k0]; - prb_bitmap used_crbs = pdsch_alloc.dl_res_grid.used_crbs( - initial_active_dl_bwp.scs, - pdsch_helper::get_ra_crb_limits_common(cell_cfg.dl_cfg_common.init_dl_bwp, ss_cfg.get_id()), - pdsch_cfg.symbols); - - crb_interval ue_grant_crbs; - sch_mcs_tbs final_mcs_tbs; - - // Check if there is space on the PDSCH, and if not, skip this slot. - auto cset0_crbs_lim = pdsch_helper::get_ra_crb_limits_common(cell_cfg.dl_cfg_common.init_dl_bwp, ss_cfg.get_id()); - crb_interval unused_crbs = - rb_helper::find_next_empty_interval(used_crbs, cset0_crbs_lim.start(), cset0_crbs_lim.stop()); - - if (unused_crbs.empty()) { - logger.debug( - "rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: No space in PDSCH.", u.crnti, pdsch_alloc.slot); - // If there is no free PRBs left on this slot for this UE, then this slot should be avoided by the other UEs too. - slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - return {}; - } - - const bool is_srb0 = false; - if (is_retx) { - const unsigned final_nof_prbs = h_dl_retx->get_grant_params().rbs.type1().length(); - final_mcs_tbs.mcs = h_dl_retx->get_grant_params().mcs; - final_mcs_tbs.tbs = h_dl_retx->get_grant_params().tbs_bytes; - - ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, final_nof_prbs, 0); - if (ue_grant_crbs.empty() or ue_grant_crbs.length() < final_nof_prbs) { - return {}; - } - - } else { - // Find available symbol x RB resources. - const unsigned pending_bytes = get_srb1_pending_tot_bytes(u.ue_index); - - // Fallback scheduler should always work with initial CQI and not rely on CSI reported by UE since UE may not have - // received the configuration to report CSI. - std::optional mcs_idx = map_cqi_to_mcs(expert_cfg.initial_cqi, pdsch_cfg.mcs_table); - if (not mcs_idx.has_value()) { - logger.warning("ue={} rnti={}: Failed to schedule SRB1 PDU for slot={}. Cause: No valid MCS found for CQI={}.", - u.ue_index, - u.crnti, - pdsch_alloc.slot, - expert_cfg.initial_cqi); - return {}; - } - const sch_mcs_description mcs_config = pdsch_mcs_get_config(pdsch_cfg.mcs_table, *mcs_idx); - sch_prbs_tbs prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, - static_cast(pdsch_cfg.symbols.length()), - calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), - pdsch_cfg.nof_oh_prb, - mcs_config, - pdsch_cfg.nof_layers}); - if (prbs_tbs.nof_prbs == 0) { - return {}; - } - grant_prbs_mcs mcs_prbs_estimate{.mcs = *mcs_idx, .n_prbs = prbs_tbs.nof_prbs}; - - // [Implementation-defined] In case of partial slots and nof. PRBs allocated equals to 1 probability of KO is - // high due to code not being able to cope with interference. So the solution is to increase the PRB allocation - // to greater than 1 PRB. - const bool set_min_nof_prbs = not cell_cfg.is_fully_dl_enabled(pdsch_alloc.slot) and mcs_prbs_estimate.n_prbs == 1; - const unsigned min_nof_prbs_partial_slots = 2U; - if (set_min_nof_prbs) { - mcs_prbs_estimate.n_prbs = min_nof_prbs_partial_slots; - } - - ue_grant_crbs = rb_helper::find_empty_interval_of_length(used_crbs, mcs_prbs_estimate.n_prbs, 0); - if (ue_grant_crbs.empty() or (set_min_nof_prbs and ue_grant_crbs.length() < min_nof_prbs_partial_slots)) { - logger.debug("ue={} rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: No space in PDSCH.", - u.ue_index, - u.crnti, - pdsch_alloc.slot); - return {}; - } - - const unsigned final_nof_prbs = ue_grant_crbs.length(); - // As \c txDirectCurrentLocation, in \c SCS-SpecificCarrier, TS 38.331, "If this field (\c - // txDirectCurrentLocation) is absent for downlink within ServingCellConfigCommon and ServingCellConfigCommonSIB, - // the UE assumes the default value of 3300 (i.e. "Outside the carrier")". - bool contains_dc = false; - if (cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.has_value()) { - contains_dc = dc_offset_helper::is_contained( - cell_cfg.dl_cfg_common.freq_info_dl.scs_carrier_list.back().tx_direct_current_location.value(), - ue_grant_crbs); - } - std::optional mcs_tbs = - compute_dl_mcs_tbs(pdsch_cfg, mcs_prbs_estimate.mcs, final_nof_prbs, contains_dc); - - // If there is not MCS-TBS info, it means no MCS exists such that the effective code rate is <= 0.95. - if (not mcs_tbs.has_value()) { - logger.warning( - "ue={} rnti={}: Failed to allocate PDSCH. Cause: no MCS such that code rate <= 0.95.", u.ue_index, u.crnti); - return {}; - } - - // If ConRes CE is pending then ensure that there is enough RBs/TBS such that ConRes CE is not segmented. - if (u.is_conres_ce_pending()) { - const unsigned only_conres_ce_pending_bytes = u.pending_conres_ce_bytes(); - sch_prbs_tbs only_conres_prbs_tbs = - get_nof_prbs(prbs_calculator_sch_config{only_conres_ce_pending_bytes, - static_cast(pdsch_cfg.symbols.length()), - calculate_nof_dmrs_per_rb(pdsch_cfg.dmrs), - pdsch_cfg.nof_oh_prb, - mcs_config, - pdsch_cfg.nof_layers}); - if ((mcs_prbs_estimate.n_prbs < only_conres_prbs_tbs.nof_prbs) or - (mcs_tbs->tbs < (only_conres_ce_pending_bytes + FIXED_SIZED_MAC_CE_SUBHEADER_SIZE))) { - logger.debug("ue={} rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: Grant is too small to fit even " - "ConRes CE.", - u.ue_index, - u.crnti, - pdsch_alloc.slot); - return {}; - } - } - - final_mcs_tbs = mcs_tbs.value(); - } - - // Allocate PDCCH resources. - cell_slot_resource_allocator& pdcch_alloc = res_alloc[slot_offset]; - pdcch_dl_information* pdcch = - pdcch_sch.alloc_dl_pdcch_common(pdcch_alloc, u.crnti, ss_cfg.get_id(), aggregation_level::n4); - if (pdcch == nullptr) { - logger.debug( - "rnti={}: Postponed SRB1 PDU scheduling for slot={}. Cause: No space in PDCCH.", u.crnti, pdcch_alloc.slot); - slots_with_no_pdxch_space[pdcch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - return {}; - } - - // Allocate PUCCH resources. - // - The dedicated resources are needed as, at this point, the UE object in the scheduler (not the actual terminal) - // could have a complete configuration; if so, the UCI scheduler can start allocating SRs and CSIs in advance, as the - // scheduler doesn't know exactly when the UE will start transmitting SRs and CSIs. - // - If the UE object in the scheduler doesn't have a complete configuration (which is a requirement for any PUCCH - // function that handles PUCCH dedicated resource), don't use the PUCCH dedicated resources. - const bool use_common_and_ded_res = - u.ue_cfg_dedicated()->is_ue_cfg_complete() and (dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0 or is_retx); - auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, - res_alloc, - pucch_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common_and_ded_res); - if (not pucch_res_indicator.has_value()) { - if (chosen_k1.has_value()) { - logger.debug("rnti={}: Failed to allocate PDSCH for SRB1 for slot={}. Cause: No space in PUCCH", - u.crnti, - pdsch_alloc.slot); - } - pdcch_sch.cancel_last_pdcch(pdcch_alloc); - return {}; - } - - // Mark resources as occupied in the ResourceGrid. - pdsch_alloc.dl_res_grid.fill(grant_info{scs, pdsch_td_cfg.symbols, ue_grant_crbs}); - - // Update DRX controller state. - u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); - - auto [nof_srb1_scheduled_bytes, h_dl] = fill_dl_srb_grant(u, - pdsch_alloc.slot, - h_dl_retx, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - final_mcs_tbs.mcs, - ue_grant_crbs, - pdsch_cfg, - final_mcs_tbs.tbs, - is_retx, - is_srb0); - - return sched_srb_results{.h_dl = h_dl, .nof_srb1_scheduled_bytes = nof_srb1_scheduled_bytes}; + return std::make_tuple(prbs_tbs.nof_prbs, chosen_mcs_idx, units::bytes{prbs_tbs.tbs_bytes}); } std::pair diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index d4a1fd4111..fd7f7a8aa7 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -118,8 +118,10 @@ class ue_fallback_scheduler }; /// \brief For a number of pending bytes, select the appropriate MCS. - std::tuple - select_mcs(const pdsch_config_params& pdsch_cfg, unsigned pending_bytes, unsigned nof_rbs_available); + std::tuple select_tbs(const pdsch_config_params& pdsch_cfg, + unsigned pending_bytes, + const crb_interval& unused_crbs, + const std::optional& fixed_mcs) const; /// \brief Allocate DL grant for a UE and for a specific PDSCH slot. sched_srb_results alloc_grant(ue& u, @@ -130,40 +132,6 @@ class ue_fallback_scheduler std::optional h_dl_retx, std::optional is_srb0); - /// \brief Tries to schedule DL ConRes CE for a UE and for a specific PDSCH slot. - /// \remark This function handles the following scenarios: - /// - Schedules ConRes CE only if ConRes indication is received from MAC but no buffer status update is received - /// for SRB0/SRB1. - sched_srb_results schedule_dl_conres_ce(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx); - - /// \brief Tries to schedule DL SRB0 message for a UE and for a specific PDSCH slot. - /// \remark This function handles the following scenarios: - /// - Schedules SRB0 only (not empty) if ConRes CE has already sent. - /// - Schedules SRB0 (not empty) + ConRes CE (if pending) if there is enough space in PDSCH resource grid. - /// - Schedules ConRes CE only (if pending) if there is not enough space in PDSCH resource grid to fit SRB0 (not - /// empty) + ConRes CE. - sched_srb_results schedule_dl_srb0(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx); - - /// \brief Tries to schedule DL SRB1 message for a UE and for a specific PDSCH slot. - /// \remark This function handles the following scenarios: - /// - Schedules SRB1 (not empty) + ConRes CE (if pending). - sched_srb_results schedule_dl_srb1(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx = std::nullopt); - /// \brief Tries to schedule SRB1 message for a specific PUSCH time domain resource. ul_srb_sched_outcome schedule_ul_srb(ue& u, cell_resource_allocator& res_alloc, From d05158e8689d6bb6a49f3bff6e7a3f0b6391369e Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 4 Dec 2024 17:58:51 +0100 Subject: [PATCH 068/227] sched: remove unnecessary code from fallback_scheduler_test --- .../ue_scheduling/fallback_scheduler_test.cpp | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index fdc0b82696..a251c143aa 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -23,19 +23,11 @@ #include "tests/unittests/scheduler/test_utils/dummy_test_components.h" #include "tests/unittests/scheduler/test_utils/scheduler_test_suite.h" #include "srsran/ran/duplex_mode.h" +#include "srsran/support/test_utils.h" #include -#include using namespace srsran; -std::random_device rd; -std::mt19937 g(rd()); - -unsigned get_random_uint(unsigned min, unsigned max) -{ - return std::uniform_int_distribution{min, max}(g); -} - static cell_config_builder_params test_builder_params(duplex_mode duplx_mode) { cell_config_builder_params builder_params{}; @@ -108,6 +100,10 @@ struct test_bench { fallback_sched(expert_cfg, cell_cfg, pdcch_sch, pucch_alloc, ue_db), csi_rs_sched(cell_cfg) { + srslog::fetch_basic_logger("SCHED", true).set_level(srslog::basic_levels::debug); + srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::info); + srslog::init(); + ue_alloc.add_cell(cell_cfg.cell_index, pdcch_sch, uci_alloc, res_grid); } @@ -582,13 +578,13 @@ TEST_P(fallback_scheduler_tester, test_srb0_buffer_size_exceeding_max_msg4_mcs_i TEST_P(fallback_scheduler_tester, sanity_check_with_random_max_mcs_and_payload_size) { - const sch_mcs_index max_msg4_mcs = get_random_uint(0, 27); + const sch_mcs_index max_msg4_mcs = test_rgen::uniform_int(0, 27); setup_sched(create_expert_config(max_msg4_mcs), create_custom_cell_config_request(params.k0)); // Add UE. const du_ue_index_t ue_idx = to_du_ue_index(0); add_ue(to_rnti(0x4601), ue_idx); // Random payload size. - const unsigned mac_srb0_sdu_size = get_random_uint(1, 458); + const unsigned mac_srb0_sdu_size = test_rgen::uniform_int(1, 458); push_buffer_state_to_dl_ue(to_du_ue_index(0), current_slot, mac_srb0_sdu_size, true); srslog::basic_logger& logger(srslog::fetch_basic_logger("TEST")); @@ -1274,7 +1270,6 @@ class ul_fallback_scheduler_tester : public base_fallback_tester, std::optional h_ul = test_ue.get_pcell().harqs.ul_harq(h_id); if (h_ul.has_value() and h_ul->is_waiting_ack() and h_ul->pusch_slot() == sl) { - test_ue.pending_ul_newtx_bytes(); bool ack = ack_harq_process(sl, *h_ul); const unsigned delivered_bytes = ack ? h_ul->get_grant_params().tbs_bytes - 10U : 0U; buffer_bytes > delivered_bytes ? buffer_bytes -= delivered_bytes : buffer_bytes = 0U; @@ -1400,7 +1395,7 @@ INSTANTIATE_TEST_SUITE_P(test_fdd_and_tdd, class fallback_sched_ue_w_out_pucch_cfg : public base_fallback_tester, public ::testing::Test { protected: - fallback_sched_ue_w_out_pucch_cfg() : base_fallback_tester(srsran::duplex_mode::TDD) + fallback_sched_ue_w_out_pucch_cfg() : base_fallback_tester(duplex_mode::TDD) { const unsigned k0 = 0; const sch_mcs_index max_msg4_mcs_index = 8; @@ -1458,16 +1453,3 @@ TEST_F(fallback_sched_ue_w_out_pucch_cfg, when_srb0_is_retx_ed_only_pucch_common ASSERT_TRUE(srb_transmitted); } - -int main(int argc, char** argv) -{ - srslog::fetch_basic_logger("SCHED", true).set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::info); - srslog::init(); - - ::testing::InitGoogleTest(&argc, argv); - - (void)(::testing::GTEST_FLAG(death_test_style) = "fast"); - - return RUN_ALL_TESTS(); -} From 04ecb2aafc779f5249d220585196dbaf176a9c22 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 6 Dec 2024 11:27:22 +0100 Subject: [PATCH 069/227] sched: fix logging message for fallback scheduler --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index c539e27235..f9dd8b6cae 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -526,7 +526,7 @@ ue_fallback_scheduler::alloc_grant(ue& u, // Search for empty HARQ in case of newTx. if (not is_retx and not ue_pcell.harqs.has_empty_dl_harqs()) { - logger.warning("rnti={}: UE must have empty HARQs during ConRes CE allocation", u.crnti); + logger.warning("rnti={}: UE must have empty HARQs during fallback newtx allocation", u.crnti); return {}; } @@ -669,7 +669,10 @@ ue_fallback_scheduler::alloc_grant(ue& u, pdsch_alloc.slot); } pdcch_sch.cancel_last_pdcch(pdcch_alloc); - slots_with_no_pdxch_space[pdcch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; + if (not use_common_and_ded_res) { + // If there isn't enough space for common PUCCH, then there is no point of repeating this slot. + slots_with_no_pdxch_space[pdcch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; + } return {}; } From 66d7207c67a126f2a176ec0cdc873117d474973c Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 12:36:39 +0100 Subject: [PATCH 070/227] sched: reduce log level from error to info when fallback sched fails --- .../ue_scheduling/ue_fallback_scheduler.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index f9dd8b6cae..a0469400b2 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -591,16 +591,17 @@ ue_fallback_scheduler::alloc_grant(ue& u, select_tbs(pdsch_cfg, pending_bytes, unused_crbs, fixed_mcs); unsigned chosen_tbs = std::get<2>(result).value(); if (chosen_tbs == 0) { - logger.error("rnti={}: Unable to compute TBS for fallback allocation", u.crnti); + logger.info("rnti={}: Fallback newTx allocation postponed. Cause: Unable to compute valid TBS for available RBs", + u.crnti); return {}; } if (chosen_tbs < min_pending_bytes) { // We could not even fulfill the minimum pending bytes. - logger.debug( - "rnti={}: Postpone fallback allocation. Cause: Pending non-segmentable bytes exceed TBS calculated ({})", - u.crnti, - min_pending_bytes, - chosen_tbs); + logger.debug("rnti={}: Fallback newTx allocation postponed. Cause: Pending non-segmentable bytes exceed TBS " + "calculated ({})", + u.crnti, + min_pending_bytes, + chosen_tbs); if (only_conres_bytes > 0) { // In case not even a ConRes CE can fit, we can start ignoring this slot. slots_with_no_pdxch_space[pdsch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; @@ -615,7 +616,9 @@ ue_fallback_scheduler::alloc_grant(ue& u, result = select_tbs(pdsch_cfg, min_pending_bytes, unused_crbs, std::nullopt); chosen_tbs = std::get<2>(result).value(); if (chosen_tbs == 0) { - logger.error("rnti={}: Unable to compute TBS for fallback allocation", u.crnti); + logger.info( + "rnti={}: Fallback newTx allocation postponed. Cause: Unable to compute valid TBS for available RBs", + u.crnti); return {}; } } From 001fee42aaf9b4cfcb15516b3cc2e5d28cf47fbe Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 5 Dec 2024 14:53:35 +0000 Subject: [PATCH 071/227] gtpu: rename ngu_gateway to gtpu_gateway --- apps/cu/cu.cpp | 6 ++--- apps/du/du.cpp | 26 +++++++++---------- apps/units/o_cu_up/o_cu_up_builder.cpp | 6 ++--- apps/units/o_cu_up/o_cu_up_unit_impl.cpp | 6 ++--- apps/units/o_cu_up/o_cu_up_unit_impl.h | 14 +++++----- include/srsran/cu_up/cu_up_config.h | 4 +-- .../f1u_split_connector_factory.h | 2 +- .../f1u_split_connector_factory.h | 12 ++++----- .../gtpu/{ngu_gateway.h => gtpu_gateway.h} | 3 --- .../split_connector/f1u_split_connector.cpp | 4 +-- .../split_connector/f1u_split_connector.h | 2 +- .../du/split_connector/f1u_split_connector.h | 26 +++++++++---------- lib/gtpu/CMakeLists.txt | 2 +- .../{ngu_gateway.cpp => gtpu_gateway.cpp} | 11 ++++---- tests/unittests/cu_up/cu_up_test_helpers.h | 4 +-- .../common/f1u_cu_split_connector_test.cpp | 2 +- .../common/f1u_du_split_connector_test.cpp | 22 ++++++++-------- 17 files changed, 74 insertions(+), 78 deletions(-) rename include/srsran/gtpu/{ngu_gateway.h => gtpu_gateway.h} (98%) rename lib/gtpu/{ngu_gateway.cpp => gtpu_gateway.cpp} (90%) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index ec708543f7..91f126b358 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -33,7 +33,7 @@ #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/gtpu/gtpu_gateway.h" #include "srsran/support/backtrace.h" #include "srsran/support/config_parsers.h" #include "srsran/support/cpu_features.h" @@ -287,8 +287,8 @@ int main(int argc, char** argv) cu_f1u_gw_config.bind_port = GTPU_PORT; cu_f1u_gw_config.reuse_addr = false; cu_f1u_gw_config.pool_occupancy_threshold = cu_cfg.nru_cfg.pool_occupancy_threshold; - std::unique_ptr cu_f1u_gw = - srs_cu_up::create_udp_ngu_gateway(cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor()); + std::unique_ptr cu_f1u_gw = + create_udp_ngu_gateway(cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor()); std::unique_ptr cu_f1u_conn = srs_cu_up::create_split_f1u_gw( {*cu_f1u_gw, *cu_f1u_gtpu_demux, *cu_up_dlt_pcaps.f1u, GTPU_PORT, cu_cfg.nru_cfg.ext_addr}); diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 4ba87707ec..b482e954f0 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -256,19 +256,19 @@ int main(int argc, char** argv) // Create F1-U connector // TODO: Simplify this and use factory. - gtpu_demux_creation_request du_f1u_gtpu_msg = {}; - du_f1u_gtpu_msg.cfg.warn_on_drop = true; - du_f1u_gtpu_msg.gtpu_pcap = du_pcaps.f1u.get(); - std::unique_ptr du_f1u_gtpu_demux = create_gtpu_demux(du_f1u_gtpu_msg); - udp_network_gateway_config du_f1u_gw_config = {}; - du_f1u_gw_config.bind_address = du_cfg.nru_cfg.bind_address; - du_f1u_gw_config.bind_port = GTPU_PORT; - du_f1u_gw_config.reuse_addr = false; - du_f1u_gw_config.pool_occupancy_threshold = du_cfg.nru_cfg.pool_threshold; - std::unique_ptr du_f1u_gw = srs_cu_up::create_udp_ngu_gateway( - du_f1u_gw_config, - *epoll_broker, - workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0))); + gtpu_demux_creation_request du_f1u_gtpu_msg = {}; + du_f1u_gtpu_msg.cfg.warn_on_drop = true; + du_f1u_gtpu_msg.gtpu_pcap = du_pcaps.f1u.get(); + std::unique_ptr du_f1u_gtpu_demux = create_gtpu_demux(du_f1u_gtpu_msg); + udp_network_gateway_config du_f1u_gw_config = {}; + du_f1u_gw_config.bind_address = du_cfg.nru_cfg.bind_address; + du_f1u_gw_config.bind_port = GTPU_PORT; + du_f1u_gw_config.reuse_addr = false; + du_f1u_gw_config.pool_occupancy_threshold = du_cfg.nru_cfg.pool_threshold; + std::unique_ptr du_f1u_gw = + create_udp_ngu_gateway(du_f1u_gw_config, + *epoll_broker, + workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0))); std::unique_ptr du_f1u_conn = srs_du::create_split_f1u_gw( {du_f1u_gw.get(), du_f1u_gtpu_demux.get(), *du_pcaps.f1u, GTPU_PORT, du_cfg.nru_cfg.ext_addr}); diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 82a9e24e8d..127a98ea94 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -63,7 +63,7 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ srsran_assert(address.has_value(), "Invalid F1-U bind address"); // Create NG-U gateway(s). - std::vector> ngu_gws; + std::vector> ngu_gws; if (not unit_cfg.cu_up_cfg.ngu_cfg.no_core) { for (const cu_up_unit_ngu_socket_config& sock_cfg : unit_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg) { udp_network_gateway_config n3_udp_cfg = {}; @@ -75,12 +75,12 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets - std::unique_ptr ngu_gw = srs_cu_up::create_udp_ngu_gateway( + std::unique_ptr ngu_gw = create_udp_ngu_gateway( n3_udp_cfg, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); ngu_gws.push_back(std::move(ngu_gw)); } } else { - std::unique_ptr ngu_gw = srs_cu_up::create_no_core_ngu_gateway(); + std::unique_ptr ngu_gw = create_no_core_ngu_gateway(); ngu_gws.push_back(std::move(ngu_gw)); } diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp index a16cebf497..8cbc253d01 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp @@ -12,9 +12,9 @@ using namespace srsran; -o_cu_up_unit_impl::o_cu_up_unit_impl(std::vector> gateways_, - std::unique_ptr e2_metric_connector_, - std::unique_ptr cu_up_) : +o_cu_up_unit_impl::o_cu_up_unit_impl(std::vector> gateways_, + std::unique_ptr e2_metric_connector_, + std::unique_ptr cu_up_) : gateways(std::move(gateways_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) { srsran_assert(not gateways.empty(), "Invalid NG-U gateway"); diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.h b/apps/units/o_cu_up/o_cu_up_unit_impl.h index 6b9167b255..c8e5228cd6 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.h +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.h @@ -14,7 +14,7 @@ #include "srsran/cu_up/cu_up_power_controller.h" #include "srsran/cu_up/o_cu_up.h" #include "srsran/e2/e2_cu_metrics_connector.h" -#include "srsran/gtpu/ngu_gateway.h" +#include "srsran/gtpu/gtpu_gateway.h" namespace srsran { @@ -27,9 +27,9 @@ using e2_cu_metrics_connector_manager = class o_cu_up_unit_impl : public srs_cu_up::o_cu_up { public: - o_cu_up_unit_impl(std::vector> gateways_, - std::unique_ptr e2_metric_connector_, - std::unique_ptr cu_up_); + o_cu_up_unit_impl(std::vector> gateways_, + std::unique_ptr e2_metric_connector_, + std::unique_ptr cu_up_); // See interface for documentation. srs_cu_up::cu_up_interface& get_cu_up() override; @@ -38,9 +38,9 @@ class o_cu_up_unit_impl : public srs_cu_up::o_cu_up srs_cu_up::cu_up_power_controller& get_power_controller() override; private: - std::vector> gateways; - std::unique_ptr e2_metric_connector; - std::unique_ptr cu_up; + std::vector> gateways; + std::unique_ptr e2_metric_connector; + std::unique_ptr cu_up; }; } // namespace srsran diff --git a/include/srsran/cu_up/cu_up_config.h b/include/srsran/cu_up/cu_up_config.h index ca7e62ef6e..5c1012794d 100644 --- a/include/srsran/cu_up/cu_up_config.h +++ b/include/srsran/cu_up/cu_up_config.h @@ -15,7 +15,7 @@ #include "srsran/e1ap/gateways/e1_connection_client.h" #include "srsran/f1u/cu_up/f1u_gateway.h" #include "srsran/gtpu/gtpu_config.h" -#include "srsran/gtpu/ngu_gateway.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/pcap/dlt_pcap.h" #include "srsran/support/timers.h" #include @@ -81,7 +81,7 @@ struct cu_up_dependencies { /// E1AP connection client. e1_connection_client* e1_conn_client = nullptr; /// NG-U gateways - std::vector ngu_gws; + std::vector ngu_gws; }; } // namespace srs_cu_up diff --git a/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h b/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h index bdafa508b1..a8c53ccbae 100644 --- a/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h +++ b/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h @@ -13,7 +13,7 @@ #include "srsran/f1u/cu_up/f1u_gateway.h" #include "srsran/gtpu/gtpu_demux.h" -#include "srsran/gtpu/ngu_gateway.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/pcap/dlt_pcap.h" #include diff --git a/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h b/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h index 48784c1d99..215cfa73b9 100644 --- a/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h +++ b/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h @@ -13,18 +13,18 @@ #include "srsran/f1u/du/f1u_gateway.h" #include "srsran/gtpu/gtpu_demux.h" -#include "srsran/gtpu/ngu_gateway.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/pcap/dlt_pcap.h" #include namespace srsran::srs_du { struct f1u_du_split_gateway_creation_msg { - srs_cu_up::ngu_gateway* udp_gw; - gtpu_demux* demux; - dlt_pcap& gtpu_pcap; - uint16_t peer_port; - std::string f1u_ext_addr = "auto"; + ngu_gateway* udp_gw; + gtpu_demux* demux; + dlt_pcap& gtpu_pcap; + uint16_t peer_port; + std::string f1u_ext_addr = "auto"; }; std::unique_ptr create_split_f1u_gw(f1u_du_split_gateway_creation_msg msg); diff --git a/include/srsran/gtpu/ngu_gateway.h b/include/srsran/gtpu/gtpu_gateway.h similarity index 98% rename from include/srsran/gtpu/ngu_gateway.h rename to include/srsran/gtpu/gtpu_gateway.h index 7642a0bd25..51b3125060 100644 --- a/include/srsran/gtpu/ngu_gateway.h +++ b/include/srsran/gtpu/gtpu_gateway.h @@ -17,8 +17,6 @@ namespace srsran { class io_broker; -namespace srs_cu_up { - /// \brief Handler of the transmission and reception of User-plane (UP) Transport Network Layer (TNL) PDUs by the CU-UP /// via the NG-U interface. /// @@ -70,5 +68,4 @@ create_udp_ngu_gateway(const udp_network_gateway_config& config, io_broker& io_b /// \return Returns the instantiated NG-U gateway. std::unique_ptr create_no_core_ngu_gateway(); -} // namespace srs_cu_up } // namespace srsran diff --git a/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp b/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp index 35e834f363..afcba8fbb3 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp @@ -28,11 +28,11 @@ class srs_cu_up::gtpu_tx_udp_gw_adapter : public gtpu_tunnel_common_tx_upper_lay } } - void connect(srs_cu_up::ngu_tnl_pdu_session& handler_) { handler = &handler_; } + void connect(ngu_tnl_pdu_session& handler_) { handler = &handler_; } void disconnect() { handler = nullptr; } - srs_cu_up::ngu_tnl_pdu_session* handler = nullptr; + ngu_tnl_pdu_session* handler = nullptr; }; class srs_cu_up::gtpu_rx_f1u_adapter : public srsran::gtpu_tunnel_nru_rx_lower_layer_notifier diff --git a/lib/f1u/cu_up/split_connector/f1u_split_connector.h b/lib/f1u/cu_up/split_connector/f1u_split_connector.h index 6f5d2f1773..d9f33a05f1 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.h +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.h @@ -15,10 +15,10 @@ #include "srsran/f1u/cu_up/f1u_gateway.h" #include "srsran/gtpu/gtpu_config.h" #include "srsran/gtpu/gtpu_demux.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/gtpu/gtpu_tunnel_common_tx.h" #include "srsran/gtpu/gtpu_tunnel_nru.h" #include "srsran/gtpu/gtpu_tunnel_nru_rx.h" -#include "srsran/gtpu/ngu_gateway.h" #include "srsran/pcap/dlt_pcap.h" #include "srsran/srslog/srslog.h" #include diff --git a/lib/f1u/du/split_connector/f1u_split_connector.h b/lib/f1u/du/split_connector/f1u_split_connector.h index 67721bb799..ce5e1bac1f 100644 --- a/lib/f1u/du/split_connector/f1u_split_connector.h +++ b/lib/f1u/du/split_connector/f1u_split_connector.h @@ -14,11 +14,11 @@ #include "srsran/f1u/du/f1u_bearer_logger.h" #include "srsran/f1u/du/f1u_gateway.h" #include "srsran/gtpu/gtpu_demux.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/gtpu/gtpu_tunnel_common_tx.h" #include "srsran/gtpu/gtpu_tunnel_nru.h" #include "srsran/gtpu/gtpu_tunnel_nru_factory.h" #include "srsran/gtpu/gtpu_tunnel_nru_rx.h" -#include "srsran/gtpu/ngu_gateway.h" #include "srsran/pcap/dlt_pcap.h" #include "srsran/srslog/srslog.h" #include @@ -38,11 +38,11 @@ class gtpu_tx_udp_gw_adapter : public gtpu_tunnel_common_tx_upper_layer_notifier } } - void connect(srs_cu_up::ngu_tnl_pdu_session& handler_) { handler = &handler_; } + void connect(ngu_tnl_pdu_session& handler_) { handler = &handler_; } void disconnect() { handler = nullptr; } - srs_cu_up::ngu_tnl_pdu_session* handler; + ngu_tnl_pdu_session* handler; }; class gtpu_rx_f1u_adapter : public srsran::gtpu_tunnel_nru_rx_lower_layer_notifier @@ -169,11 +169,11 @@ class f1u_split_gateway_du_bearer : public f1u_du_gateway_bearer class f1u_split_connector final : public f1u_du_udp_gateway { public: - f1u_split_connector(srs_cu_up::ngu_gateway* udp_gw_, - gtpu_demux* demux_, - dlt_pcap& gtpu_pcap_, - uint16_t peer_port_ = GTPU_PORT, - std::string f1u_ext_addr_ = "auto") : + f1u_split_connector(ngu_gateway* udp_gw_, + gtpu_demux* demux_, + dlt_pcap& gtpu_pcap_, + uint16_t peer_port_ = GTPU_PORT, + std::string f1u_ext_addr_ = "auto") : logger_du(srslog::fetch_basic_logger("DU-F1-U")), udp_gw(udp_gw_), demux(demux_), @@ -208,11 +208,11 @@ class f1u_split_connector final : public f1u_du_udp_gateway std::unordered_map du_map; std::mutex map_mutex; // shared mutex for access to cu_map - srs_cu_up::ngu_gateway* udp_gw; - std::unique_ptr udp_session; - gtpu_demux* demux; - network_gateway_data_gtpu_demux_adapter gw_data_gtpu_demux_adapter; - dlt_pcap& gtpu_pcap; + ngu_gateway* udp_gw; + std::unique_ptr udp_session; + gtpu_demux* demux; + network_gateway_data_gtpu_demux_adapter gw_data_gtpu_demux_adapter; + dlt_pcap& gtpu_pcap; uint16_t peer_port; std::string f1u_ext_addr = "auto"; // External address advertised by the F1-U interface diff --git a/lib/gtpu/CMakeLists.txt b/lib/gtpu/CMakeLists.txt index 0b7e86672e..4e92e3e13e 100644 --- a/lib/gtpu/CMakeLists.txt +++ b/lib/gtpu/CMakeLists.txt @@ -13,7 +13,7 @@ set(SOURCES gtpu_tunnel_ngu_factory.cpp gtpu_echo_factory.cpp gtpu_teid_pool_factory.cpp gtpu_demux_impl.cpp - ngu_gateway.cpp) + gtpu_gateway.cpp) add_library(srsran_gtpu STATIC ${SOURCES}) target_link_libraries(srsran_gtpu srsran_nru srsran_psup srsran_support srsran_gateway) diff --git a/lib/gtpu/ngu_gateway.cpp b/lib/gtpu/gtpu_gateway.cpp similarity index 90% rename from lib/gtpu/ngu_gateway.cpp rename to lib/gtpu/gtpu_gateway.cpp index 35d981649c..2b0b4cb0c5 100644 --- a/lib/gtpu/ngu_gateway.cpp +++ b/lib/gtpu/gtpu_gateway.cpp @@ -8,13 +8,12 @@ * */ -#include "srsran/gtpu/ngu_gateway.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/gateways/udp_network_gateway_factory.h" #include "srsran/srslog/srslog.h" #include "srsran/support/io/io_broker.h" using namespace srsran; -using namespace srs_cu_up; namespace { @@ -102,9 +101,9 @@ class udp_ngu_gateway final : public ngu_gateway } // namespace -std::unique_ptr srsran::srs_cu_up::create_udp_ngu_gateway(const udp_network_gateway_config& config, - io_broker& io_brk, - task_executor& io_tx_executor) +std::unique_ptr srsran::create_udp_ngu_gateway(const udp_network_gateway_config& config, + io_broker& io_brk, + task_executor& io_tx_executor) { return std::make_unique(config, io_brk, io_tx_executor); } @@ -144,7 +143,7 @@ class no_core_ngu_gateway : public ngu_gateway } // namespace -std::unique_ptr srsran::srs_cu_up::create_no_core_ngu_gateway() +std::unique_ptr srsran::create_no_core_ngu_gateway() { return std::make_unique(); } diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index 0cce1a80e4..ebeeff272b 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -17,9 +17,9 @@ #include "srsran/e1ap/cu_up/e1ap_cu_up.h" #include "srsran/f1u/cu_up/f1u_gateway.h" #include "srsran/gtpu/gtpu_demux.h" +#include "srsran/gtpu/gtpu_gateway.h" #include "srsran/gtpu/gtpu_teid_pool.h" #include "srsran/gtpu/gtpu_tunnel_common_tx.h" -#include "srsran/gtpu/ngu_gateway.h" #include #include #include @@ -255,7 +255,7 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway std::list removed_ul_teid_list = {}; }; -class dummy_ngu_gateway final : public srs_cu_up::ngu_tnl_pdu_session +class dummy_ngu_gateway final : public ngu_tnl_pdu_session { bool get_bind_address(std::string& ip_address) const override { diff --git a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp index 41e79b6266..4e7bed6b8b 100644 --- a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp @@ -131,7 +131,7 @@ class f1u_cu_split_connector_test : public ::testing::Test nru_gw_config.bind_address = cu_gw_bind_address; nru_gw_config.bind_port = 0; nru_gw_config.reuse_addr = true; - udp_gw = srs_cu_up::create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); + udp_gw = create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); f1u_cu_up_split_gateway_creation_msg cu_create_msg{ *udp_gw, *demux, dummy_pcap, tester_bind_port.value(), get_external_bind_address()}; diff --git a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp index 83d5377104..ef452ece24 100644 --- a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp @@ -111,7 +111,7 @@ class f1u_du_split_connector_test : public ::testing::Test nru_gw_config.bind_address = du_gw_bind_address; nru_gw_config.bind_port = 0; nru_gw_config.reuse_addr = true; - udp_gw = srs_cu_up::create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); + udp_gw = create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); f1u_du_split_gateway_creation_msg cu_create_msg{ udp_gw.get(), demux.get(), dummy_pcap, tester_bind_port.value(), get_external_bind_address()}; @@ -181,16 +181,16 @@ class f1u_du_split_connector_test : public ::testing::Test virtual std::string get_external_bind_address() { return "auto"; } - timer_manager timer_mng; - manual_task_worker ue_worker{128}; - timer_factory timers; - unique_timer ue_inactivity_timer; - std::unique_ptr epoll_broker; - manual_task_worker io_tx_executor{128}; - std::unique_ptr demux; - std::unique_ptr udp_gw; - null_dlt_pcap dummy_pcap = {}; - std::string du_gw_bind_address = "127.0.0.2"; + timer_manager timer_mng; + manual_task_worker ue_worker{128}; + timer_factory timers; + unique_timer ue_inactivity_timer; + std::unique_ptr epoll_broker; + manual_task_worker io_tx_executor{128}; + std::unique_ptr demux; + std::unique_ptr udp_gw; + null_dlt_pcap dummy_pcap = {}; + std::string du_gw_bind_address = "127.0.0.2"; // Tester UDP gw to TX/RX PDUs to F1-U CU GW std::unique_ptr udp_tester; From 730722f7b4cc0584036418a4bf282321b55a5b15 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 5 Dec 2024 15:06:46 +0000 Subject: [PATCH 072/227] gtpu: update comments in gtpu_gateway --- include/srsran/gtpu/gtpu_gateway.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/srsran/gtpu/gtpu_gateway.h b/include/srsran/gtpu/gtpu_gateway.h index 51b3125060..efe788a910 100644 --- a/include/srsran/gtpu/gtpu_gateway.h +++ b/include/srsran/gtpu/gtpu_gateway.h @@ -17,13 +17,13 @@ namespace srsran { class io_broker; -/// \brief Handler of the transmission and reception of User-plane (UP) Transport Network Layer (TNL) PDUs by the CU-UP -/// via the NG-U interface. +/// \brief Handler of the transmission and reception of User-plane (UP) Transport Network Layer (TNL) PDUs +/// via a GTP-U interface. /// /// In particular, this class handles: -/// - the reception of PDUs by the CU-UP via the NG-U interface, -/// - the transmission of PDUs to the UPF via the NG-U interface, and -/// - the creation and deallocation of the required network resources for the link with the UPF via the NG-U interface. +/// - the reception of PDUs by the CU-UP via the NG-U interface, or the DU/CU-UP via the F1-U interface +/// - the transmission of PDUs to the UPF via the NG-U interface, or the DU/CU-UP via the F1-U interface and +/// - the creation and deallocation of the required network resources for the NG-U/F1-U interface. class ngu_tnl_pdu_session : public udp_network_gateway_data_handler, public network_gateway_data_notifier_with_src_addr { public: @@ -35,37 +35,37 @@ class ngu_tnl_pdu_session : public udp_network_gateway_data_handler, public netw /// this function can be used to get the actual IP address in string form. virtual bool get_bind_address(std::string& ip_address) const = 0; - /// Get bind port currently being used by the NG-U TNL session for the reception of PDUs. + /// Get bind port currently being used by the GTP-U TNL session for the reception of PDUs. /// \return If a UDP link is being used, returns the respective bind port. If the connection is local, it returns /// std::nullopt. virtual std::optional get_bind_port() const = 0; }; -/// \brief This class is called by the CU-UP to instantiate new NG-U TNL PDU sessions. +/// \brief This class is called by the CU-UP to instantiate new GTP-U TNL PDU sessions. class ngu_gateway { public: virtual ~ngu_gateway() = default; - /// \brief Creates a new NG-U TNL session and starts listening for incoming PDUs. - /// \param[in] data_notifier The notifier to be used by the instantiated NG-U TNL session to push received PDUs back + /// \brief Creates a new GTP-U TNL session and starts listening for incoming PDUs. + /// \param[in] data_notifier The notifier to be used by the instantiated GTP-U TNL session to push received PDUs back /// to the CU-UP. /// \return Returns a new instance of a NG-U TNL PDU session. virtual std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) = 0; }; -/// Creates a factory of NG-U TNL sessions that handle the allocation of network resources for a UDP-based link. +/// Creates a factory of GTP-U TNL sessions that handle the allocation of network resources for a UDP-based link. /// \param[in] config Configuration of the UDP network gateway. /// \param[in] io_brk IO broker that will manage the reception of new PDUs from the UDP socket. /// \param[in] io_tx_executor Executor that will be used to handle the transmission of PDUs to the UDP socket. -/// \return Returns the instantiated NG-U gateway. Returns nullptr, if the NG-U gateway could not be established. +/// \return Returns the instantiated GTP-U gateway. Returns nullptr, if the GTP-U gateway could not be established. std::unique_ptr create_udp_ngu_gateway(const udp_network_gateway_config& config, io_broker& io_brk, task_executor& io_tx_executor); -/// \brief Creates a NG-U gateway that establishes a connection to a null/dummy UPF. +/// \brief Creates a GTP-U gateway that establishes a connection to a null/dummy UPF. /// -/// This type of NG-U gateway is useful when testing the CU-UP without a real UPF. -/// \return Returns the instantiated NG-U gateway. +/// This type of GTP-U gateway is useful when testing the CU-UP without a real UPF. +/// \return Returns the instantiated GTP-U gateway. std::unique_ptr create_no_core_ngu_gateway(); } // namespace srsran From a2b2843fe3843f0e173afada2603cc391c510b94 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 5 Dec 2024 15:09:03 +0000 Subject: [PATCH 073/227] gtpu: rename ngu_gateway to gtpu_gateway --- apps/cu/cu.cpp | 2 +- apps/du/du.cpp | 2 +- apps/units/o_cu_up/o_cu_up_builder.cpp | 6 +- apps/units/o_cu_up/o_cu_up_unit_impl.cpp | 2 +- apps/units/o_cu_up/o_cu_up_unit_impl.h | 4 +- include/srsran/cu_up/cu_up_config.h | 2 +- .../f1u_split_connector_factory.h | 10 +-- .../f1u_split_connector_factory.h | 10 +-- include/srsran/gtpu/gtpu_gateway.h | 14 +-- lib/cu_up/cu_up_impl.cpp | 18 ++-- lib/cu_up/cu_up_impl.h | 16 ++-- lib/cu_up/cu_up_manager_impl.h | 20 ++--- lib/cu_up/pdu_session_manager_impl.cpp | 2 +- lib/cu_up/pdu_session_manager_impl.h | 86 +++++++++---------- lib/cu_up/ue_context.h | 34 ++++---- lib/cu_up/ue_manager.h | 54 ++++++------ .../split_connector/f1u_split_connector.cpp | 16 ++-- .../split_connector/f1u_split_connector.h | 16 ++-- .../du/split_connector/f1u_split_connector.h | 18 ++-- lib/gtpu/gtpu_gateway.cpp | 20 ++--- tests/unittests/cu_up/cu_up_test.cpp | 2 +- tests/unittests/cu_up/cu_up_test_helpers.h | 2 +- .../cu_up/pdu_session_manager_test.h | 2 +- tests/unittests/cu_up/ue_manager_test.cpp | 2 +- .../common/f1u_cu_split_connector_test.cpp | 12 +-- .../common/f1u_du_split_connector_test.cpp | 20 ++--- 26 files changed, 196 insertions(+), 196 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 91f126b358..0cf2a53a7f 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -287,7 +287,7 @@ int main(int argc, char** argv) cu_f1u_gw_config.bind_port = GTPU_PORT; cu_f1u_gw_config.reuse_addr = false; cu_f1u_gw_config.pool_occupancy_threshold = cu_cfg.nru_cfg.pool_occupancy_threshold; - std::unique_ptr cu_f1u_gw = + std::unique_ptr cu_f1u_gw = create_udp_ngu_gateway(cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor()); std::unique_ptr cu_f1u_conn = srs_cu_up::create_split_f1u_gw( {*cu_f1u_gw, *cu_f1u_gtpu_demux, *cu_up_dlt_pcaps.f1u, GTPU_PORT, cu_cfg.nru_cfg.ext_addr}); diff --git a/apps/du/du.cpp b/apps/du/du.cpp index b482e954f0..28eee64087 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -265,7 +265,7 @@ int main(int argc, char** argv) du_f1u_gw_config.bind_port = GTPU_PORT; du_f1u_gw_config.reuse_addr = false; du_f1u_gw_config.pool_occupancy_threshold = du_cfg.nru_cfg.pool_threshold; - std::unique_ptr du_f1u_gw = + std::unique_ptr du_f1u_gw = create_udp_ngu_gateway(du_f1u_gw_config, *epoll_broker, workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0))); diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 127a98ea94..74eb44c860 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -63,7 +63,7 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ srsran_assert(address.has_value(), "Invalid F1-U bind address"); // Create NG-U gateway(s). - std::vector> ngu_gws; + std::vector> ngu_gws; if (not unit_cfg.cu_up_cfg.ngu_cfg.no_core) { for (const cu_up_unit_ngu_socket_config& sock_cfg : unit_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg) { udp_network_gateway_config n3_udp_cfg = {}; @@ -75,12 +75,12 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets - std::unique_ptr ngu_gw = create_udp_ngu_gateway( + std::unique_ptr ngu_gw = create_udp_ngu_gateway( n3_udp_cfg, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); ngu_gws.push_back(std::move(ngu_gw)); } } else { - std::unique_ptr ngu_gw = create_no_core_ngu_gateway(); + std::unique_ptr ngu_gw = create_no_core_ngu_gateway(); ngu_gws.push_back(std::move(ngu_gw)); } diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp index 8cbc253d01..a10f07682f 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.cpp +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.cpp @@ -12,7 +12,7 @@ using namespace srsran; -o_cu_up_unit_impl::o_cu_up_unit_impl(std::vector> gateways_, +o_cu_up_unit_impl::o_cu_up_unit_impl(std::vector> gateways_, std::unique_ptr e2_metric_connector_, std::unique_ptr cu_up_) : gateways(std::move(gateways_)), e2_metric_connector(std::move(e2_metric_connector_)), cu_up(std::move(cu_up_)) diff --git a/apps/units/o_cu_up/o_cu_up_unit_impl.h b/apps/units/o_cu_up/o_cu_up_unit_impl.h index c8e5228cd6..c493cfbb64 100644 --- a/apps/units/o_cu_up/o_cu_up_unit_impl.h +++ b/apps/units/o_cu_up/o_cu_up_unit_impl.h @@ -27,7 +27,7 @@ using e2_cu_metrics_connector_manager = class o_cu_up_unit_impl : public srs_cu_up::o_cu_up { public: - o_cu_up_unit_impl(std::vector> gateways_, + o_cu_up_unit_impl(std::vector> gateways_, std::unique_ptr e2_metric_connector_, std::unique_ptr cu_up_); @@ -38,7 +38,7 @@ class o_cu_up_unit_impl : public srs_cu_up::o_cu_up srs_cu_up::cu_up_power_controller& get_power_controller() override; private: - std::vector> gateways; + std::vector> gateways; std::unique_ptr e2_metric_connector; std::unique_ptr cu_up; }; diff --git a/include/srsran/cu_up/cu_up_config.h b/include/srsran/cu_up/cu_up_config.h index 5c1012794d..cc0b41b976 100644 --- a/include/srsran/cu_up/cu_up_config.h +++ b/include/srsran/cu_up/cu_up_config.h @@ -81,7 +81,7 @@ struct cu_up_dependencies { /// E1AP connection client. e1_connection_client* e1_conn_client = nullptr; /// NG-U gateways - std::vector ngu_gws; + std::vector ngu_gws; }; } // namespace srs_cu_up diff --git a/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h b/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h index a8c53ccbae..eacc62dac8 100644 --- a/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h +++ b/include/srsran/f1u/cu_up/split_connector/f1u_split_connector_factory.h @@ -20,11 +20,11 @@ namespace srsran::srs_cu_up { struct f1u_cu_up_split_gateway_creation_msg { - ngu_gateway& udp_gw; - gtpu_demux& demux; - dlt_pcap& gtpu_pcap; - uint16_t peer_port; - std::string f1u_ext_addr = "auto"; + gtpu_gateway& udp_gw; + gtpu_demux& demux; + dlt_pcap& gtpu_pcap; + uint16_t peer_port; + std::string f1u_ext_addr = "auto"; }; std::unique_ptr create_split_f1u_gw(f1u_cu_up_split_gateway_creation_msg msg); diff --git a/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h b/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h index 215cfa73b9..5d53bf3dee 100644 --- a/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h +++ b/include/srsran/f1u/du/split_connector/f1u_split_connector_factory.h @@ -20,11 +20,11 @@ namespace srsran::srs_du { struct f1u_du_split_gateway_creation_msg { - ngu_gateway* udp_gw; - gtpu_demux* demux; - dlt_pcap& gtpu_pcap; - uint16_t peer_port; - std::string f1u_ext_addr = "auto"; + gtpu_gateway* udp_gw; + gtpu_demux* demux; + dlt_pcap& gtpu_pcap; + uint16_t peer_port; + std::string f1u_ext_addr = "auto"; }; std::unique_ptr create_split_f1u_gw(f1u_du_split_gateway_creation_msg msg); diff --git a/include/srsran/gtpu/gtpu_gateway.h b/include/srsran/gtpu/gtpu_gateway.h index efe788a910..9420a1ec25 100644 --- a/include/srsran/gtpu/gtpu_gateway.h +++ b/include/srsran/gtpu/gtpu_gateway.h @@ -24,10 +24,10 @@ class io_broker; /// - the reception of PDUs by the CU-UP via the NG-U interface, or the DU/CU-UP via the F1-U interface /// - the transmission of PDUs to the UPF via the NG-U interface, or the DU/CU-UP via the F1-U interface and /// - the creation and deallocation of the required network resources for the NG-U/F1-U interface. -class ngu_tnl_pdu_session : public udp_network_gateway_data_handler, public network_gateway_data_notifier_with_src_addr +class gtpu_tnl_pdu_session : public udp_network_gateway_data_handler, public network_gateway_data_notifier_with_src_addr { public: - ~ngu_tnl_pdu_session() override = default; + ~gtpu_tnl_pdu_session() override = default; /// \brief Get the address to which the socket is bound. /// @@ -42,16 +42,16 @@ class ngu_tnl_pdu_session : public udp_network_gateway_data_handler, public netw }; /// \brief This class is called by the CU-UP to instantiate new GTP-U TNL PDU sessions. -class ngu_gateway +class gtpu_gateway { public: - virtual ~ngu_gateway() = default; + virtual ~gtpu_gateway() = default; /// \brief Creates a new GTP-U TNL session and starts listening for incoming PDUs. /// \param[in] data_notifier The notifier to be used by the instantiated GTP-U TNL session to push received PDUs back /// to the CU-UP. /// \return Returns a new instance of a NG-U TNL PDU session. - virtual std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) = 0; + virtual std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) = 0; }; /// Creates a factory of GTP-U TNL sessions that handle the allocation of network resources for a UDP-based link. @@ -59,13 +59,13 @@ class ngu_gateway /// \param[in] io_brk IO broker that will manage the reception of new PDUs from the UDP socket. /// \param[in] io_tx_executor Executor that will be used to handle the transmission of PDUs to the UDP socket. /// \return Returns the instantiated GTP-U gateway. Returns nullptr, if the GTP-U gateway could not be established. -std::unique_ptr +std::unique_ptr create_udp_ngu_gateway(const udp_network_gateway_config& config, io_broker& io_brk, task_executor& io_tx_executor); /// \brief Creates a GTP-U gateway that establishes a connection to a null/dummy UPF. /// /// This type of GTP-U gateway is useful when testing the CU-UP without a real UPF. /// \return Returns the instantiated GTP-U gateway. -std::unique_ptr create_no_core_ngu_gateway(); +std::unique_ptr create_no_core_ngu_gateway(); } // namespace srsran diff --git a/lib/cu_up/cu_up_impl.cpp b/lib/cu_up/cu_up_impl.cpp index ca1aa972a1..e697b4983b 100644 --- a/lib/cu_up/cu_up_impl.cpp +++ b/lib/cu_up/cu_up_impl.cpp @@ -38,13 +38,13 @@ static cu_up_manager_impl_config generate_cu_up_manager_impl_config(const cu_up_ } static cu_up_manager_impl_dependencies -generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, - e1ap_interface& e1ap, - gtpu_network_gateway_adapter& gtpu_gw_adapter, - gtpu_demux& ngu_demux, - const std::vector>& ngu_gws, - gtpu_teid_pool& n3_teid_allocator, - gtpu_teid_pool& f1u_teid_allocator) +generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, + e1ap_interface& e1ap, + gtpu_network_gateway_adapter& gtpu_gw_adapter, + gtpu_demux& ngu_demux, + const std::vector>& ngu_gws, + gtpu_teid_pool& n3_teid_allocator, + gtpu_teid_pool& f1u_teid_allocator) { return {e1ap, gtpu_gw_adapter, @@ -88,8 +88,8 @@ cu_up::cu_up(const cu_up_config& config_, const cu_up_dependencies& dependencies // Establish new NG-U session and connect the instantiated session to the GTP-U DEMUX adapter, so that the latter // is called when new NG-U DL PDUs are received. - for (ngu_gateway* gw : dependencies.ngu_gws) { - std::unique_ptr ngu_session = gw->create(gw_data_gtpu_demux_adapter); + for (gtpu_gateway* gw : dependencies.ngu_gws) { + std::unique_ptr ngu_session = gw->create(gw_data_gtpu_demux_adapter); if (ngu_session == nullptr) { report_error("Unable to allocate the required NG-U network resources"); } diff --git a/lib/cu_up/cu_up_impl.h b/lib/cu_up/cu_up_impl.h index f8436e5d96..a90c3e9ece 100644 --- a/lib/cu_up/cu_up_impl.h +++ b/lib/cu_up/cu_up_impl.h @@ -61,14 +61,14 @@ class cu_up final : public cu_up_interface std::unique_ptr ctrl_exec_mapper; // Components - std::atomic e1ap_connected = {false}; - std::unique_ptr e1ap; - std::vector> ngu_sessions; - std::unique_ptr ngu_demux; - std::unique_ptr ngu_echo; - std::unique_ptr n3_teid_allocator; - std::unique_ptr f1u_teid_allocator; - std::unique_ptr cu_up_mng; + std::atomic e1ap_connected = {false}; + std::unique_ptr e1ap; + std::vector> ngu_sessions; + std::unique_ptr ngu_demux; + std::unique_ptr ngu_echo; + std::unique_ptr n3_teid_allocator; + std::unique_ptr f1u_teid_allocator; + std::unique_ptr cu_up_mng; // Adapters network_gateway_data_gtpu_demux_adapter gw_data_gtpu_demux_adapter; diff --git a/lib/cu_up/cu_up_manager_impl.h b/lib/cu_up/cu_up_manager_impl.h index 437bc0c0b0..fee21a50f6 100644 --- a/lib/cu_up/cu_up_manager_impl.h +++ b/lib/cu_up/cu_up_manager_impl.h @@ -29,16 +29,16 @@ struct cu_up_manager_impl_config { /// CU-UP manager implementation dependencies. struct cu_up_manager_impl_dependencies { - e1ap_interface& e1ap; - gtpu_network_gateway_adapter& gtpu_gw_adapter; - gtpu_demux& ngu_demux; - const std::vector>& ngu_gws; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_mapper; - f1u_cu_up_gateway& f1u_gateway; - timer_manager& timers; - dlt_pcap& gtpu_pcap; + e1ap_interface& e1ap; + gtpu_network_gateway_adapter& gtpu_gw_adapter; + gtpu_demux& ngu_demux; + const std::vector>& ngu_gws; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_mapper; + f1u_cu_up_gateway& f1u_gateway; + timer_manager& timers; + dlt_pcap& gtpu_pcap; }; class cu_up_manager_impl final : public cu_up_manager diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index d799ecfa8c..1739a211f8 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -32,7 +32,7 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t timer_factory ue_ul_timer_factory_, timer_factory ue_ctrl_timer_factory_, f1u_cu_up_gateway& f1u_gw_, - const std::vector>& ngu_gws_, + const std::vector>& ngu_gws_, gtpu_teid_pool& n3_teid_allocator_, gtpu_teid_pool& f1u_teid_allocator_, gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index 99dff65db2..c40403c3c1 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -30,27 +30,27 @@ namespace srs_cu_up { class pdu_session_manager_impl final : public pdu_session_manager_ctrl { public: - pdu_session_manager_impl(ue_index_t ue_index_, - std::map qos_cfg_, - const security::sec_as_config& security_info_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - const std::vector>& ngu_gws_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - task_executor& ue_dl_exec_, - task_executor& ue_ul_exec_, - task_executor& ue_ctrl_exec_, - task_executor& crypto_exec_, - dlt_pcap& gtpu_pcap_); + pdu_session_manager_impl(ue_index_t ue_index_, + std::map qos_cfg_, + const security::sec_as_config& security_info_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + cu_up_ue_logger& logger_, + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + const std::vector>& ngu_gws_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, + gtpu_demux_ctrl& gtpu_rx_demux_, + task_executor& ue_dl_exec_, + task_executor& ue_ul_exec_, + task_executor& ue_ctrl_exec_, + task_executor& crypto_exec_, + dlt_pcap& gtpu_pcap_); pdu_session_setup_result setup_pdu_session(const e1ap_pdu_session_res_to_setup_item& session) override; pdu_session_modification_result modify_pdu_session(const e1ap_pdu_session_res_to_modify_item& session, @@ -73,28 +73,28 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl drb_setup_result handle_drb_to_setup_item(pdu_session& new_session, const e1ap_drb_to_setup_item_ng_ran& drb_to_setup); - ue_index_t ue_index; - const std::map qos_cfg; - const security::sec_as_config& security_info; - const n3_interface_config& n3_config; - cu_up_test_mode_config test_mode_config; - cu_up_ue_logger& logger; - unique_timer& ue_inactivity_timer; - timer_factory ue_dl_timer_factory; - timer_factory ue_ul_timer_factory; - timer_factory ue_ctrl_timer_factory; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - gtpu_demux_ctrl& gtpu_rx_demux; - task_executor& ue_dl_exec; - task_executor& ue_ul_exec; - task_executor& ue_ctrl_exec; - task_executor& crypto_exec; - dlt_pcap& gtpu_pcap; - f1u_cu_up_gateway& f1u_gw; - const std::vector>& ngu_gws; - std::map> pdu_sessions; // key is pdu_session_id + ue_index_t ue_index; + const std::map qos_cfg; + const security::sec_as_config& security_info; + const n3_interface_config& n3_config; + cu_up_test_mode_config test_mode_config; + cu_up_ue_logger& logger; + unique_timer& ue_inactivity_timer; + timer_factory ue_dl_timer_factory; + timer_factory ue_ul_timer_factory; + timer_factory ue_ctrl_timer_factory; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + gtpu_demux_ctrl& gtpu_rx_demux; + task_executor& ue_dl_exec; + task_executor& ue_ul_exec; + task_executor& ue_ctrl_exec; + task_executor& crypto_exec; + dlt_pcap& gtpu_pcap; + f1u_cu_up_gateway& f1u_gw; + const std::vector>& ngu_gws; + std::map> pdu_sessions; // key is pdu_session_id }; } // namespace srs_cu_up diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index d7218c4788..e82a93a45c 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -37,23 +37,23 @@ struct ue_context_cfg { class ue_context : public pdu_session_manager_ctrl { public: - ue_context(ue_index_t index_, - ue_context_cfg cfg_, - e1ap_control_message_handler& e1ap_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - std::unique_ptr ue_exec_mapper_, - fifo_async_task_scheduler& task_sched_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - const std::vector>& ngu_gws_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - dlt_pcap& gtpu_pcap) : + ue_context(ue_index_t index_, + ue_context_cfg cfg_, + e1ap_control_message_handler& e1ap_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + std::unique_ptr ue_exec_mapper_, + fifo_async_task_scheduler& task_sched_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + const std::vector>& ngu_gws_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, + gtpu_demux_ctrl& gtpu_rx_demux_, + dlt_pcap& gtpu_pcap) : task_sched(task_sched_), ue_exec_mapper(std::move(ue_exec_mapper_)), index(index_), diff --git a/lib/cu_up/ue_manager.h b/lib/cu_up/ue_manager.h index d8503be903..1d2b71eaea 100644 --- a/lib/cu_up/ue_manager.h +++ b/lib/cu_up/ue_manager.h @@ -29,17 +29,17 @@ struct ue_manager_config { /// UE manager dependencies. struct ue_manager_dependencies { - e1ap_control_message_handler& e1ap; - timer_manager& timers; - f1u_cu_up_gateway& f1u_gw; - const std::vector>& ngu_gws; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - dlt_pcap& gtpu_pcap; - srslog::basic_logger& logger; + e1ap_control_message_handler& e1ap; + timer_manager& timers; + f1u_cu_up_gateway& f1u_gw; + const std::vector>& ngu_gws; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + dlt_pcap& gtpu_pcap; + srslog::basic_logger& logger; }; class ue_manager : public ue_manager_ctrl @@ -63,22 +63,22 @@ class ue_manager : public ue_manager_ctrl /// \return The UE index. ue_index_t get_next_ue_index(); - const n3_interface_config& n3_config; - const cu_up_test_mode_config& test_mode_config; - e1ap_control_message_handler& e1ap; - f1u_cu_up_gateway& f1u_gw; - const std::vector>& ngu_gws; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - task_executor& ctrl_executor; - dlt_pcap& gtpu_pcap; - timer_manager& timers; - ue_db_t ue_db; - ue_task_schedulers_t ue_task_schedulers; - srslog::basic_logger& logger; + const n3_interface_config& n3_config; + const cu_up_test_mode_config& test_mode_config; + e1ap_control_message_handler& e1ap; + f1u_cu_up_gateway& f1u_gw; + const std::vector>& ngu_gws; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + task_executor& ctrl_executor; + dlt_pcap& gtpu_pcap; + timer_manager& timers; + ue_db_t ue_db; + ue_task_schedulers_t ue_task_schedulers; + srslog::basic_logger& logger; }; } // namespace srs_cu_up diff --git a/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp b/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp index afcba8fbb3..6349e2e78e 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.cpp @@ -28,11 +28,11 @@ class srs_cu_up::gtpu_tx_udp_gw_adapter : public gtpu_tunnel_common_tx_upper_lay } } - void connect(ngu_tnl_pdu_session& handler_) { handler = &handler_; } + void connect(gtpu_tnl_pdu_session& handler_) { handler = &handler_; } void disconnect() { handler = nullptr; } - ngu_tnl_pdu_session* handler = nullptr; + gtpu_tnl_pdu_session* handler = nullptr; }; class srs_cu_up::gtpu_rx_f1u_adapter : public srsran::gtpu_tunnel_nru_rx_lower_layer_notifier @@ -81,7 +81,7 @@ f1u_split_gateway_cu_bearer::f1u_split_gateway_cu_bearer(uint32_t drb_id_t drb_id, const up_transport_layer_info& ul_tnl_info_, f1u_cu_up_gateway_bearer_rx_notifier& cu_rx_, - ngu_tnl_pdu_session& udp_session, + gtpu_tnl_pdu_session& udp_session, task_executor& ul_exec_, srs_cu_up::f1u_bearer_disconnector& disconnector_) : ul_exec(ul_exec_), @@ -110,11 +110,11 @@ void f1u_split_gateway_cu_bearer::stop() stopped = true; } -f1u_split_connector::f1u_split_connector(ngu_gateway& udp_gw_, - gtpu_demux& demux_, - dlt_pcap& gtpu_pcap_, - uint16_t peer_port_, - std::string ext_addr_) : +f1u_split_connector::f1u_split_connector(gtpu_gateway& udp_gw_, + gtpu_demux& demux_, + dlt_pcap& gtpu_pcap_, + uint16_t peer_port_, + std::string ext_addr_) : logger_cu(srslog::fetch_basic_logger("CU-F1-U")), peer_port(peer_port_), ext_addr(std::move(ext_addr_)), diff --git a/lib/f1u/cu_up/split_connector/f1u_split_connector.h b/lib/f1u/cu_up/split_connector/f1u_split_connector.h index d9f33a05f1..4854095fe3 100644 --- a/lib/f1u/cu_up/split_connector/f1u_split_connector.h +++ b/lib/f1u/cu_up/split_connector/f1u_split_connector.h @@ -43,7 +43,7 @@ class f1u_split_gateway_cu_bearer final : public f1u_cu_up_gateway_bearer drb_id_t drb_id, const up_transport_layer_info& ul_tnl_info_, f1u_cu_up_gateway_bearer_rx_notifier& cu_rx_, - ngu_tnl_pdu_session& udp_session, + gtpu_tnl_pdu_session& udp_session, task_executor& ul_exec_, srs_cu_up::f1u_bearer_disconnector& disconnector_); @@ -103,11 +103,11 @@ class f1u_split_gateway_cu_bearer final : public f1u_cu_up_gateway_bearer class f1u_split_connector final : public f1u_cu_up_udp_gateway { public: - f1u_split_connector(ngu_gateway& udp_gw_, - gtpu_demux& demux_, - dlt_pcap& gtpu_pcap_, - uint16_t peer_port_ = GTPU_PORT, - std::string ext_addr_ = "auto"); + f1u_split_connector(gtpu_gateway& udp_gw_, + gtpu_demux& demux_, + dlt_pcap& gtpu_pcap_, + uint16_t peer_port_ = GTPU_PORT, + std::string ext_addr_ = "auto"); ~f1u_split_connector() override; f1u_cu_up_gateway* get_f1u_cu_up_gateway() { return this; } @@ -136,8 +136,8 @@ class f1u_split_connector final : public f1u_cu_up_udp_gateway uint16_t peer_port; std::string ext_addr; - ngu_gateway& udp_gw; - std::unique_ptr udp_session; + gtpu_gateway& udp_gw; + std::unique_ptr udp_session; gtpu_demux& demux; std::unique_ptr gw_data_gtpu_demux_adapter; dlt_pcap& gtpu_pcap; diff --git a/lib/f1u/du/split_connector/f1u_split_connector.h b/lib/f1u/du/split_connector/f1u_split_connector.h index ce5e1bac1f..0e205eefc5 100644 --- a/lib/f1u/du/split_connector/f1u_split_connector.h +++ b/lib/f1u/du/split_connector/f1u_split_connector.h @@ -38,11 +38,11 @@ class gtpu_tx_udp_gw_adapter : public gtpu_tunnel_common_tx_upper_layer_notifier } } - void connect(ngu_tnl_pdu_session& handler_) { handler = &handler_; } + void connect(gtpu_tnl_pdu_session& handler_) { handler = &handler_; } void disconnect() { handler = nullptr; } - ngu_tnl_pdu_session* handler; + gtpu_tnl_pdu_session* handler; }; class gtpu_rx_f1u_adapter : public srsran::gtpu_tunnel_nru_rx_lower_layer_notifier @@ -169,11 +169,11 @@ class f1u_split_gateway_du_bearer : public f1u_du_gateway_bearer class f1u_split_connector final : public f1u_du_udp_gateway { public: - f1u_split_connector(ngu_gateway* udp_gw_, - gtpu_demux* demux_, - dlt_pcap& gtpu_pcap_, - uint16_t peer_port_ = GTPU_PORT, - std::string f1u_ext_addr_ = "auto") : + f1u_split_connector(gtpu_gateway* udp_gw_, + gtpu_demux* demux_, + dlt_pcap& gtpu_pcap_, + uint16_t peer_port_ = GTPU_PORT, + std::string f1u_ext_addr_ = "auto") : logger_du(srslog::fetch_basic_logger("DU-F1-U")), udp_gw(udp_gw_), demux(demux_), @@ -208,8 +208,8 @@ class f1u_split_connector final : public f1u_du_udp_gateway std::unordered_map du_map; std::mutex map_mutex; // shared mutex for access to cu_map - ngu_gateway* udp_gw; - std::unique_ptr udp_session; + gtpu_gateway* udp_gw; + std::unique_ptr udp_session; gtpu_demux* demux; network_gateway_data_gtpu_demux_adapter gw_data_gtpu_demux_adapter; dlt_pcap& gtpu_pcap; diff --git a/lib/gtpu/gtpu_gateway.cpp b/lib/gtpu/gtpu_gateway.cpp index 2b0b4cb0c5..346a2e9a20 100644 --- a/lib/gtpu/gtpu_gateway.cpp +++ b/lib/gtpu/gtpu_gateway.cpp @@ -18,7 +18,7 @@ using namespace srsran; namespace { /// Implementation of a NG-U TNL PDU session that uses a UDP connection. -class udp_ngu_tnl_session final : public ngu_tnl_pdu_session +class udp_ngu_tnl_session final : public gtpu_tnl_pdu_session { // private ctor. udp_ngu_tnl_session(network_gateway_data_notifier_with_src_addr& data_notifier_) : @@ -80,7 +80,7 @@ class udp_ngu_tnl_session final : public ngu_tnl_pdu_session }; /// Implementation of the NG-U gateway for the case a UDP connection is used to a remote UPF. -class udp_ngu_gateway final : public ngu_gateway +class udp_ngu_gateway final : public gtpu_gateway { public: udp_ngu_gateway(const udp_network_gateway_config& cfg_, io_broker& io_brk_, task_executor& io_tx_executor_) : @@ -88,7 +88,7 @@ class udp_ngu_gateway final : public ngu_gateway { } - std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) override + std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) override { return udp_ngu_tnl_session::create(cfg, data_notifier, io_brk, io_tx_executor); } @@ -101,9 +101,9 @@ class udp_ngu_gateway final : public ngu_gateway } // namespace -std::unique_ptr srsran::create_udp_ngu_gateway(const udp_network_gateway_config& config, - io_broker& io_brk, - task_executor& io_tx_executor) +std::unique_ptr srsran::create_udp_ngu_gateway(const udp_network_gateway_config& config, + io_broker& io_brk, + task_executor& io_tx_executor) { return std::make_unique(config, io_brk, io_tx_executor); } @@ -113,7 +113,7 @@ std::unique_ptr srsran::create_udp_ngu_gateway(const udp_network_ga namespace { /// Implementation of an NG-U TNL PDU session when a local UPF stub is used. -class no_core_ngu_tnl_pdu_session final : public ngu_tnl_pdu_session +class no_core_ngu_tnl_pdu_session final : public gtpu_tnl_pdu_session { public: void handle_pdu(byte_buffer pdu, const sockaddr_storage& dest_addr) override @@ -132,10 +132,10 @@ class no_core_ngu_tnl_pdu_session final : public ngu_tnl_pdu_session }; /// Implementation of the NG-U gateway for the case a local UPF stub is used. -class no_core_ngu_gateway : public ngu_gateway +class no_core_ngu_gateway : public gtpu_gateway { public: - std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) override + std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) override { return std::make_unique(); } @@ -143,7 +143,7 @@ class no_core_ngu_gateway : public ngu_gateway } // namespace -std::unique_ptr srsran::create_no_core_ngu_gateway() +std::unique_ptr srsran::create_no_core_ngu_gateway() { return std::make_unique(); } diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index 2b6b31f3ec..017a666000 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -152,7 +152,7 @@ class cu_up_test : public ::testing::Test dummy_inner_f1u_bearer f1u_bearer; std::unique_ptr f1u_gw; std::unique_ptr broker; - std::unique_ptr ngu_gw; + std::unique_ptr ngu_gw; std::unique_ptr exec_pool; std::unique_ptr cu_up; srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index ebeeff272b..aae06d1b48 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -255,7 +255,7 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway std::list removed_ul_teid_list = {}; }; -class dummy_ngu_gateway final : public ngu_tnl_pdu_session +class dummy_ngu_gateway final : public gtpu_tnl_pdu_session { bool get_bind_address(std::string& ip_address) const override { diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index ba51f6f67e..681f65066c 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -85,7 +85,7 @@ class pdu_session_manager_test_base std::unique_ptr gtpu_tx_notifier; dummy_inner_f1u_bearer f1u_bearer; std::unique_ptr f1u_gw; - std::vector> ngu_gws; + std::vector> ngu_gws; std::unique_ptr n3_allocator; std::unique_ptr f1u_allocator; std::unique_ptr pdu_session_mng; diff --git a/tests/unittests/cu_up/ue_manager_test.cpp b/tests/unittests/cu_up/ue_manager_test.cpp index 9d1abb80fc..64167d86af 100644 --- a/tests/unittests/cu_up/ue_manager_test.cpp +++ b/tests/unittests/cu_up/ue_manager_test.cpp @@ -72,7 +72,7 @@ class ue_manager_test : public ::testing::Test dummy_inner_f1u_bearer f1u_bearer; null_dlt_pcap gtpu_pcap; std::unique_ptr f1u_gw; - std::vector> ngu_gws; + std::vector> ngu_gws; timer_manager timers; ue_context_cfg ue_cfg; std::unique_ptr ue_mng; diff --git a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp index 4e7bed6b8b..4ede48b3b7 100644 --- a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp @@ -195,12 +195,12 @@ class f1u_cu_split_connector_test : public ::testing::Test virtual std::string get_external_bind_address() { return "auto"; } - manual_task_worker ue_worker{128}; - std::unique_ptr epoll_broker; - manual_task_worker io_tx_executor{128}; - std::unique_ptr demux; - std::unique_ptr udp_gw; - null_dlt_pcap dummy_pcap = {}; + manual_task_worker ue_worker{128}; + std::unique_ptr epoll_broker; + manual_task_worker io_tx_executor{128}; + std::unique_ptr demux; + std::unique_ptr udp_gw; + null_dlt_pcap dummy_pcap = {}; // Tester UDP gw to TX/RX PDUs to F1-U CU GW std::unique_ptr udp_tester; diff --git a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp index ef452ece24..890b7f609a 100644 --- a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp @@ -181,16 +181,16 @@ class f1u_du_split_connector_test : public ::testing::Test virtual std::string get_external_bind_address() { return "auto"; } - timer_manager timer_mng; - manual_task_worker ue_worker{128}; - timer_factory timers; - unique_timer ue_inactivity_timer; - std::unique_ptr epoll_broker; - manual_task_worker io_tx_executor{128}; - std::unique_ptr demux; - std::unique_ptr udp_gw; - null_dlt_pcap dummy_pcap = {}; - std::string du_gw_bind_address = "127.0.0.2"; + timer_manager timer_mng; + manual_task_worker ue_worker{128}; + timer_factory timers; + unique_timer ue_inactivity_timer; + std::unique_ptr epoll_broker; + manual_task_worker io_tx_executor{128}; + std::unique_ptr demux; + std::unique_ptr udp_gw; + null_dlt_pcap dummy_pcap = {}; + std::string du_gw_bind_address = "127.0.0.2"; // Tester UDP gw to TX/RX PDUs to F1-U CU GW std::unique_ptr udp_tester; From f41c1db4c3cbcf72484da5de18b04c190122a769 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Thu, 5 Dec 2024 16:22:24 +0000 Subject: [PATCH 074/227] gtpu: rename create gtpu factories --- apps/cu/cu.cpp | 2 +- apps/du/du.cpp | 8 ++++---- apps/units/o_cu_up/o_cu_up_builder.cpp | 4 ++-- include/srsran/gtpu/gtpu_gateway.h | 4 ++-- lib/gtpu/gtpu_gateway.cpp | 8 ++++---- tests/unittests/cu_up/cu_up_test.cpp | 2 +- .../unittests/f1u/common/f1u_cu_split_connector_test.cpp | 2 +- .../unittests/f1u/common/f1u_du_split_connector_test.cpp | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 0cf2a53a7f..373ce4c6a1 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -288,7 +288,7 @@ int main(int argc, char** argv) cu_f1u_gw_config.reuse_addr = false; cu_f1u_gw_config.pool_occupancy_threshold = cu_cfg.nru_cfg.pool_occupancy_threshold; std::unique_ptr cu_f1u_gw = - create_udp_ngu_gateway(cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor()); + create_udp_gtpu_gateway(cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor()); std::unique_ptr cu_f1u_conn = srs_cu_up::create_split_f1u_gw( {*cu_f1u_gw, *cu_f1u_gtpu_demux, *cu_up_dlt_pcaps.f1u, GTPU_PORT, cu_cfg.nru_cfg.ext_addr}); diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 28eee64087..65d44e55d4 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -265,10 +265,10 @@ int main(int argc, char** argv) du_f1u_gw_config.bind_port = GTPU_PORT; du_f1u_gw_config.reuse_addr = false; du_f1u_gw_config.pool_occupancy_threshold = du_cfg.nru_cfg.pool_threshold; - std::unique_ptr du_f1u_gw = - create_udp_ngu_gateway(du_f1u_gw_config, - *epoll_broker, - workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0))); + std::unique_ptr du_f1u_gw = create_udp_gtpu_gateway( + du_f1u_gw_config, + *epoll_broker, + workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0))); std::unique_ptr du_f1u_conn = srs_du::create_split_f1u_gw( {du_f1u_gw.get(), du_f1u_gtpu_demux.get(), *du_pcaps.f1u, GTPU_PORT, du_cfg.nru_cfg.ext_addr}); diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 74eb44c860..a6b2f97761 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -75,12 +75,12 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets - std::unique_ptr ngu_gw = create_udp_ngu_gateway( + std::unique_ptr ngu_gw = create_udp_gtpu_gateway( n3_udp_cfg, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); ngu_gws.push_back(std::move(ngu_gw)); } } else { - std::unique_ptr ngu_gw = create_no_core_ngu_gateway(); + std::unique_ptr ngu_gw = create_no_core_gtpu_gateway(); ngu_gws.push_back(std::move(ngu_gw)); } diff --git a/include/srsran/gtpu/gtpu_gateway.h b/include/srsran/gtpu/gtpu_gateway.h index 9420a1ec25..43ad0af336 100644 --- a/include/srsran/gtpu/gtpu_gateway.h +++ b/include/srsran/gtpu/gtpu_gateway.h @@ -60,12 +60,12 @@ class gtpu_gateway /// \param[in] io_tx_executor Executor that will be used to handle the transmission of PDUs to the UDP socket. /// \return Returns the instantiated GTP-U gateway. Returns nullptr, if the GTP-U gateway could not be established. std::unique_ptr -create_udp_ngu_gateway(const udp_network_gateway_config& config, io_broker& io_brk, task_executor& io_tx_executor); +create_udp_gtpu_gateway(const udp_network_gateway_config& config, io_broker& io_brk, task_executor& io_tx_executor); /// \brief Creates a GTP-U gateway that establishes a connection to a null/dummy UPF. /// /// This type of GTP-U gateway is useful when testing the CU-UP without a real UPF. /// \return Returns the instantiated GTP-U gateway. -std::unique_ptr create_no_core_ngu_gateway(); +std::unique_ptr create_no_core_gtpu_gateway(); } // namespace srsran diff --git a/lib/gtpu/gtpu_gateway.cpp b/lib/gtpu/gtpu_gateway.cpp index 346a2e9a20..7932d8c71e 100644 --- a/lib/gtpu/gtpu_gateway.cpp +++ b/lib/gtpu/gtpu_gateway.cpp @@ -101,9 +101,9 @@ class udp_ngu_gateway final : public gtpu_gateway } // namespace -std::unique_ptr srsran::create_udp_ngu_gateway(const udp_network_gateway_config& config, - io_broker& io_brk, - task_executor& io_tx_executor) +std::unique_ptr srsran::create_udp_gtpu_gateway(const udp_network_gateway_config& config, + io_broker& io_brk, + task_executor& io_tx_executor) { return std::make_unique(config, io_brk, io_tx_executor); } @@ -143,7 +143,7 @@ class no_core_ngu_gateway : public gtpu_gateway } // namespace -std::unique_ptr srsran::create_no_core_ngu_gateway() +std::unique_ptr srsran::create_no_core_gtpu_gateway() { return std::make_unique(); } diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index 017a666000..cbae0fd8c8 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -128,7 +128,7 @@ class cu_up_test : public ::testing::Test deps.exec_mapper = exec_pool.get(); deps.e1_conn_client = &e1ap_client; deps.f1u_gateway = f1u_gw.get(); - ngu_gw = create_udp_ngu_gateway(cu_up_udp_cfg, *broker, *executor); + ngu_gw = create_udp_gtpu_gateway(cu_up_udp_cfg, *broker, *executor); deps.ngu_gws.push_back(ngu_gw.get()); deps.timers = app_timers.get(); return deps; diff --git a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp index 4ede48b3b7..ef296df8b5 100644 --- a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp @@ -131,7 +131,7 @@ class f1u_cu_split_connector_test : public ::testing::Test nru_gw_config.bind_address = cu_gw_bind_address; nru_gw_config.bind_port = 0; nru_gw_config.reuse_addr = true; - udp_gw = create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); + udp_gw = create_udp_gtpu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); f1u_cu_up_split_gateway_creation_msg cu_create_msg{ *udp_gw, *demux, dummy_pcap, tester_bind_port.value(), get_external_bind_address()}; diff --git a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp index 890b7f609a..c3214d6a95 100644 --- a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp @@ -111,7 +111,7 @@ class f1u_du_split_connector_test : public ::testing::Test nru_gw_config.bind_address = du_gw_bind_address; nru_gw_config.bind_port = 0; nru_gw_config.reuse_addr = true; - udp_gw = create_udp_ngu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); + udp_gw = create_udp_gtpu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); f1u_du_split_gateway_creation_msg cu_create_msg{ udp_gw.get(), demux.get(), dummy_pcap, tester_bind_port.value(), get_external_bind_address()}; From f236fe82c02e4998a210a0227b3b51d5e2dc6de0 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 21 Nov 2024 16:15:58 +0100 Subject: [PATCH 075/227] sched: fix UL power controller reconfiguration Signed-off-by: Carlo Galiotto --- .../srsran/ran/logical_channel/phr_report.h | 2 - lib/scheduler/support/ul_power_controller.cpp | 38 +++++++++++++++---- lib/scheduler/support/ul_power_controller.h | 10 +++-- lib/scheduler/ue_context/ue_cell.cpp | 4 +- .../ue_scheduling/ue_event_manager.cpp | 2 +- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/include/srsran/ran/logical_channel/phr_report.h b/include/srsran/ran/logical_channel/phr_report.h index f90b8ba756..a023422487 100644 --- a/include/srsran/ran/logical_channel/phr_report.h +++ b/include/srsran/ran/logical_channel/phr_report.h @@ -42,8 +42,6 @@ struct cell_ph_report { /// UE configured maximum output power used in computation of Power Headroom level. This field maps to P_CMAX,f,c in /// table 6.1.3.8-2 of TS 38.321. This field is optional only in case of Multiple Entry PHR. std::optional p_cmax; - /// Indicates the slot at which the PHR was received. - slot_point slot_rx; }; /// UL Power Headroom Report (PHR). diff --git a/lib/scheduler/support/ul_power_controller.cpp b/lib/scheduler/support/ul_power_controller.cpp index 8c178f4479..8ca141875d 100644 --- a/lib/scheduler/support/ul_power_controller.cpp +++ b/lib/scheduler/support/ul_power_controller.cpp @@ -14,20 +14,28 @@ using namespace srsran; -ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell_cfg_, +ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell_cfg, const ue_channel_state_manager& ch_state_manager) : - ue_cell_cfg(ue_cell_cfg_), + p0_nominal_pusch( + ue_cell_cfg.cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().p0_nominal_with_grant.to_int()), channel_state_manager(ch_state_manager), - pusch_sinr_target_dB(ue_cell_cfg_.cell_cfg_common.expert_cfg.ue.target_pusch_sinr), - ref_path_loss_for_target_sinr(ue_cell_cfg_.cell_cfg_common.expert_cfg.ue.path_loss_for_target_pusch_sinr), - tpc_adjust_prohibit_time_sl([this]() -> unsigned { + pusch_sinr_target_dB(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.target_pusch_sinr), + ref_path_loss_for_target_sinr(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.path_loss_for_target_pusch_sinr), + tpc_adjust_prohibit_time_sl([&ue_cell_cfg]() -> unsigned { return tpc_adjust_prohibit_time_ms << to_numerology_value( ue_cell_cfg.cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs); }()), logger(srslog::fetch_basic_logger("SCHED")) { + // Save the PUSCH power control configuration. + reconfigure(ue_cell_cfg); + // Initialize PUSCH PRB grid. - std::fill(pusch_pw_ctrl_grid.begin(), pusch_pw_ctrl_grid.end(), pusch_pw_ctrl_data{slot_point{}, 0}); + static constexpr unsigned init_nof_prbs = 0U; + static constexpr int init_f_pw_control = 0; + std::fill(pusch_pw_ctrl_grid.begin(), + pusch_pw_ctrl_grid.end(), + pusch_pw_ctrl_data{slot_point{}, init_nof_prbs, init_f_pw_control}); // Dummy casts only needed to prevent Clang from complaining about unused variables. static_cast(channel_state_manager); @@ -35,8 +43,21 @@ ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell static_cast(pusch_sinr_target_dB); } -SRSRAN_WEAK_SYMB void ul_power_controller::handle_phr(const cell_ph_report& phr) +void ul_power_controller::reconfigure(const ue_cell_configuration& ue_cell_cfg) +{ + if (ue_cell_cfg.cfg_dedicated().ul_config.has_value() and + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pusch_cfg.has_value() and + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pusch_cfg.value().pusch_pwr_ctrl.has_value()) { + pusch_pwr_ctrl.emplace( + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pusch_cfg.value().pusch_pwr_ctrl.value()); + } +} + +SRSRAN_WEAK_SYMB void ul_power_controller::handle_phr(const cell_ph_report& phr, slot_point slot_rx) { + if (not pusch_pwr_ctrl.has_value()) { + return; + } latest_phr.emplace(ue_phr_report{phr, std::nullopt}); } @@ -44,7 +65,8 @@ void ul_power_controller::update_pusch_pw_ctrl_state(slot_point slot_rx, unsigne { const int latest_f_cl_pw_control = latest_pusch_pw_control.has_value() ? latest_pusch_pw_control.value().f_cl_pw_control : 0; - pusch_pw_ctrl_grid[slot_rx.to_uint()] = {slot_rx, nof_prbs, latest_f_cl_pw_control}; + const unsigned grid_idx = slot_rx.to_uint(); + pusch_pw_ctrl_grid[grid_idx] = {slot_rx, nof_prbs, latest_f_cl_pw_control}; } SRSRAN_WEAK_SYMB unsigned ul_power_controller::adapt_pusch_prbs_to_phr(unsigned nof_prbs) const diff --git a/lib/scheduler/support/ul_power_controller.h b/lib/scheduler/support/ul_power_controller.h index ac1b8a788b..20f29f2bdf 100644 --- a/lib/scheduler/support/ul_power_controller.h +++ b/lib/scheduler/support/ul_power_controller.h @@ -21,8 +21,11 @@ class ul_power_controller public: ul_power_controller(const ue_cell_configuration& ue_cell_cfg_, const ue_channel_state_manager& ch_state_manager); + /// Save the PUSCH power control configuration. + void reconfigure(const ue_cell_configuration& ue_cell_cfg); + /// Update UE with the latest PHR for a given cell. - void handle_phr(const cell_ph_report& phr); + void handle_phr(const cell_ph_report& phr, slot_point slot_rx); /// Save the PUSCH power control parameters after each PUSCH transmission. void update_pusch_pw_ctrl_state(slot_point slot, unsigned nof_prbs); @@ -47,8 +50,9 @@ class ul_power_controller // SINR) for the PUSCH with the latest power adjustment is received, before a new power adjustment is computed. static constexpr unsigned tpc_adjust_prohibit_time_ms = 40U; - const ue_cell_configuration& ue_cell_cfg; - const ue_channel_state_manager& channel_state_manager; + const int p0_nominal_pusch; + std::optional pusch_pwr_ctrl; + const ue_channel_state_manager& channel_state_manager; /// \brief Latest PHR received from the UE. struct ue_phr_report { diff --git a/lib/scheduler/ue_context/ue_cell.cpp b/lib/scheduler/ue_context/ue_cell.cpp index 345e7943f0..d054a977b5 100644 --- a/lib/scheduler/ue_context/ue_cell.cpp +++ b/lib/scheduler/ue_context/ue_cell.cpp @@ -89,6 +89,8 @@ void ue_cell::handle_reconfiguration_request(const ue_cell_configuration& ue_cel h_ul->cancel_retxs(); } } + + get_ul_power_controller().reconfigure(ue_cell_cfg); } void ue_cell::set_fallback_state(bool set_fallback) @@ -246,7 +248,7 @@ grant_prbs_mcs ue_cell::required_ul_prbs(const pusch_time_domain_resource_alloca sch_mcs_description mcs_config = pusch_mcs_get_config(pusch_cfg.mcs_table, mcs, pusch_cfg.use_transform_precoder, false); - const unsigned nof_symbols = static_cast(pusch_td_cfg.symbols.length()); + const auto nof_symbols = static_cast(pusch_td_cfg.symbols.length()); sch_prbs_tbs prbs_tbs = get_nof_prbs(prbs_calculator_sch_config{pending_bytes, nof_symbols, diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 4eabffbf70..0483cce745 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -415,7 +415,7 @@ void ue_event_manager::handle_ul_phr_indication(const ul_phr_indication_message& cell_phr.serv_cell_id < u.nof_cells(), "Invalid serving cell index={}", cell_phr.serv_cell_id); auto& ue_cc = u.get_cell(cell_phr.serv_cell_id); - ue_cc.get_ul_power_controller().handle_phr(cell_phr); + ue_cc.get_ul_power_controller().handle_phr(cell_phr, phr_ind->slot_rx); // Log event. scheduler_event_logger::phr_event event{}; From c3fb2a1bc81b55db13ca680695710c319a93fb30 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 22 Nov 2024 17:12:19 +0100 Subject: [PATCH 076/227] du: add option to disable UL closed-loop pw ctrl Signed-off-by: Carlo Galiotto --- .../flexible_o_du/o_du_high/du_high/du_high_config.h | 8 ++++++-- .../o_du_high/du_high/du_high_config_translators.cpp | 1 + include/srsran/scheduler/config/scheduler_expert_config.h | 4 ++++ lib/scheduler/support/ul_power_controller.cpp | 1 + lib/scheduler/support/ul_power_controller.h | 1 + 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 32aafa3b30..61781e1712 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -236,11 +236,15 @@ struct du_high_unit_pusch_config { /// End RB for resource allocation of UE PUSCHs. unsigned end_rb = MAX_NOF_PRBS; - /// Target PUSCH SINR to be achieved with close-loop power control, in dB. + /// Enable closed-loop PUSCH power control. + bool enable_closed_loop_pw_control = true; + /// Target PUSCH SINR to be achieved with close-loop power control, in dB. Only relevant if \c + /// enable_closed_loop_pw_control is set to true. float target_pusch_sinr{10.0f}; /// Path-loss at which the Target PUSCH SINR is expected to be achieved, in dB. /// This is used to compute the path loss compensation for PUSCH fractional power control. The value must be positive. - /// Only relevant if \c path_loss_compensation_factor is set to a value different from 1.0. + /// Only relevant if \c enable_closed_loop_pw_control is set to true and \c path_loss_compensation_factor is set to a + /// value different from 1.0. float path_loss_for_target_pusch_sinr{70.0f}; /// Factor "alpha" for fractional path-loss compensation in PUSCH power control. /// Values: {0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index fab0696daa..28002e653c 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -902,6 +902,7 @@ scheduler_expert_config srsran::generate_scheduler_expert_config(const du_high_u if (std::holds_alternative(app_sched_expert_cfg.policy_sched_expert_cfg)) { out_cfg.ue.strategy_cfg = app_sched_expert_cfg.policy_sched_expert_cfg; } + out_cfg.ue.enable_closed_loop_pw_control = pusch.enable_closed_loop_pw_control; out_cfg.ue.target_pusch_sinr = pusch.target_pusch_sinr; out_cfg.ue.path_loss_for_target_pusch_sinr = pusch.path_loss_for_target_pusch_sinr; out_cfg.ue.ta_cmd_offset_threshold = app_sched_expert_cfg.ta_sched_cfg.ta_cmd_offset_threshold; diff --git a/include/srsran/scheduler/config/scheduler_expert_config.h b/include/srsran/scheduler/config/scheduler_expert_config.h index f8cd678c5d..0a909766c8 100644 --- a/include/srsran/scheduler/config/scheduler_expert_config.h +++ b/include/srsran/scheduler/config/scheduler_expert_config.h @@ -105,10 +105,14 @@ struct scheduler_ue_expert_config { uint8_t min_k1 = 4; /// Maximum number of PDCCH grant allocation attempts per slot. Default: Unlimited. unsigned max_pdcch_alloc_attempts_per_slot = std::max(MAX_DL_PDCCH_PDUS_PER_SLOT, MAX_UL_PDCCH_PDUS_PER_SLOT); + /// Enable closed-loop PUSCH power control. + bool enable_closed_loop_pw_control = true; /// Target PUSCH SINR to be achieved with Close-loop power control, in dB. + /// Only relevant if \c enable_closed_loop_pw_control is set to true. float target_pusch_sinr{10.0f}; /// Path-loss at which the Target PUSCH SINR is expected to be achieved, in dB. /// This is used to compute the path loss compensation for PUSCH fractional power control. + /// Only relevant if \c enable_closed_loop_pw_control is set to true. float path_loss_for_target_pusch_sinr{70.0f}; /// CQI offset increment used in outer loop link adaptation (OLLA) algorithm. If set to zero, OLLA is disabled. float olla_cqi_inc{0.001}; diff --git a/lib/scheduler/support/ul_power_controller.cpp b/lib/scheduler/support/ul_power_controller.cpp index 8ca141875d..02b5fb8734 100644 --- a/lib/scheduler/support/ul_power_controller.cpp +++ b/lib/scheduler/support/ul_power_controller.cpp @@ -16,6 +16,7 @@ using namespace srsran; ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell_cfg, const ue_channel_state_manager& ch_state_manager) : + cl_pw_control_enabled(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.enable_closed_loop_pw_control), p0_nominal_pusch( ue_cell_cfg.cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().p0_nominal_with_grant.to_int()), channel_state_manager(ch_state_manager), diff --git a/lib/scheduler/support/ul_power_controller.h b/lib/scheduler/support/ul_power_controller.h index 20f29f2bdf..c16d67be53 100644 --- a/lib/scheduler/support/ul_power_controller.h +++ b/lib/scheduler/support/ul_power_controller.h @@ -50,6 +50,7 @@ class ul_power_controller // SINR) for the PUSCH with the latest power adjustment is received, before a new power adjustment is computed. static constexpr unsigned tpc_adjust_prohibit_time_ms = 40U; + const bool cl_pw_control_enabled; const int p0_nominal_pusch; std::optional pusch_pwr_ctrl; const ue_channel_state_manager& channel_state_manager; From d567dbedbfedd8d4a36debc1d7e44b8bc5a71cb1 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 22 Nov 2024 17:19:32 +0100 Subject: [PATCH 077/227] sched: cap f_cl_pw_ctrl to a minimum value Signed-off-by: Carlo Galiotto --- lib/scheduler/support/ul_power_controller.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/scheduler/support/ul_power_controller.h b/lib/scheduler/support/ul_power_controller.h index c16d67be53..4b5703a0e8 100644 --- a/lib/scheduler/support/ul_power_controller.h +++ b/lib/scheduler/support/ul_power_controller.h @@ -49,6 +49,9 @@ class ul_power_controller // [Implementation-defined] This value should be enough to guarantee that the CRC indication (reporting the PUSCH // SINR) for the PUSCH with the latest power adjustment is received, before a new power adjustment is computed. static constexpr unsigned tpc_adjust_prohibit_time_ms = 40U; + /// Minimum value for the closed-loop power control adjustment value. This is to avoid the power control going too + /// low. + static constexpr int min_f_cl_pw_control = -30; const bool cl_pw_control_enabled; const int p0_nominal_pusch; From a5e64218c7cf7bccaee658efcfd135c4bb20bf28 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 9 Dec 2024 17:50:20 +0100 Subject: [PATCH 078/227] sched: group pw ctrl parameters in ue expert cfg Signed-off-by: Carlo Galiotto --- .../o_du_high/du_high/du_high_config.h | 2 +- .../du_high/du_high_config_translators.cpp | 12 +++++----- .../config/scheduler_expert_config.h | 23 +++++++++++-------- lib/scheduler/support/ul_power_controller.cpp | 8 ++++--- lib/scheduler/support/ul_power_controller.h | 5 ++-- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 61781e1712..12f7cc3e1e 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -237,7 +237,7 @@ struct du_high_unit_pusch_config { unsigned end_rb = MAX_NOF_PRBS; /// Enable closed-loop PUSCH power control. - bool enable_closed_loop_pw_control = true; + bool enable_closed_loop_pw_control = false; /// Target PUSCH SINR to be achieved with close-loop power control, in dB. Only relevant if \c /// enable_closed_loop_pw_control is set to true. float target_pusch_sinr{10.0f}; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index 28002e653c..1f0c824cd6 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -902,12 +902,12 @@ scheduler_expert_config srsran::generate_scheduler_expert_config(const du_high_u if (std::holds_alternative(app_sched_expert_cfg.policy_sched_expert_cfg)) { out_cfg.ue.strategy_cfg = app_sched_expert_cfg.policy_sched_expert_cfg; } - out_cfg.ue.enable_closed_loop_pw_control = pusch.enable_closed_loop_pw_control; - out_cfg.ue.target_pusch_sinr = pusch.target_pusch_sinr; - out_cfg.ue.path_loss_for_target_pusch_sinr = pusch.path_loss_for_target_pusch_sinr; - out_cfg.ue.ta_cmd_offset_threshold = app_sched_expert_cfg.ta_sched_cfg.ta_cmd_offset_threshold; - out_cfg.ue.ta_target = app_sched_expert_cfg.ta_sched_cfg.ta_target; - out_cfg.ue.ta_measurement_slot_period = app_sched_expert_cfg.ta_sched_cfg.ta_measurement_slot_period; + out_cfg.ue.ul_power_ctrl.enable_pusch_cl_pw_control = pusch.enable_closed_loop_pw_control; + out_cfg.ue.ul_power_ctrl.target_pusch_sinr = pusch.target_pusch_sinr; + out_cfg.ue.ul_power_ctrl.path_loss_for_target_pusch_sinr = pusch.path_loss_for_target_pusch_sinr; + out_cfg.ue.ta_cmd_offset_threshold = app_sched_expert_cfg.ta_sched_cfg.ta_cmd_offset_threshold; + out_cfg.ue.ta_target = app_sched_expert_cfg.ta_sched_cfg.ta_target; + out_cfg.ue.ta_measurement_slot_period = app_sched_expert_cfg.ta_sched_cfg.ta_measurement_slot_period; out_cfg.ue.ta_update_measurement_ul_sinr_threshold = app_sched_expert_cfg.ta_sched_cfg.ta_update_measurement_ul_sinr_threshold; diff --git a/include/srsran/scheduler/config/scheduler_expert_config.h b/include/srsran/scheduler/config/scheduler_expert_config.h index 0a909766c8..b664a466b0 100644 --- a/include/srsran/scheduler/config/scheduler_expert_config.h +++ b/include/srsran/scheduler/config/scheduler_expert_config.h @@ -38,6 +38,18 @@ struct time_rr_scheduler_expert_config {}; /// \brief Policy scheduler expert parameters. using policy_scheduler_expert_config = std::variant; +struct ul_power_control { + /// Enable closed-loop PUSCH power control. + bool enable_pusch_cl_pw_control = false; + /// Target PUSCH SINR to be achieved with Close-loop power control, in dB. + /// Only relevant if \c enable_closed_loop_pw_control is set to true. + float target_pusch_sinr{10.0f}; + /// Path-loss at which the Target PUSCH SINR is expected to be achieved, in dB. + /// This is used to compute the path loss compensation for PUSCH fractional power control. + /// Only relevant if \c enable_closed_loop_pw_control is set to true. + float path_loss_for_target_pusch_sinr{70.0f}; +}; + /// \brief UE scheduling statically configurable expert parameters. struct scheduler_ue_expert_config { /// Range of allowed MCS indices for DL UE scheduling. To use a fixed mcs, set the minimum mcs equal to the maximum. @@ -105,15 +117,6 @@ struct scheduler_ue_expert_config { uint8_t min_k1 = 4; /// Maximum number of PDCCH grant allocation attempts per slot. Default: Unlimited. unsigned max_pdcch_alloc_attempts_per_slot = std::max(MAX_DL_PDCCH_PDUS_PER_SLOT, MAX_UL_PDCCH_PDUS_PER_SLOT); - /// Enable closed-loop PUSCH power control. - bool enable_closed_loop_pw_control = true; - /// Target PUSCH SINR to be achieved with Close-loop power control, in dB. - /// Only relevant if \c enable_closed_loop_pw_control is set to true. - float target_pusch_sinr{10.0f}; - /// Path-loss at which the Target PUSCH SINR is expected to be achieved, in dB. - /// This is used to compute the path loss compensation for PUSCH fractional power control. - /// Only relevant if \c enable_closed_loop_pw_control is set to true. - float path_loss_for_target_pusch_sinr{70.0f}; /// CQI offset increment used in outer loop link adaptation (OLLA) algorithm. If set to zero, OLLA is disabled. float olla_cqi_inc{0.001}; /// DL Target BLER to be achieved with OLLA. @@ -138,6 +141,8 @@ struct scheduler_ue_expert_config { crb_interval pusch_crb_limits{0, MAX_NOF_PRBS}; /// Expert parameters to be passed to the policy scheduler. policy_scheduler_expert_config strategy_cfg = time_rr_scheduler_expert_config{}; + /// Expert PUCCH/PUSCH power control parameters. + ul_power_control ul_power_ctrl = ul_power_control{}; }; /// \brief System Information scheduling statically configurable expert parameters. diff --git a/lib/scheduler/support/ul_power_controller.cpp b/lib/scheduler/support/ul_power_controller.cpp index 02b5fb8734..ea49d8d881 100644 --- a/lib/scheduler/support/ul_power_controller.cpp +++ b/lib/scheduler/support/ul_power_controller.cpp @@ -16,12 +16,13 @@ using namespace srsran; ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell_cfg, const ue_channel_state_manager& ch_state_manager) : - cl_pw_control_enabled(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.enable_closed_loop_pw_control), + cl_pw_control_enabled(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.ul_power_ctrl.enable_pusch_cl_pw_control), p0_nominal_pusch( ue_cell_cfg.cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().p0_nominal_with_grant.to_int()), channel_state_manager(ch_state_manager), - pusch_sinr_target_dB(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.target_pusch_sinr), - ref_path_loss_for_target_sinr(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.path_loss_for_target_pusch_sinr), + pusch_sinr_target_dB(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.ul_power_ctrl.target_pusch_sinr), + ref_path_loss_for_target_sinr( + ue_cell_cfg.cell_cfg_common.expert_cfg.ue.ul_power_ctrl.path_loss_for_target_pusch_sinr), tpc_adjust_prohibit_time_sl([&ue_cell_cfg]() -> unsigned { return tpc_adjust_prohibit_time_ms << to_numerology_value( ue_cell_cfg.cell_cfg_common.ul_cfg_common.init_ul_bwp.generic_params.scs); @@ -39,6 +40,7 @@ ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell pusch_pw_ctrl_data{slot_point{}, init_nof_prbs, init_f_pw_control}); // Dummy casts only needed to prevent Clang from complaining about unused variables. + static_cast(cl_pw_control_enabled); static_cast(channel_state_manager); static_cast(ref_path_loss_for_target_sinr); static_cast(pusch_sinr_target_dB); diff --git a/lib/scheduler/support/ul_power_controller.h b/lib/scheduler/support/ul_power_controller.h index 4b5703a0e8..fa79987038 100644 --- a/lib/scheduler/support/ul_power_controller.h +++ b/lib/scheduler/support/ul_power_controller.h @@ -53,8 +53,9 @@ class ul_power_controller /// low. static constexpr int min_f_cl_pw_control = -30; - const bool cl_pw_control_enabled; - const int p0_nominal_pusch; + const bool cl_pw_control_enabled; + const int p0_nominal_pusch; + // Configuration for the PUSCH power control. std::optional pusch_pwr_ctrl; const ue_channel_state_manager& channel_state_manager; From a4120feccf9931b0779466f33885d682a4e56c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 2 Dec 2024 16:25:26 +0100 Subject: [PATCH 079/227] ci: change smoke dpdk PR job to gcc ubuntu 22 --- .gitlab/ci/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 2d770281d5..1cbe76cd82 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -239,7 +239,7 @@ variables: - launch_tests variables: OS: ubuntu-24.04 - COMPILER: gcc + COMPILER: clang CMAKE_BUILD_TYPE: RelWithDebInfo ASSERT_LEVEL: PARANOID TEST_MODE: default @@ -288,8 +288,8 @@ variables: script: - *smoke_script variables: - OS: ubuntu-24.04 - COMPILER: clang + OS: ubuntu-22.04 + COMPILER: gcc CMAKE_BUILD_TYPE: Release ENABLE_UHD: "False" ENABLE_ZEROMQ: "False" From aa5cf132337b8b1882134a5eac7d181719f7e413 Mon Sep 17 00:00:00 2001 From: sauka Date: Tue, 10 Dec 2024 10:45:58 +0100 Subject: [PATCH 080/227] ofh: reduce workload of the integration test in the nightly --- tests/integrationtests/ofh/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrationtests/ofh/CMakeLists.txt b/tests/integrationtests/ofh/CMakeLists.txt index 7c00c10dd4..ad1b2bfd57 100644 --- a/tests/integrationtests/ofh/CMakeLists.txt +++ b/tests/integrationtests/ofh/CMakeLists.txt @@ -15,5 +15,5 @@ target_link_libraries(ofh_integration_test srsran_phy_support srsran_channel_precoder srsran_support) -add_test(ofh_integration_test ofh_integration_test) +add_test(ofh_integration_test ofh_integration_test -d \'{0,1}\') set_tests_properties(ofh_integration_test PROPERTIES LABELS "tsan;NO_MEMCHECK") From 70595413042af41efae6fb164151e65601c048b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 5 Dec 2024 17:51:52 +0100 Subject: [PATCH 081/227] ci: allow plugin ci to overwrite is using latest job --- .gitlab/ci-shared/plugin.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci-shared/plugin.yml b/.gitlab/ci-shared/plugin.yml index 682c9dfb29..c40e6c27fa 100644 --- a/.gitlab/ci-shared/plugin.yml +++ b/.gitlab/ci-shared/plugin.yml @@ -21,7 +21,7 @@ variables: ###### # CI # ###### -is using latest: +.is using latest: image: ubuntu:24.04 stage: ci rules: @@ -38,6 +38,9 @@ is using latest: echo "Please update to latest srsRAN commit: $SRSRAN_LATEST_COMMIT" exit 1 fi + +is using latest: + extends: .is using latest allow_failure: true download srsran: From 9a10cb047eeb9aacbe50d730386c18ca1d143e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Tue, 10 Dec 2024 11:07:30 +0100 Subject: [PATCH 082/227] ci: update retina --- .gitlab/ci/e2e/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 83583bfeac..762ed1dde4 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.58.0 +RETINA_VERSION=0.58.1 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From 6cbf15ddbd0816cfe16ef413df93b66855a988c8 Mon Sep 17 00:00:00 2001 From: yagoda Date: Mon, 9 Dec 2024 17:33:51 +0100 Subject: [PATCH 083/227] ntn: remove SR window lenght restrictions for NTN case --- .../du_high/du_high_config_validator.cpp | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index 7632002a4b..3868a14d1b 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -394,7 +394,8 @@ static bool validate_pusch_cell_unit_config(const du_high_unit_pusch_config& con /// Validates the given PUCCH cell application configuration. Returns true on success, otherwise false. static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& config, subcarrier_spacing scs_common, - unsigned nof_crbs) + unsigned nof_crbs, + bool ntn) { const du_high_unit_pucch_config& pucch_cfg = config.pucch_cfg; if (not config.csi_cfg.csi_rs_enabled and pucch_cfg.nof_cell_csi_resources > 0) { @@ -426,14 +427,16 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& get_nof_slots_per_subframe(scs_common)); return false; } - span valid_sr_period_slots = mu_to_valid_sr_period_slots_lookup.at(to_numerology_value(scs_common)); - if (std::find(valid_sr_period_slots.begin(), valid_sr_period_slots.end(), sr_period_slots) == - valid_sr_period_slots.end()) { - fmt::print("SR period of {}ms (i.e. {} slots) is not valid for {}kHz SCS.\n", - pucch_cfg.sr_period_msec, - sr_period_slots, - scs_to_khz(scs_common)); - return false; + if (!ntn) { + span valid_sr_period_slots = mu_to_valid_sr_period_slots_lookup.at(to_numerology_value(scs_common)); + if (std::find(valid_sr_period_slots.begin(), valid_sr_period_slots.end(), sr_period_slots) == + valid_sr_period_slots.end()) { + fmt::print("SR period of {}ms (i.e. {} slots) is not valid for {}kHz SCS.\n", + pucch_cfg.sr_period_msec, + sr_period_slots, + scs_to_khz(scs_common)); + return false; + } } // We need to count pucch_cfg.nof_ue_pucch_res_harq_per_set twice, as we have 2 sets of PUCCH resources for HARQ-ACK @@ -909,7 +912,7 @@ static bool validate_cell_sib_config(const du_high_unit_base_cell_config& cell_c } /// Validates the given cell application configuration. Returns true on success, otherwise false. -static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& config) +static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& config, bool ntn) { if (config.pci >= INVALID_PCI) { fmt::print("Invalid PCI (i.e. {}). PCI ranges from 0 to {}.\n", config.pci, MAX_PCI); @@ -972,7 +975,7 @@ static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& return false; } - if (!validate_pucch_cell_unit_config(config, config.common_scs, nof_crbs)) { + if (!validate_pucch_cell_unit_config(config, config.common_scs, nof_crbs, ntn)) { return false; } @@ -1007,17 +1010,17 @@ static bool validate_base_cell_unit_config(const du_high_unit_base_cell_config& return true; } -static bool validate_cell_unit_config(const du_high_unit_cell_config& config) +static bool validate_cell_unit_config(const du_high_unit_cell_config& config, bool ntn) { - return validate_base_cell_unit_config(config.cell); + return validate_base_cell_unit_config(config.cell, ntn); } /// Validates the given list of cell application configuration. Returns true on success, otherwise false. -static bool validate_cells_unit_config(span config, const gnb_id_t& gnb_id) +static bool validate_cells_unit_config(span config, const gnb_id_t& gnb_id, bool ntn) { unsigned tac = config[0].cell.tac; for (const auto& cell : config) { - if (!validate_cell_unit_config(cell)) { + if (!validate_cell_unit_config(cell, ntn)) { return false; } if (cell.cell.tac != tac) { @@ -1336,7 +1339,13 @@ static bool validate_qos_config(span config) bool srsran::validate_du_high_config(const du_high_unit_config& config, const os_sched_affinity_bitmask& available_cpus) { - if (!validate_cells_unit_config(config.cells_cfg, config.gnb_id)) { + bool ntn = false; + if (config.ntn_cfg.has_value()) { + if (config.ntn_cfg.has_value()) { + ntn = true; + } + } + if (!validate_cells_unit_config(config.cells_cfg, config.gnb_id, ntn)) { return false; } From b56cb659929e7941ca3391ce31505744d42b2d0b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 10 Dec 2024 11:39:08 +0100 Subject: [PATCH 084/227] cu_cp,ngap: add dummy nrppa implementation --- include/srsran/nrppa/nrppa_factory.h | 23 ++++++++++++++++ lib/CMakeLists.txt | 1 + lib/cu_cp/CMakeLists.txt | 1 + lib/cu_cp/cu_cp_impl.cpp | 3 ++- lib/nrppa/CMakeLists.txt | 21 +++++++++++++++ lib/nrppa/nrppa_dummy_factory.cpp | 29 +++++++++++++++++++++ lib/nrppa/nrppa_dummy_impl.cpp | 30 +++++++++++++++++++++ lib/nrppa/nrppa_dummy_impl.h | 39 ++++++++++++++++++++++++++++ 8 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 include/srsran/nrppa/nrppa_factory.h create mode 100644 lib/nrppa/CMakeLists.txt create mode 100644 lib/nrppa/nrppa_dummy_factory.cpp create mode 100644 lib/nrppa/nrppa_dummy_impl.cpp create mode 100644 lib/nrppa/nrppa_dummy_impl.h diff --git a/include/srsran/nrppa/nrppa_factory.h b/include/srsran/nrppa/nrppa_factory.h new file mode 100644 index 0000000000..6de860160d --- /dev/null +++ b/include/srsran/nrppa/nrppa_factory.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 "srsran/cu_cp/cu_cp_configuration.h" +#include "srsran/nrppa/nrppa.h" + +namespace srsran { +namespace srs_cu_cp { + +/// Creates an instance of an NRPPA interface, notifying outgoing packets on the specified listener object. +std::unique_ptr create_nrppa(const cu_cp_configuration& cfg, nrppa_cu_cp_notifier& cu_cp_notifier); + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f46c380eaf..b667b415af 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -27,6 +27,7 @@ endif (DPDK_FOUND) add_subdirectory(instrumentation) add_subdirectory(mac) add_subdirectory(ngap) +add_subdirectory(nrppa) add_subdirectory(nru) add_subdirectory(ofh) add_subdirectory(pcap) diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index 8e27cc27e3..28f305f00e 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -60,6 +60,7 @@ target_link_libraries(srsran_cu_cp srsran_e1ap_cu_cp srsran_f1ap_cu srsran_ngap + srsran_nrppa srsran_rrc srsran_ran srslog diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 2252cf4b58..90e6b7413f 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -26,6 +26,7 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/nrppa/nrppa.h" +#include "srsran/nrppa/nrppa_factory.h" #include "srsran/rrc/rrc_du.h" #include "srsran/support/compiler.h" #include @@ -158,7 +159,7 @@ bool cu_cp_impl::amfs_are_connected() SRSRAN_WEAK_SYMB std::unique_ptr cu_cp_impl::create_nrppa_entity(const cu_cp_configuration& cu_cp_cfg, nrppa_cu_cp_notifier& cu_cp_notif) { - return nullptr; + return create_nrppa(cu_cp_cfg, cu_cp_notif); } void cu_cp_impl::handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) diff --git a/lib/nrppa/CMakeLists.txt b/lib/nrppa/CMakeLists.txt new file mode 100644 index 0000000000..5bee1103a8 --- /dev/null +++ b/lib/nrppa/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# 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 + nrppa_dummy_factory.cpp + nrppa_dummy_impl.cpp + ) + + +add_library(srsran_nrppa STATIC ${SOURCES}) + +target_link_libraries(srsran_nrppa + srsran_cu_cp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/lib/nrppa/nrppa_dummy_factory.cpp b/lib/nrppa/nrppa_dummy_factory.cpp new file mode 100644 index 0000000000..a71c0ec2a7 --- /dev/null +++ b/lib/nrppa/nrppa_dummy_factory.cpp @@ -0,0 +1,29 @@ +/* + * + * 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 "nrppa_dummy_impl.h" +#include "srsran/nrppa/nrppa_factory.h" + +/// Notice this would be the only place were we include concrete class implementation files. + +using namespace srsran; +using namespace srs_cu_cp; + +using namespace srsran; +using namespace srs_cu_cp; + +std::unique_ptr srsran::srs_cu_cp::create_nrppa(const cu_cp_configuration& cfg, + nrppa_cu_cp_notifier& cu_cp_notifier) +{ + (void)&cfg; + (void)&cu_cp_notifier; + auto nrppa = std::make_unique(); + return nrppa; +} diff --git a/lib/nrppa/nrppa_dummy_impl.cpp b/lib/nrppa/nrppa_dummy_impl.cpp new file mode 100644 index 0000000000..2849d999a0 --- /dev/null +++ b/lib/nrppa/nrppa_dummy_impl.cpp @@ -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. + * + */ + +#include "nrppa_dummy_impl.h" +#include "srsran/srslog/srslog.h" + +using namespace srsran; +using namespace srs_cu_cp; + +nrppa_dummy_impl::nrppa_dummy_impl() : logger(srslog::fetch_basic_logger("NRPPA")) {} + +// Note: For fwd declaration of member types, dtor cannot be trivial. +nrppa_dummy_impl::~nrppa_dummy_impl() {} + +void nrppa_dummy_impl::handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) +{ + logger.info("NRPPa messages are not supported"); +} + +void nrppa_dummy_impl::handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) +{ + logger.info("NRPPa messages are not supported"); +} diff --git a/lib/nrppa/nrppa_dummy_impl.h b/lib/nrppa/nrppa_dummy_impl.h new file mode 100644 index 0000000000..56c87280e4 --- /dev/null +++ b/lib/nrppa/nrppa_dummy_impl.h @@ -0,0 +1,39 @@ +/* + * + * 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/nrppa/nrppa.h" +#include + +namespace srsran { +namespace srs_cu_cp { + +class nrppa_dummy_impl : public nrppa_interface, public nrppa_message_handler, public nrppa_measurement_handler +{ +public: + nrppa_dummy_impl(); + ~nrppa_dummy_impl(); + + // See nrppa_message_handler for documentation. + void handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override; + + // See nrppa_measurement_handler for documentation. + void handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override; + + nrppa_message_handler& get_nrppa_message_handler() override { return *this; } + nrppa_measurement_handler& get_nrppa_measurement_handler() override { return *this; } + +private: + srslog::basic_logger& logger; +}; + +} // namespace srs_cu_cp +} // namespace srsran From 57412191e4c559640a8ef36cd9a744b2a18638ae Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 10 Dec 2024 11:39:15 +0100 Subject: [PATCH 085/227] cu_cp,nrppa: add nrppa ue context removal to ue context removal routine --- include/srsran/nrppa/nrppa.h | 16 ++++++++++++++-- lib/cu_cp/cu_cp_impl.cpp | 4 ++++ lib/cu_cp/routines/ue_removal_routine.cpp | 17 ++++++++++++----- lib/cu_cp/routines/ue_removal_routine.h | 18 +++++++++++------- lib/nrppa/nrppa_dummy_impl.cpp | 5 +++++ lib/nrppa/nrppa_dummy_impl.h | 13 ++++++++++--- 6 files changed, 56 insertions(+), 17 deletions(-) diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h index e3445651a2..1d823cb257 100644 --- a/include/srsran/nrppa/nrppa.h +++ b/include/srsran/nrppa/nrppa.h @@ -78,14 +78,26 @@ class nrppa_measurement_handler virtual void handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; }; +/// Handle ue context removal. +class nrppa_ue_context_removal_handler +{ +public: + virtual ~nrppa_ue_context_removal_handler() = default; + + /// \brief Remove the context of an UE. + /// \param[in] ue_index The index of the UE to remove. + virtual void remove_ue_context(ue_index_t ue_index) = 0; +}; + /// Combined entry point for the NRPPA object. class nrppa_interface { public: virtual ~nrppa_interface() = default; - virtual nrppa_message_handler& get_nrppa_message_handler() = 0; - virtual nrppa_measurement_handler& get_nrppa_measurement_handler() = 0; + virtual nrppa_message_handler& get_nrppa_message_handler() = 0; + virtual nrppa_measurement_handler& get_nrppa_measurement_handler() = 0; + virtual nrppa_ue_context_removal_handler& get_nrppa_ue_context_removal_handler() = 0; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 90e6b7413f..8f46ea8428 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -703,11 +703,15 @@ async_task cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) }); } + nrppa_ue_context_removal_handler* nrppa_removal_handler = nullptr; + nrppa_removal_handler = &nrppa_entity->get_nrppa_ue_context_removal_handler(); + return launch_async(ue_index, du_db.get_du_processor(du_index).get_rrc_du_handler(), e1ap_removal_handler, du_db.get_du_processor(du_index).get_f1ap_handler(), ngap->get_ngap_ue_context_removal_handler(), + nrppa_removal_handler, ue_mng, logger); } diff --git a/lib/cu_cp/routines/ue_removal_routine.cpp b/lib/cu_cp/routines/ue_removal_routine.cpp index c6fb3f9731..5d11b35dbb 100644 --- a/lib/cu_cp/routines/ue_removal_routine.cpp +++ b/lib/cu_cp/routines/ue_removal_routine.cpp @@ -18,6 +18,7 @@ ue_removal_routine::ue_removal_routine(ue_index_t ue_i e1ap_bearer_context_removal_handler* e1ap_removal_handler_, f1ap_ue_context_removal_handler& f1ap_removal_handler_, ngap_ue_context_removal_handler& ngap_removal_handler_, + nrppa_ue_context_removal_handler* nrppa_removal_handler_, ue_manager& ue_mng_, srslog::basic_logger& logger_) : ue_index(ue_index_), @@ -25,6 +26,7 @@ ue_removal_routine::ue_removal_routine(ue_index_t ue_i e1ap_removal_handler(e1ap_removal_handler_), f1ap_removal_handler(f1ap_removal_handler_), ngap_removal_handler(ngap_removal_handler_), + nrppa_removal_handler(nrppa_removal_handler_), ue_mng(ue_mng_), logger(logger_) { @@ -36,21 +38,26 @@ void ue_removal_routine::operator()(coro_context>& ctx) logger.debug("ue={}: \"{}\" initialized", ue_index, name()); - // Remove RRC UE + // Remove RRC UE. rrc_du_notifier.remove_ue(ue_index); - // Remove Bearer Context from E1AP + // Remove Bearer Context from E1AP. if (e1ap_removal_handler != nullptr) { e1ap_removal_handler->remove_bearer_context(ue_index); } - // Remove UE Context from F1AP + // Remove UE Context from F1AP. f1ap_removal_handler.remove_ue_context(ue_index); - // Remove UE Context from NGAP + // Remove UE Context from NGAP. ngap_removal_handler.remove_ue_context(ue_index); - // Remove UE from UE manager + // Remove UE Context from NRPPa. + if (nrppa_removal_handler != nullptr) { + nrppa_removal_handler->remove_ue_context(ue_index); + } + + // Remove UE from UE manager. ue_mng.remove_ue(ue_index); logger.info("ue={}: \"{}\" finalized", ue_index, name()); diff --git a/lib/cu_cp/routines/ue_removal_routine.h b/lib/cu_cp/routines/ue_removal_routine.h index 619062acdf..a6579a211c 100644 --- a/lib/cu_cp/routines/ue_removal_routine.h +++ b/lib/cu_cp/routines/ue_removal_routine.h @@ -26,6 +26,7 @@ class ue_removal_routine e1ap_bearer_context_removal_handler* e1ap_removal_handler_, f1ap_ue_context_removal_handler& f1ap_removal_handler_, ngap_ue_context_removal_handler& ngap_removal_handler_, + nrppa_ue_context_removal_handler* nrppa_removal_handler_, ue_manager& ue_mng_, srslog::basic_logger& logger_); @@ -34,13 +35,16 @@ class ue_removal_routine static const char* name() { return "UE Removal Routine"; } private: - const ue_index_t ue_index; - rrc_ue_handler& rrc_du_notifier; // to trigger removal of the UE at the RRC - e1ap_bearer_context_removal_handler* e1ap_removal_handler; // to trigger removal of the UE at the E1AP - f1ap_ue_context_removal_handler& f1ap_removal_handler; // to trigger removal of the UE at the F1AP - ngap_ue_context_removal_handler& ngap_removal_handler; // to trigger removal of the UE at the NGAP - ue_manager& ue_mng; // to remove UE context from DU processor - srslog::basic_logger& logger; + const ue_index_t ue_index; + // Handlers to trigger UE removal in the respective layers. + rrc_ue_handler& rrc_du_notifier; + e1ap_bearer_context_removal_handler* e1ap_removal_handler = nullptr; + f1ap_ue_context_removal_handler& f1ap_removal_handler; + ngap_ue_context_removal_handler& ngap_removal_handler; + nrppa_ue_context_removal_handler* nrppa_removal_handler = nullptr; + // To remove UE context from DU processor. + ue_manager& ue_mng; + srslog::basic_logger& logger; }; } // namespace srs_cu_cp diff --git a/lib/nrppa/nrppa_dummy_impl.cpp b/lib/nrppa/nrppa_dummy_impl.cpp index 2849d999a0..67dc7e661d 100644 --- a/lib/nrppa/nrppa_dummy_impl.cpp +++ b/lib/nrppa/nrppa_dummy_impl.cpp @@ -24,6 +24,11 @@ void nrppa_dummy_impl::handle_ue_measurement(ue_index_t ue_index, const cell_mea logger.info("NRPPa messages are not supported"); } +void nrppa_dummy_impl::remove_ue_context(ue_index_t ue_index) +{ + logger.info("NRPPa messages are not supported"); +} + void nrppa_dummy_impl::handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) { logger.info("NRPPa messages are not supported"); diff --git a/lib/nrppa/nrppa_dummy_impl.h b/lib/nrppa/nrppa_dummy_impl.h index 56c87280e4..2b541b7193 100644 --- a/lib/nrppa/nrppa_dummy_impl.h +++ b/lib/nrppa/nrppa_dummy_impl.h @@ -16,7 +16,10 @@ namespace srsran { namespace srs_cu_cp { -class nrppa_dummy_impl : public nrppa_interface, public nrppa_message_handler, public nrppa_measurement_handler +class nrppa_dummy_impl : public nrppa_interface, + public nrppa_message_handler, + public nrppa_measurement_handler, + public nrppa_ue_context_removal_handler { public: nrppa_dummy_impl(); @@ -28,8 +31,12 @@ class nrppa_dummy_impl : public nrppa_interface, public nrppa_message_handler, p // See nrppa_measurement_handler for documentation. void handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override; - nrppa_message_handler& get_nrppa_message_handler() override { return *this; } - nrppa_measurement_handler& get_nrppa_measurement_handler() override { return *this; } + // See nrppa_ue_context_removal_handle for documentation. + void remove_ue_context(ue_index_t ue_index) override; + + nrppa_message_handler& get_nrppa_message_handler() override { return *this; } + nrppa_measurement_handler& get_nrppa_measurement_handler() override { return *this; } + nrppa_ue_context_removal_handler& get_nrppa_ue_context_removal_handler() override { return *this; } private: srslog::basic_logger& logger; From d3a73c1bb09d19e7094158a32337e1c9cd29db88 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 3 Dec 2024 11:33:55 +0100 Subject: [PATCH 086/227] cu_cp,ngap: add unit test for ngap ue context --- lib/ngap/ue_context/ngap_ue_context.h | 8 ++ tests/unittests/ngap/CMakeLists.txt | 1 + tests/unittests/ngap/ngap_ue_context_test.cpp | 118 ++++++++++++++++++ tests/unittests/ngap/test_helpers.h | 33 +++++ 4 files changed, 160 insertions(+) create mode 100644 tests/unittests/ngap/ngap_ue_context_test.cpp diff --git a/lib/ngap/ue_context/ngap_ue_context.h b/lib/ngap/ue_context/ngap_ue_context.h index 8fb89db9f3..1c2d8b9097 100644 --- a/lib/ngap/ue_context/ngap_ue_context.h +++ b/lib/ngap/ue_context/ngap_ue_context.h @@ -238,6 +238,14 @@ class ngap_ue_context_list return ran_ue_id_t::invalid; } + // Check if the next_ran_ue_id is available + if (ues.find(next_ran_ue_id) == ues.end()) { + ran_ue_id_t ret = next_ran_ue_id; + // increase the next cu ue f1ap id + increase_next_ran_ue_id(); + return ret; + } + // iterate over all ids starting with the next_ran_ue_id to find the available id while (true) { // Iterate over ue_index_to_ran_ue_id diff --git a/tests/unittests/ngap/CMakeLists.txt b/tests/unittests/ngap/CMakeLists.txt index 001a62c1ec..fcbf987f83 100644 --- a/tests/unittests/ngap/CMakeLists.txt +++ b/tests/unittests/ngap/CMakeLists.txt @@ -13,6 +13,7 @@ target_link_libraries(ngap_test_helpers srsran_support ngap_asn1 srslog) set(SOURCES ngap_asn1_packer_test.cpp ngap_validators_test.cpp + ngap_ue_context_test.cpp ng_setup_procedure_test.cpp ngap_nas_message_test.cpp ngap_ue_context_management_procedure_test.cpp diff --git a/tests/unittests/ngap/ngap_ue_context_test.cpp b/tests/unittests/ngap/ngap_ue_context_test.cpp new file mode 100644 index 0000000000..5daf1a99f7 --- /dev/null +++ b/tests/unittests/ngap/ngap_ue_context_test.cpp @@ -0,0 +1,118 @@ +/* + * + * 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/ngap/ue_context/ngap_ue_context.h" +#include "srsran/support/executors/manual_task_worker.h" +#include "srsran/support/test_utils.h" +#include +#include +#include + +using namespace srsran; +using namespace srs_cu_cp; + +// Test class. +class ngap_ue_context_list_test : public ngap_ue_context_list +{ +public: + ngap_ue_context_list_test(srslog::basic_logger& logger_) : ngap_ue_context_list(logger_) {} +}; + +/// Fixture class for NGAP UE context +class ngap_ue_context_test : public ::testing::Test +{ +protected: + ngap_ue_context_test() + { + ngap_logger.set_level(srslog::basic_levels::debug); + srslog::init(); + }; + ~ngap_ue_context_test() + { + // flush logger after each test + srslog::flush(); + } + + ue_index_t generate_random_ue_index() + { + return uint_to_ue_index( + test_rgen::uniform_int(ue_index_to_uint(ue_index_t::min), ue_index_to_uint(ue_index_t::max) - 1)); + } + + ran_ue_id_t generate_random_ran_ue_id() + { + return uint_to_ran_ue_id( + test_rgen::uniform_int(ran_ue_id_to_uint(ran_ue_id_t::min), ran_ue_id_to_uint(ran_ue_id_t::max) - 1)); + } + + srslog::basic_logger& ngap_logger = srslog::fetch_basic_logger("NGAP"); + timer_manager timer_mng; + manual_task_worker ctrl_worker{128}; + timer_factory timers{timer_mng, ctrl_worker}; + dummy_ngap_cu_cp_ue_notifier ue_notifier; + ngap_ue_context_list_test ue_ctxt_list{ngap_logger}; +}; + +TEST_F(ngap_ue_context_test, when_ue_added_then_ue_exists) +{ + ue_index_t ue_index = generate_random_ue_index(); + ran_ue_id_t ran_ue_id = generate_random_ran_ue_id(); + + ue_ctxt_list.add_ue(ue_index, ran_ue_id, ue_notifier, timer_mng, ctrl_worker); + + ASSERT_TRUE(ue_ctxt_list.contains(ran_ue_id)); + ASSERT_TRUE(ue_ctxt_list.contains(ue_index)); + + ASSERT_EQ(ue_ctxt_list[ran_ue_id].ue_ids.ran_ue_id, ran_ue_id); + ASSERT_EQ(ue_ctxt_list[ran_ue_id].ue_ids.ue_index, ue_index); + ASSERT_EQ(ue_ctxt_list[ue_index].ue_ids.ran_ue_id, ran_ue_id); + ASSERT_EQ(ue_ctxt_list[ue_index].ue_ids.ue_index, ue_index); +} + +TEST_F(ngap_ue_context_test, when_ue_not_added_then_ue_doesnt_exist) +{ + ue_index_t ue_index = generate_random_ue_index(); + ran_ue_id_t ran_ue_id = generate_random_ran_ue_id(); + + ASSERT_FALSE(ue_ctxt_list.contains(ran_ue_id)); + ASSERT_FALSE(ue_ctxt_list.contains(ue_index)); +} + +TEST_F(ngap_ue_context_test, when_ue_exists_then_removal_succeeds) +{ + ue_index_t ue_index = generate_random_ue_index(); + ran_ue_id_t ran_ue_id = generate_random_ran_ue_id(); + + ue_ctxt_list.add_ue(ue_index, ran_ue_id, ue_notifier, timer_mng, ctrl_worker); + + // test removal + ue_ctxt_list.remove_ue_context(ue_index); + + ASSERT_FALSE(ue_ctxt_list.contains(ran_ue_id)); + ASSERT_FALSE(ue_ctxt_list.contains(ue_index)); +} + +TEST_F(ngap_ue_context_test, when_ue_is_added_then_next_ue_id_is_increased) +{ + ue_index_t ue_index = generate_random_ue_index(); + ran_ue_id_t ran_ue_id = ue_ctxt_list.allocate_ran_ue_id(); + + ASSERT_EQ((unsigned)ran_ue_id, (unsigned)ran_ue_id_t::min); + + ue_ctxt_list.add_ue(ue_index, ran_ue_id, ue_notifier, timer_mng, ctrl_worker); + + // remove ue + ue_ctxt_list.remove_ue_context(ue_index); + + ASSERT_FALSE(ue_ctxt_list.contains(ran_ue_id)); + ASSERT_FALSE(ue_ctxt_list.contains(ue_index)); + + ASSERT_EQ((unsigned)ue_ctxt_list.allocate_ran_ue_id(), (unsigned)ran_ue_id_t::min + 1); +} diff --git a/tests/unittests/ngap/test_helpers.h b/tests/unittests/ngap/test_helpers.h index fb91fd78e1..02e639d369 100644 --- a/tests/unittests/ngap/test_helpers.h +++ b/tests/unittests/ngap/test_helpers.h @@ -410,5 +410,38 @@ class dummy_rrc_ngap_message_handler : public rrc_ngap_message_handler byte_buffer ho_preparation_message; }; +class dummy_ngap_cu_cp_ue_notifier : public ngap_cu_cp_ue_notifier +{ +public: + ~dummy_ngap_cu_cp_ue_notifier() = default; + + void set_ue_index(ue_index_t ue_index_) { ue_index = ue_index_; } + void set_rrc_ue_notifier(dummy_ngap_rrc_ue_notifier& rrc_ue_notifier_) { rrc_ue_notifier = &rrc_ue_notifier_; } + + /// \brief Get the UE index of the UE. + ue_index_t get_ue_index() override { return ue_index.value(); }; + + /// \brief Schedule an async task for the UE. + bool schedule_async_task(async_task task) override { return true; }; + + /// \brief Get the RRC UE notifier of the UE. + ngap_rrc_ue_notifier& get_ngap_rrc_ue_notifier() override + { + srsran_assert(rrc_ue_notifier != nullptr, "RRC UE notifier must not be nullptr"); + return *rrc_ue_notifier; + }; + + /// \brief Notify the CU-CP about a security context + /// \param[in] sec_ctxt The received security context + /// \return True if the security context was successfully initialized, false otherwise + bool init_security_context(security::security_context sec_ctxt) override { return true; }; + + /// \brief Check if security is enabled + [[nodiscard]] bool is_security_enabled() const override { return true; }; + + std::optional ue_index; + dummy_ngap_rrc_ue_notifier* rrc_ue_notifier = nullptr; +}; + } // namespace srs_cu_cp } // namespace srsran From 55eb1e1ea92fc2f5477794e22e98d9f8b983d01e Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Tue, 10 Dec 2024 12:01:11 +0100 Subject: [PATCH 087/227] du_low_app_unit: added BBDEV section to YAML writer --- .../o_du_low/du_low_config_yaml_writer.cpp | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/apps/units/flexible_o_du/o_du_low/du_low_config_yaml_writer.cpp b/apps/units/flexible_o_du/o_du_low/du_low_config_yaml_writer.cpp index c660b3f270..09432d7f28 100644 --- a/apps/units/flexible_o_du/o_du_low/du_low_config_yaml_writer.cpp +++ b/apps/units/flexible_o_du/o_du_low/du_low_config_yaml_writer.cpp @@ -71,9 +71,61 @@ static void fill_du_low_expert_section(YAML::Node node, const du_low_unit_expert node["max_request_headroom_slots"] = config.nof_slots_request_headroom; } +static void fill_du_low_bbdev_pdsch_enc_section(YAML::Node node, const hwacc_pdsch_appconfig& config) +{ + node["nof_hwacc"] = config.nof_hwacc; + node["cb_mode"] = config.cb_mode; + node["dedicated_queue"] = config.dedicated_queue; + if (config.max_buffer_size) { + node["max_buffer_size"] = config.max_buffer_size.value(); + } +} + +static void fill_du_low_bbdev_pusch_dec_section(YAML::Node node, const hwacc_pusch_appconfig& config) +{ + node["nof_hwacc"] = config.nof_hwacc; + node["ext_softbuffer"] = config.ext_softbuffer; + node["dedicated_queue"] = config.dedicated_queue; + if (config.harq_context_size) { + node["harq_context_size"] = config.harq_context_size.value(); + } +} + +static void fill_du_low_bbdev_section(YAML::Node node, const bbdev_appconfig& config) +{ + node["hwacc_type"] = config.hwacc_type; + node["id"] = config.id; + + if (config.pdsch_enc) { + fill_du_low_bbdev_pdsch_enc_section(node["pdsch_enc"], config.pdsch_enc.value()); + } + if (config.pusch_dec) { + fill_du_low_bbdev_pusch_dec_section(node["pusch_dec"], config.pusch_dec.value()); + } + if (config.msg_mbuf_size) { + node["msg_mbuf_size"] = config.msg_mbuf_size.value(); + } + if (config.rm_mbuf_size) { + node["rm_mbuf_size"] = config.rm_mbuf_size.value(); + } + if (config.nof_mbuf) { + node["nof_mbuf"] = config.nof_mbuf.value(); + } +} + +static void fill_du_low_hal_section(YAML::Node node, const du_low_unit_hal_config& config) +{ + if (config.bbdev_hwacc) { + fill_du_low_bbdev_section(node["bbdev_hwacc"], config.bbdev_hwacc.value()); + } +} + void srsran::fill_du_low_config_in_yaml_schema(YAML::Node& node, const du_low_unit_config& config) { fill_du_low_log_section(node["log"], config.loggers); fill_du_low_expert_execution_section(node["expert_execution"], config.expert_execution_cfg); fill_du_low_expert_section(node["expert_phy"], config.expert_phy_cfg); + if (config.hal_config) { + fill_du_low_hal_section(node["hal"], config.hal_config.value()); + } } From c739518cc73fc74156084e55f4f6f1c8616c56d3 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 6 Dec 2024 11:03:47 +0100 Subject: [PATCH 088/227] cu_cp: fix mobility appconfig validator --- apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp index 97fb04f860..7857cccc4e 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp @@ -140,8 +140,8 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili // verify that each configured neighbor cell is present for (const auto& cell : config.cells) { - nr_cell_identity nci = nr_cell_identity::create(cell.nr_cell_id).value(); for (const auto& ncell : cell.ncells) { + nr_cell_identity nci = nr_cell_identity::create(ncell.nr_cell_id).value(); if (ncis.find(nci) == ncis.end()) { fmt::print("Neighbor cell config for nci={:#x} incomplete. No valid configuration for cell nci={:#x} found.\n", cell.nr_cell_id, From cc63549b2c59c9778541a35bcf84b5c52ed021ad Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 10 Dec 2024 12:53:47 +0000 Subject: [PATCH 089/227] cu_up: fix cu_up test mode configuration --- .../cu_up/cu_up_unit_config_cli11_schema.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp index 5c26dc69f7..cb2fb1615a 100644 --- a/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp +++ b/apps/units/o_cu_up/cu_up/cu_up_unit_config_cli11_schema.cpp @@ -54,12 +54,29 @@ static void configure_cli11_ngu_args(CLI::App& app, cu_up_unit_ngu_config& ngu_p add_option_cell(app, "--socket", sock_lambda, "Configures UDP/IP socket parameters of the N3 interface"); } +static void configure_cli11_test_mode_args(CLI::App& app, cu_up_unit_test_mode_config& test_mode_params) +{ + add_option(app, "--enable", test_mode_params.enabled, "Enable or disable CU-UP test mode"); + add_option(app, "--integrity_enable", test_mode_params.integrity_enabled, "Enable or disable PDCP integrity testing"); + add_option(app, "--ciphering_enable", test_mode_params.ciphering_enabled, "Enable or disable PDCP ciphering testing"); + add_option(app, "--nea_algo", test_mode_params.nea_algo, "NEA algo to use for testing. Valid values {0, 1, 2, 3}.") + ->capture_default_str() + ->check(CLI::Range(0, 3)); + add_option(app, "--nia_algo", test_mode_params.nea_algo, "NIA algo to use for testing. Valid values {1, 2, 3}.") + ->capture_default_str() + ->check(CLI::Range(1, 3)); +} + static void configure_cli11_cu_up_args(CLI::App& app, cu_up_unit_config& cu_up_params) { // UPF section. CLI::App* ngu_subcmd = add_subcommand(app, "ngu", "NG-U parameters")->configurable(); configure_cli11_ngu_args(*ngu_subcmd, cu_up_params.ngu_cfg); + // Test mode section. + CLI::App* test_mode_subcmd = add_subcommand(app, "test_mode", "CU-UP test mode parameters")->configurable(); + configure_cli11_test_mode_args(*test_mode_subcmd, cu_up_params.test_mode_cfg); + add_option(app, "--gtpu_queue_size", cu_up_params.gtpu_queue_size, "GTP-U queue size, in PDUs") ->capture_default_str(); add_option(app, @@ -125,19 +142,6 @@ static void configure_cli11_qos_args(CLI::App& app, cu_up_unit_qos_config& qos_p configure_cli11_f1u_cu_up_args(*f1u_cu_up_subcmd, qos_params.f1u_cu_up); } -static void configure_cli11_test_mode_args(CLI::App& app, cu_up_unit_test_mode_config& test_mode_params) -{ - add_option(app, "--enable", test_mode_params.enabled, "Enable or disable CU-UP test mode"); - add_option(app, "--integrity_enable", test_mode_params.integrity_enabled, "Enable or disable PDCP integrity testing"); - add_option(app, "--ciphering_enable", test_mode_params.ciphering_enabled, "Enable or disable PDCP ciphering testing"); - add_option(app, "--nea_algo", test_mode_params.nea_algo, "NEA algo to use for testing. Valid values {0, 1, 2, 3}.") - ->capture_default_str() - ->check(CLI::Range(0, 3)); - add_option(app, "--nia_algo", test_mode_params.nea_algo, "NIA algo to use for testing. Valid values {1, 2, 3}.") - ->capture_default_str() - ->check(CLI::Range(1, 3)); -} - void srsran::configure_cli11_with_cu_up_unit_config_schema(CLI::App& app, cu_up_unit_config& unit_cfg) { // CU-UP section. @@ -172,8 +176,4 @@ void srsran::configure_cli11_with_cu_up_unit_config_schema(CLI::App& app, cu_up_ } }; add_option_cell(app, "--qos", qos_lambda, "Configures RLC and PDCP radio bearers on a per 5QI basis."); - - // Test mode section. - CLI::App* test_mode_subcmd = add_subcommand(app, "test_mode", "CU-UP test mode parameters")->configurable(); - configure_cli11_test_mode_args(*test_mode_subcmd, unit_cfg.test_mode_cfg); } From 17d569f284a3f3fe5e68783c1e74dd21c66b912d Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Tue, 10 Dec 2024 09:36:40 +0100 Subject: [PATCH 090/227] e2,rc: reduce log level when trying to parse PLMN --- lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 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 f1a2b32ee2..1fe8ed69b4 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 @@ -109,8 +109,8 @@ void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value( srs_du::control_config_params cur_control_params = {}; cur_control_params.rrm_policy_group.emplace(); if (ran_param.ran_p_choice_elem_false().ran_param_value.value_oct_s().size() != 3) { - logger.warning("E2SM-RC Slice-level PRB quota Control Request: PLMN (param_id={}) encoded not correctly.", - ran_param_id); + logger.info("E2SM-RC Slice-level PRB quota Control Request: PLMN (param_id={}) encoded not correctly.", + ran_param_id); return; } std::array plmn_bytes; From 627e68717da246a3873655f471aea54c70817b93 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 10 Dec 2024 15:58:09 +0000 Subject: [PATCH 091/227] cu_up: decouple cu-up no_core from amf no core --- apps/cu/cu.cpp | 1 - apps/gnb/gnb.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 373ce4c6a1..17bf0040b5 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -150,7 +150,6 @@ static void autoderive_cu_up_parameters_after_parsing(o_cu_up_unit_config& o sock_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; o_cu_up_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg.push_back(sock_cfg); } - o_cu_up_cfg.cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; o_cu_up_cfg.e2_cfg.pcaps.enabled = o_cu_up_cfg.e2_cfg.base_config.enable_unit_e2 && o_cu_up_cfg.e2_cfg.pcaps.enabled; } diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 30d5c5692b..96499a0819 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -173,7 +173,6 @@ static void autoderive_cu_up_parameters_after_parsing(cu_up_unit_config& cu_up_c sock_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; cu_up_cfg.ngu_cfg.ngu_socket_cfg.push_back(sock_cfg); } - cu_up_cfg.ngu_cfg.no_core = cu_cp_cfg.amf_config.no_core; } int main(int argc, char** argv) From 659667dcc744bc7093d87bb00c61147e36ae3847 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Mon, 9 Dec 2024 11:28:34 +0100 Subject: [PATCH 092/227] mac: support pucch f4 in pucch_resource_generator --- .../o_du_high/du_high/du_high_config.h | 15 + .../du_high/du_high_config_cli11_schema.cpp | 79 +- .../du_high/du_high_config_translators.cpp | 29 +- .../du_high/du_high_config_validator.cpp | 21 +- .../du_high/du_high_config_yaml_writer.cpp | 51 +- include/srsran/du/du_cell_config.h | 24 +- include/srsran/ran/pucch/pucch_info.h | 23 +- include/srsran/ran/sr_configuration.h | 1 + .../srsran/scheduler/scheduler_pucch_format.h | 2 +- lib/du/du_cell_config_validation.cpp | 4 +- .../du_pucch_resource_manager.cpp | 72 +- .../pucch_resource_generator.cpp | 478 ++++++--- .../pucch_resource_generator.h | 108 +- lib/du/du_update_config_helpers.cpp | 12 +- lib/fapi_adaptor/mac/messages/pucch.cpp | 2 +- lib/ran/pucch/pucch_info.cpp | 46 + .../config/sched_cell_config_helpers.cpp | 11 +- .../benchmarks/du_high/du_high_benchmark.cpp | 10 +- .../scheduler_multi_ue_benchmark.cpp | 10 +- .../du_high/du_high_many_ues_test.cpp | 6 +- .../scheduler/scheduler_config_helper.cpp | 8 +- .../du_ran_resource_manager_test.cpp | 58 +- .../pucch_resource_generator_test.cpp | 955 ++++++++++++------ .../fapi_adaptor/mac/messages/helpers.cpp | 2 +- .../mac/messages/ul_pucch_pdu_test.cpp | 2 +- .../scheduler/multiple_ue_sched_test.cpp | 8 +- .../test_pucch_res_test_builder_helper.cpp | 3 +- .../uci_and_pucch/uci_test_utils.cpp | 4 +- 28 files changed, 1324 insertions(+), 720 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 12f7cc3e1e..f1151940bb 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -337,6 +337,21 @@ struct du_high_unit_pucch_config { bool f3_pi2_bpsk = false; /// @} + /// PUCCH F4 resource parameters. + /// \defgroup pucch_f4_params + /// \brief PUCCH F4 resource parameters. + /// @{ + /// Max code rate for PUCCH Format 4. + max_pucch_code_rate f4_max_code_rate = max_pucch_code_rate::dot_35; + /// Set true for PUCCH Format 4 intra-slot frequency hopping. + bool f4_intraslot_freq_hopping = false; + /// Set true for PUCCH Format 4 additional DM-RS. + bool f4_additional_dmrs = false; + /// Set true to use pi/2-BPSK as the modulation for PUCCH Format 4. + bool f4_pi2_bpsk = false; + unsigned f4_occ_length = 2; + /// @} + /// Minimum k1 value (distance in slots between PDSCH and HARQ-ACK) that the gNB can use. Values: {1, ..., 7}. /// [Implementation-defined] As min_k1 is used for both common and dedicated PUCCH configuration, and in the UE /// fallback scheduler only allow max k1 = 7, we restrict min_k1 to 7. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 030ee51b0c..7360006bd9 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -824,6 +824,27 @@ static void configure_cli11_pusch_args(CLI::App& app, du_high_unit_pusch_config& static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& pucch_params) { + // Lambda function to map the argument values to max_pucch_code_rate values. + auto map_max_code_rate = [](max_pucch_code_rate& max_code_rate) { + return [&max_code_rate](const std::string& value) { + if (value == "dot08") { + max_code_rate = max_pucch_code_rate::dot_08; + } else if (value == "dot15") { + max_code_rate = max_pucch_code_rate::dot_15; + } else if (value == "dot25") { + max_code_rate = max_pucch_code_rate::dot_25; + } else if (value == "dot35") { + max_code_rate = max_pucch_code_rate::dot_35; + } else if (value == "dot45") { + max_code_rate = max_pucch_code_rate::dot_45; + } else if (value == "dot60") { + max_code_rate = max_pucch_code_rate::dot_60; + } else if (value == "dot80") { + max_code_rate = max_pucch_code_rate::dot_80; + } + }; + }; + add_option(app, "--p0_nominal", pucch_params.p0_nominal, @@ -909,23 +930,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option_function( app, "--f2_max_code_rate", - [&pucch_params](const std::string& value) { - if (value == "dot08") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_08; - } else if (value == "dot15") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_15; - } else if (value == "dot25") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_25; - } else if (value == "dot35") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_35; - } else if (value == "dot45") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_45; - } else if (value == "dot60") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_60; - } else if (value == "dot80") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_80; - } - }, + map_max_code_rate(pucch_params.f2_max_code_rate), "PUCCH F2 max code rate {dot08, dot15, dot25, dot35, dot45, dot60, dot80}. Default: dot35") ->check(CLI::IsMember({"dot08", "dot15", "dot25", "dot35", "dot45", "dot60", "dot80"}, CLI::ignore_case)); add_option(app, @@ -942,23 +947,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option_function( app, "--f3_max_code_rate", - [&pucch_params](const std::string& value) { - if (value == "dot08") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_08; - } else if (value == "dot15") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_15; - } else if (value == "dot25") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_25; - } else if (value == "dot35") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_35; - } else if (value == "dot45") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_45; - } else if (value == "dot60") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_60; - } else if (value == "dot80") { - pucch_params.f2_max_code_rate = max_pucch_code_rate::dot_80; - } - }, + map_max_code_rate(pucch_params.f3_max_code_rate), "PUCCH F3 max code rate {dot08, dot15, dot25, dot35, dot45, dot60, dot80}. Default: dot35") ->check(CLI::IsMember({"dot08", "dot15", "dot25", "dot35", "dot45", "dot60", "dot80"}, CLI::ignore_case)); add_option(app, @@ -970,6 +959,24 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& ->capture_default_str(); add_option(app, "--f3_pi2_bpsk", pucch_params.f3_pi2_bpsk, "Enable pi/2-BPSK modulation for PUCCH F3") ->capture_default_str(); + add_option_function( + app, + "--f4_max_code_rate", + map_max_code_rate(pucch_params.f3_max_code_rate), + "PUCCH F4 max code rate {dot08, dot15, dot25, dot35, dot45, dot60, dot80}. Default: dot35") + ->check(CLI::IsMember({"dot08", "dot15", "dot25", "dot35", "dot45", "dot60", "dot80"}, CLI::ignore_case)); + add_option(app, + "--f4_intraslot_freq_hop", + pucch_params.f4_intraslot_freq_hopping, + "Enable intra-slot frequency hopping for PUCCH F4") + ->capture_default_str(); + add_option(app, "--f4_additional_dmrs", pucch_params.f4_additional_dmrs, "Enable additional DM-RS for PUCCH F4") + ->capture_default_str(); + add_option(app, "--f4_pi2_bpsk", pucch_params.f4_pi2_bpsk, "Enable pi/2-BPSK modulation for PUCCH F4") + ->capture_default_str(); + add_option(app, "--f4_occ_length", pucch_params.f4_occ_length, "OCC length for PUCCH F4") + ->capture_default_str() + ->check(CLI::IsMember({2, 4})); add_option(app, "--min_k1", pucch_params.min_k1, @@ -1373,8 +1380,8 @@ static void configure_cli11_common_cell_args(CLI::App& app, du_high_unit_base_ce configure_cli11_prach_args(*prach_subcmd, cell_params.prach_cfg); // TDD UL DL configuration. - // NOTE: As the cell TDD pattern can be configured in the common cell and not in the cell, use a different variable to - // parse the cell TDD property. If the TDD pattern is present for the cell, update the cell TDD pattern value, + // NOTE: As the cell TDD pattern can be configured in the common cell and not in the cell, use a different variable + // to parse the cell TDD property. If the TDD pattern is present for the cell, update the cell TDD pattern value, // otherwise do nothing (this will cause that the cell TDD pattern value equals than the common cell TDD pattern). // CLI11 needs that the life of the variable last longer than the call of callback function. Therefore, the // cell_tdd_pattern variable needs to be static. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index 1f0c824cd6..02e9751a18 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -540,28 +540,28 @@ std::vector srsran::generate_du_cell_config(const du_hig auto& f0_params = du_pucch_cfg.f0_or_f1_params.emplace(); // Subtract 2 PUCCH resources from value: with Format 0, 2 extra resources will be added by the DU resource // allocator when the DU create the UE configuration. - du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; - du_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; - f0_params.intraslot_freq_hopping = user_pucch_cfg.f0_intraslot_freq_hopping; + du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; + du_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; + f0_params.intraslot_freq_hopping = user_pucch_cfg.f0_intraslot_freq_hopping; } else { auto& f1_params = du_pucch_cfg.f0_or_f1_params.emplace(); du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; - du_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; - f1_params.occ_supported = user_pucch_cfg.f1_enable_occ; + du_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set; + f1_params.occ_supported = user_pucch_cfg.f1_enable_occ; f1_params.nof_cyc_shifts = static_cast(user_pucch_cfg.f1_nof_cyclic_shifts); f1_params.intraslot_freq_hopping = user_pucch_cfg.f1_intraslot_freq_hopping; } switch (user_pucch_cfg.set1_format) { case 2: { - auto& f2_params = du_pucch_cfg.f2_or_f3_params.emplace(); + auto& f2_params = du_pucch_cfg.f2_or_f3_or_f4_params.emplace(); f2_params.max_code_rate = user_pucch_cfg.f2_max_code_rate; f2_params.max_nof_rbs = user_pucch_cfg.f2_max_nof_rbs; f2_params.intraslot_freq_hopping = user_pucch_cfg.f2_intraslot_freq_hopping; f2_params.max_payload_bits = user_pucch_cfg.f2_max_payload_bits; } break; case 3: { - auto& f3_params = du_pucch_cfg.f2_or_f3_params.emplace(); + auto& f3_params = du_pucch_cfg.f2_or_f3_or_f4_params.emplace(); f3_params.max_code_rate = user_pucch_cfg.f3_max_code_rate; f3_params.max_nof_rbs = user_pucch_cfg.f3_max_nof_rbs; f3_params.intraslot_freq_hopping = user_pucch_cfg.f3_intraslot_freq_hopping; @@ -569,6 +569,14 @@ std::vector srsran::generate_du_cell_config(const du_hig f3_params.additional_dmrs = user_pucch_cfg.f3_additional_dmrs; f3_params.pi2_bpsk = user_pucch_cfg.f3_pi2_bpsk; } break; + case 4: { + auto& f4_params = du_pucch_cfg.f2_or_f3_or_f4_params.emplace(); + f4_params.max_code_rate = user_pucch_cfg.f4_max_code_rate; + f4_params.intraslot_freq_hopping = user_pucch_cfg.f4_intraslot_freq_hopping; + f4_params.additional_dmrs = user_pucch_cfg.f4_additional_dmrs; + f4_params.pi2_bpsk = user_pucch_cfg.f4_pi2_bpsk; + f4_params.occ_length = user_pucch_cfg.f4_occ_length == 2 ? pucch_f4_occ_len::n2 : pucch_f4_occ_len::n4; + } break; default: break; } @@ -686,9 +694,12 @@ std::vector srsran::generate_du_cell_config(const du_hig auto& f1_params = std::get(du_pucch_cfg.f0_or_f1_params); f1_params.nof_symbols = std::min(du_pucch_cfg.max_nof_symbols.to_uint(), f1_params.nof_symbols.to_uint()); } - if (std::holds_alternative(du_pucch_cfg.f2_or_f3_params)) { - auto& f3_params = std::get(du_pucch_cfg.f2_or_f3_params); + if (std::holds_alternative(du_pucch_cfg.f2_or_f3_or_f4_params)) { + auto& f3_params = std::get(du_pucch_cfg.f2_or_f3_or_f4_params); f3_params.nof_symbols = std::min(du_pucch_cfg.max_nof_symbols.to_uint(), f3_params.nof_symbols.to_uint()); + } else if (std::holds_alternative(du_pucch_cfg.f2_or_f3_or_f4_params)) { + auto& f4_params = std::get(du_pucch_cfg.f2_or_f3_or_f4_params); + f4_params.nof_symbols = std::min(du_pucch_cfg.max_nof_symbols.to_uint(), f4_params.nof_symbols.to_uint()); } } if (update_msg1_frequency_start) { diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index 3868a14d1b..d9546bf957 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -400,13 +400,14 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& const du_high_unit_pucch_config& pucch_cfg = config.pucch_cfg; if (not config.csi_cfg.csi_rs_enabled and pucch_cfg.nof_cell_csi_resources > 0) { fmt::print( - "Number of PUCCH Format 2/3 cell resources for CSI must be zero when CSI-RS and CSI report are disabled.\n"); + "Number of PUCCH Format 2/3/4 cell resources for CSI must be zero when CSI-RS and CSI report are disabled.\n"); return false; } if (config.csi_cfg.csi_rs_enabled and pucch_cfg.nof_cell_csi_resources == 0) { - fmt::print("Number of PUCCH Format 2/3 cell resources for CSI must be greater than 0 when CSI-RS and CSI report " - "are enabled.\n"); + fmt::print( + "Number of PUCCH Format 2/3/4 cell resources for CSI must be greater than 0 when CSI-RS and CSI report are " + "enabled.\n"); return false; } @@ -440,7 +441,7 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& } // We need to count pucch_cfg.nof_ue_pucch_res_harq_per_set twice, as we have 2 sets of PUCCH resources for HARQ-ACK - // (PUCCH Resource Set Id 0 with Format 0/1 and PUCCH Resource Set Id 1 with Format 2/3). + // (PUCCH Resource Set Id 0 with Format 0/1 and PUCCH Resource Set Id 1 with Format 2/3/4). if (pucch_cfg.nof_ue_pucch_res_harq_per_set * 2U * pucch_cfg.nof_cell_harq_pucch_sets + pucch_cfg.nof_cell_sr_resources + pucch_cfg.nof_cell_csi_resources > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { @@ -536,6 +537,18 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; } } break; + case 4: { + // The number of symbols per PUCCH resource is not exposed to the DU user interface; for PUCCH F4, we use all + // symbols available for PUCCH within a slot. + const unsigned pucch_f4_nof_symbols = max_nof_pucch_symbols; + const unsigned nof_f4_blocks = max_nof_pucch_symbols / pucch_f4_nof_symbols; + nof_f2_f3_f4_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f4_blocks))); + // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. + if (pucch_cfg.f4_intraslot_freq_hopping) { + nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; + } + } break; default: fmt::print("Invalid PUCCH format for Set Id 1.\n"); return false; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp index 70f4624bb2..e4702cd239 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp @@ -407,29 +407,34 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c { YAML::Node node; - node["p0_nominal"] = config.p0_nominal; - node["pucch_resource_common"] = config.pucch_resource_common; - node["use_format_0"] = config.use_format_0; - node["set1_format"] = config.set1_format; - node["sr_period_ms"] = config.sr_period_msec; - node["nof_ue_pucch_res_harq_per_set"] = config.nof_ue_pucch_res_harq_per_set; - node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; - node["f0_intraslot_freq_hop"] = config.f0_intraslot_freq_hopping; - node["f1_enable_occ"] = config.f1_enable_occ; - node["f1_nof_cyclic_shifts"] = config.f1_nof_cyclic_shifts; - node["f1_intraslot_freq_hop"] = config.f1_intraslot_freq_hopping; - node["nof_cell_harq_pucch_res_sets"] = config.nof_cell_harq_pucch_sets; - node["f2_or_f3_nof_cell_res_csi"] = config.nof_cell_csi_resources; - node["f2_max_nof_rbs"] = config.f2_max_nof_rbs; - node["f2_max_code_rate"] = to_string(config.f2_max_code_rate); - node["f2_intraslot_freq_hop"] = config.f2_intraslot_freq_hopping; - node["f3_max_nof_rbs"] = config.f3_max_nof_rbs; - node["f3_max_code_rate"] = to_string(config.f3_max_code_rate); - node["f3_intraslot_freq_hop"] = config.f3_intraslot_freq_hopping; - node["f3_additional_dmrs"] = config.f3_additional_dmrs; - node["f3_pi2_bpsk"] = config.f3_pi2_bpsk; - node["min_k1"] = config.min_k1; - node["max_consecutive_kos"] = config.max_consecutive_kos; + node["p0_nominal"] = config.p0_nominal; + node["pucch_resource_common"] = config.pucch_resource_common; + node["use_format_0"] = config.use_format_0; + node["set1_format"] = config.set1_format; + node["sr_period_ms"] = config.sr_period_msec; + node["nof_ue_pucch_res_harq_per_set"] = config.nof_ue_pucch_res_harq_per_set; + node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; + node["f0_intraslot_freq_hop"] = config.f0_intraslot_freq_hopping; + node["f1_enable_occ"] = config.f1_enable_occ; + node["f1_nof_cyclic_shifts"] = config.f1_nof_cyclic_shifts; + node["f1_intraslot_freq_hop"] = config.f1_intraslot_freq_hopping; + node["nof_cell_harq_pucch_res_sets"] = config.nof_cell_harq_pucch_sets; + node["f2_or_f3_or_f4_nof_cell_res_csi"] = config.nof_cell_csi_resources; + node["f2_max_nof_rbs"] = config.f2_max_nof_rbs; + node["f2_max_code_rate"] = to_string(config.f2_max_code_rate); + node["f2_intraslot_freq_hop"] = config.f2_intraslot_freq_hopping; + node["f3_max_nof_rbs"] = config.f3_max_nof_rbs; + node["f3_max_code_rate"] = to_string(config.f3_max_code_rate); + node["f3_intraslot_freq_hop"] = config.f3_intraslot_freq_hopping; + node["f3_additional_dmrs"] = config.f3_additional_dmrs; + node["f3_pi2_bpsk"] = config.f3_pi2_bpsk; + node["f4_intraslot_freq_hop"] = config.f4_intraslot_freq_hopping; + node["f4_additional_dmrs"] = config.f4_additional_dmrs; + node["f4_pi2_bpsk"] = config.f4_pi2_bpsk; + node["f4_occ_length"] = config.f4_occ_length; + node["f4_occ_length"] = config.f4_occ_length; + node["min_k1"] = config.min_k1; + node["max_consecutive_kos"] = config.max_consecutive_kos; if (config.f2_max_payload_bits.has_value()) { node["f2_max_payload"] = config.f2_max_payload_bits.value(); } diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index 594e468679..36ca38830c 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -80,6 +80,16 @@ struct pucch_f3_params { bool pi2_bpsk{false}; }; +/// Collects the parameters for PUCCH Format 4 that can be configured. +struct pucch_f4_params { + bounded_integer nof_symbols{14}; + max_pucch_code_rate max_code_rate{max_pucch_code_rate::dot_25}; + bool intraslot_freq_hopping{false}; + bool additional_dmrs{false}; + bool pi2_bpsk{false}; + pucch_f4_occ_len occ_length{pucch_f4_occ_len::n2}; +}; + /// \brief Parameters for PUCCH configuration. /// Defines the parameters that are used for the PUCCH configuration builder. These parameters are used to define the /// number of PUCCH resources, as well as the PUCCH format-specific parameters. @@ -87,9 +97,9 @@ struct pucch_builder_params { /// UE specific parameters. Use to set the number of resources per UE for HARQ-ACK reporting (not including SR/CSI /// dedicated resources). NOTE: by default, each UE is assigned 1 SR and 1 CSI resource. /// \remark Format 0 and Format 1 resources are mutually exclusive. - /// \remark Format 2 and Format 3 resources are mutually exclusive. - bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 6; - bounded_integer nof_ue_pucch_f2_or_f3_res_harq = 6; + /// \remark Format 2 and Format 3 and Format 4 resources are mutually exclusive. + bounded_integer nof_ue_pucch_f0_or_f1_res_harq = 6; + bounded_integer nof_ue_pucch_f2_or_f3_or_f4_res_harq = 6; /// \brief Number of separate PUCCH resource sets for HARQ-ACK reporting that are available in a cell. /// \remark UEs will be distributed possibly over different HARQ-ACK PUCCH sets; the more sets, the fewer UEs will /// have to share the same set, which reduces the chances that UEs won't be allocated PUCCH due to lack of resources. @@ -98,14 +108,14 @@ struct pucch_builder_params { /// Defines how many PUCCH F0 or F1 resources should be dedicated for SR at cell level; each UE will be allocated 1 /// resource for SR. unsigned nof_sr_resources = 2; - /// Defines how many PUCCH F2 or F3 resources should be dedicated for CSI at cell level; each UE will be allocated 1 - /// resource for CSI. + /// Defines how many PUCCH F2 or F3 or F4 resources should be dedicated for CSI at cell level; each UE will be + /// allocated 1 resource for CSI. unsigned nof_csi_resources = 1; /// PUCCH Format specific parameters. // NOTE: Having \c pucch_f1_params first forces the variant to use the Format 1 in the default constructor. - std::variant f0_or_f1_params; - std::variant f2_or_f3_params; + std::variant f0_or_f1_params; + std::variant f2_or_f3_or_f4_params; /// Maximum number of symbols per UL slot dedicated for PUCCH. /// \remark In case of Sounding Reference Signals (SRS) being used, the number of symbols should be reduced so that /// the PUCCH resources do not overlap in symbols with the SRS resources. diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index 2a01a5219f..2dc7b4e65b 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -13,6 +13,7 @@ #include "srsran/adt/bounded_integer.h" #include "srsran/adt/to_array.h" #include "srsran/phy/constants.h" +#include "srsran/ran/pucch/pucch_configuration.h" #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/ran/uci/uci_info.h" @@ -45,7 +46,6 @@ inline float pucch_format2_code_rate(unsigned nof_prb, unsigned nof_symbols, uns { // As per Table 6.3.1.4.1-1, TS 38.212, for UCI of transmissions of CSI of one part only, // \f$E_{UCI}\f$ = \f$E_{tot}\f$. - // TODO: replace this with a function that returns the e_uci for the general case. const unsigned e_uci = get_pucch_format2_E_total(nof_prb, nof_symbols); // As per Sections 6.3.1.2.1 and 6.3.1.4.1, TS 38.212, the parameter \f$E\f$ used to derive the number of @@ -148,9 +148,9 @@ get_pucch_format2_nof_prbs(unsigned nof_payload_bits, unsigned max_nof_prbs, uns } /// \brief Calculates the maximum payload for a PUCCH Format 2 transmission. -/// \param[in] max_nof_prbs Transmission bandwidth in PRBs. -/// \param[in] nof_symbols Transmission duration in symbols. -/// \param[in] max_code_rate Maximum allowed PUCCH Format 2 code rate. +/// \param[in] max_nof_prbs Transmission bandwidth in PRBs. +/// \param[in] nof_symbols Transmission duration in symbols. +/// \param[in] max_code_rate Maximum allowed PUCCH Format 2 code rate. /// \return The maximum payload for a PUCCH Format 2 transmission. unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate); @@ -208,6 +208,21 @@ unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, bool additional_dmrs, bool pi2_bpsk); +/// \brief Calculates the maximum payload for a PUCCH Format 4 transmission. +/// \param[in] nof_symbols Transmission duration in symbols. +/// \param[in] max_code_rate Maximum allowed PUCCH Format 4 code rate. +/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. +/// \param[in] pi2_bpsk Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] occ_length OCC length. +/// \return The maximum payload for a PUCCH Format 4 transmission. +unsigned get_pucch_format4_max_payload(unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk, + pucch_f4_occ_len occ_length); + /// Returns the number of possible spreading factors which is a function of the number of symbols. inline unsigned format1_symb_to_spreading_factor(bounded_integer f1_symbols) { diff --git a/include/srsran/ran/sr_configuration.h b/include/srsran/ran/sr_configuration.h index dab949159b..fb5fbcfe11 100644 --- a/include/srsran/ran/sr_configuration.h +++ b/include/srsran/ran/sr_configuration.h @@ -13,6 +13,7 @@ #include "srsran/ran/pucch/pucch_mapping.h" #include "srsran/support/error_handling.h" #include +#include namespace srsran { diff --git a/include/srsran/scheduler/scheduler_pucch_format.h b/include/srsran/scheduler/scheduler_pucch_format.h index a055e7b3fa..f00963213d 100644 --- a/include/srsran/scheduler/scheduler_pucch_format.h +++ b/include/srsran/scheduler/scheduler_pucch_format.h @@ -118,7 +118,7 @@ struct pucch_format_4 { unsigned harq_ack_nof_bits; unsigned csi_part1_bits; pucch_repetition_tx_slot slot_repetition; - uint16_t n_id_scambling; + uint16_t n_id_scrambling; bool pi_2_bpsk; max_pucch_code_rate max_code_rate; /// \c occ-Index as per TS 38.331, or equivalent to index \f$n\f$ in Tables 6.3.2.6.3-1/2, TS 38.211. Only for PUCCH diff --git a/lib/du/du_cell_config_validation.cpp b/lib/du/du_cell_config_validation.cpp index 6c31ef2b0b..f3e43e8bfe 100644 --- a/lib/du/du_cell_config_validation.cpp +++ b/lib/du/du_cell_config_validation.cpp @@ -759,10 +759,10 @@ check_outcome srs_du::is_du_cell_config_valid(const du_cell_config& cell_cfg) HANDLE_ERROR(srs_du::pucch_parameters_validator( pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * pucch_cfg.nof_cell_harq_pucch_res_sets + pucch_cfg.nof_sr_resources, - pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * pucch_cfg.nof_cell_harq_pucch_res_sets + + pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() * pucch_cfg.nof_cell_harq_pucch_res_sets + pucch_cfg.nof_csi_resources, pucch_cfg.f0_or_f1_params, - pucch_cfg.f2_or_f3_params, + pucch_cfg.f2_or_f3_or_f4_params, cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(), pucch_cfg.max_nof_symbols)); HANDLE_ERROR(check_prach_config(cell_cfg)); diff --git a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index ea57f5cdf1..b01fd29d6f 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -41,10 +41,16 @@ static pucch_config build_default_pucch_cfg(const pucch_config& pucch_cfg, const target_pucch_cfg.format_1_common_param.reset(); } std::visit( - [&target_pucch_cfg](const auto& f2_or_f3_params) { - target_pucch_cfg.format_2_common_param.value().max_c_rate = f2_or_f3_params.max_code_rate; + [&target_pucch_cfg](const auto& params) { + if constexpr (std::is_same_v) { + target_pucch_cfg.format_2_common_param.value().max_c_rate = params.max_code_rate; + } else if constexpr (std::is_same_v) { + target_pucch_cfg.format_3_common_param.value().max_c_rate = params.max_code_rate; + } else if constexpr (std::is_same_v) { + target_pucch_cfg.format_4_common_param.value().max_c_rate = params.max_code_rate; + } }, - user_params.f2_or_f3_params); + user_params.f2_or_f3_or_f4_params); return target_pucch_cfg; } @@ -56,11 +62,11 @@ du_pucch_resource_manager::du_pucch_resource_manager(span srs_du::generate_cell_pucch_res_list(cell_cfg_list_[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * cell_cfg_list_[0].pucch_cfg.nof_cell_harq_pucch_res_sets + cell_cfg_list_[0].pucch_cfg.nof_sr_resources, - cell_cfg_list_[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * + cell_cfg_list_[0].pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() * cell_cfg_list_[0].pucch_cfg.nof_cell_harq_pucch_res_sets + cell_cfg_list_[0].pucch_cfg.nof_csi_resources, cell_cfg_list_[0].pucch_cfg.f0_or_f1_params, - cell_cfg_list_[0].pucch_cfg.f2_or_f3_params, + cell_cfg_list_[0].pucch_cfg.f2_or_f3_or_f4_params, cell_cfg_list_[0].ul_cfg_common.init_ul_bwp.generic_params.crbs.length(), cell_cfg_list_[0].pucch_cfg.max_nof_symbols)), default_pucch_cfg( @@ -295,7 +301,7 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) sr_res_offset.value().first, csi_res_offset.has_value() ? csi_res_offset.value().first : 0, user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq, - user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq, + user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq, user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets, user_defined_pucch_cfg.nof_sr_resources, user_defined_pucch_cfg.nof_csi_resources); @@ -316,16 +322,16 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) cell_grp_cfg.cells[0].serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value().format_max_payload[pucch_format_to_uint( pucch_format::FORMAT_1)] = pucch_f1_max_harq_payload; - if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_params)) { - const auto& f2_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_or_f4_params)) { + const auto& f2_params = std::get(user_defined_pucch_cfg.f2_or_f3_or_f4_params); cell_grp_cfg.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() .format_max_payload[pucch_format_to_uint(pucch_format::FORMAT_2)] = get_pucch_format2_max_payload( f2_params.max_nof_rbs, f2_params.nof_symbols.to_uint(), to_max_code_rate_float(default_pucch_cfg.format_2_common_param.value().max_c_rate)); - } else { - const auto& f3_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + } else if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_or_f4_params)) { + const auto& f3_params = std::get(user_defined_pucch_cfg.f2_or_f3_or_f4_params); cell_grp_cfg.cells[0] .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() .format_max_payload[pucch_format_to_uint(pucch_format::FORMAT_3)] = get_pucch_format3_max_payload( @@ -335,6 +341,17 @@ bool du_pucch_resource_manager::alloc_resources(cell_group_config& cell_grp_cfg) f3_params.intraslot_freq_hopping, f3_params.additional_dmrs, f3_params.pi2_bpsk); + } else { + const auto& f4_params = std::get(user_defined_pucch_cfg.f2_or_f3_or_f4_params); + cell_grp_cfg.cells[0] + .serv_cell_cfg.ul_config->init_ul_bwp.pucch_cfg.value() + .format_max_payload[pucch_format_to_uint(pucch_format::FORMAT_4)] = get_pucch_format4_max_payload( + f4_params.nof_symbols.to_uint(), + to_max_code_rate_float(default_pucch_cfg.format_4_common_param.value().max_c_rate), + f4_params.intraslot_freq_hopping, + f4_params.additional_dmrs, + f4_params.pi2_bpsk, + f4_params.occ_length); } ++cells[0].ue_idx; @@ -395,26 +412,37 @@ du_pucch_resource_manager::get_csi_resource_offset(const csi_meas_config& csi_me const sr_nof_bits sr_bits_to_report = sr_csi_on_the_same_slot ? sr_nof_bits::one : sr_nof_bits::no_sr; const unsigned candidate_uci_bits = sr_nof_bits_to_uint(sr_bits_to_report) + csi_report_size.value(); - const float max_pucch_code_rate = - to_max_code_rate_float(default_pucch_cfg.format_2_common_param.value().max_c_rate); - unsigned max_payload; - if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_params)) { - const auto& f2_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); + if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_or_f4_params)) { + const auto& f2_params = std::get(user_defined_pucch_cfg.f2_or_f3_or_f4_params); + const float max_pucch_code_rate = + to_max_code_rate_float(default_pucch_cfg.format_2_common_param.value().max_c_rate); max_payload = get_pucch_format2_max_payload(f2_params.max_nof_rbs, f2_params.nof_symbols.to_uint(), max_pucch_code_rate); - } else { - const auto& f3_params = std::get(user_defined_pucch_cfg.f2_or_f3_params); - max_payload = get_pucch_format3_max_payload(f3_params.max_nof_rbs, + } else if (std::holds_alternative(user_defined_pucch_cfg.f2_or_f3_or_f4_params)) { + const auto& f3_params = std::get(user_defined_pucch_cfg.f2_or_f3_or_f4_params); + const float max_pucch_code_rate = + to_max_code_rate_float(default_pucch_cfg.format_3_common_param.value().max_c_rate); + max_payload = get_pucch_format3_max_payload(f3_params.max_nof_rbs, f3_params.nof_symbols.to_uint(), max_pucch_code_rate, f3_params.intraslot_freq_hopping, f3_params.additional_dmrs, f3_params.pi2_bpsk); + } else { + const auto& f4_params = std::get(user_defined_pucch_cfg.f2_or_f3_or_f4_params); + const float max_pucch_code_rate = + to_max_code_rate_float(default_pucch_cfg.format_4_common_param.value().max_c_rate); + max_payload = get_pucch_format4_max_payload(f4_params.nof_symbols.to_uint(), + max_pucch_code_rate, + f4_params.intraslot_freq_hopping, + f4_params.additional_dmrs, + f4_params.pi2_bpsk, + f4_params.occ_length); } - // This is the case of suitable CSI offset found, but the CSI offset would result in exceeding the PUCCH F2 max - // payload. + // This is the case of suitable CSI offset found, but the CSI offset would result in exceeding the PUCCH F2/F3/F4 + // max payload. if (candidate_uci_bits > max_payload) { // Allocation failed, exit without allocating the UE resources. optimal_res_it = free_csi_list.end(); @@ -476,7 +504,7 @@ unsigned du_pucch_resource_manager::csi_du_res_idx_to_pucch_res_idx(unsigned csi return user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + user_defined_pucch_cfg.nof_sr_resources + - user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * + user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + csi_du_res_idx; } @@ -488,7 +516,7 @@ unsigned du_pucch_resource_manager::pucch_res_idx_to_csi_du_res_idx(unsigned puc return pucch_res_idx - (user_defined_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets + user_defined_pucch_cfg.nof_sr_resources + - user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * + user_defined_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() * user_defined_pucch_cfg.nof_cell_harq_pucch_res_sets); } diff --git a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp index 3bf3975e45..b1d3813b8e 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -52,6 +52,13 @@ static unsigned occ_cs_index_to_occ(unsigned occ_cs_idx, unsigned nof_css) return occ_cs_idx / nof_css; } +/// Given the OCC-CS index (implementation-defined), maps and returns the \c OCC-Index, defined as per +/// PUCCH-format4, in PUCCH-Config, TS 38.331. +static pucch_f4_occ_idx occ_cs_index_to_f4_occ(unsigned occ_cs_idx) +{ + return static_cast(occ_cs_idx); +} + static std::vector compute_f0_res(unsigned nof_res_f0, pucch_f0_params params, unsigned bwp_size_rbs, @@ -259,7 +266,7 @@ static std::vector compute_f1_res(unsigned } static std::vector compute_f2_res(unsigned nof_res_f2, - pucch_f2_params params, + const pucch_f2_params& params, unsigned bwp_size_rbs, bounded_integer max_nof_symbols) { @@ -354,7 +361,7 @@ static std::vector compute_f2_res(unsigned } static std::vector compute_f3_res(unsigned nof_res_f3, - pucch_f3_params params, + const pucch_f3_params& params, unsigned bwp_size_rbs, bounded_integer max_nof_symbols) { @@ -447,12 +454,98 @@ static std::vector compute_f3_res(unsigned return res_list; } -error_type srs_du::pucch_parameters_validator(unsigned nof_res_f0_f1, - unsigned nof_res_f2_f3, - std::variant f0_f1_params, - std::variant f2_f3_params, - unsigned bwp_size_rbs, - bounded_integer max_nof_symbols) +static std::vector compute_f4_res(unsigned nof_res_f4, + const pucch_f4_params& params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) +{ + std::vector res_list; + const unsigned nof_f4_symbols = params.nof_symbols.to_uint(); + const unsigned occ_length = params.occ_length == pucch_f4_occ_len::n2 ? 2 : 4; + + // With intraslot freq. hopping. + if (params.intraslot_freq_hopping) { + for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1; ++rb_idx) { + // Generate resource for increasing RB index, until the num. of required resources is reached. + const prb_interval prbs{rb_idx, rb_idx + 1}; + // Pre-compute the second RBs for the frequency hop specularly to the first RBs. + const prb_interval freq_hop_prbs{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; + + // Generate resource for increasing Symbol index, until the num. of required resources is reached. + for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f4_symbols) { + const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f4_symbols}; + + for (unsigned occ_index = 0; occ_index < occ_length; ++occ_index) { + // Allocate resources for first hop. + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_4, + .symbols = symbols, + .prbs = prbs, + .freq_hop_grant = freq_hop_prbs, + .occ_cs_idx = occ_index}); + if (res_list.size() == nof_res_f4) { + return res_list; + } + + // Allocate resources for second hop. + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_4, + .symbols = symbols, + .prbs = freq_hop_prbs, + .freq_hop_grant = prbs, + .occ_cs_idx = occ_index}); + if (res_list.size() == nof_res_f4) { + return res_list; + } + } + } + } + } + // With intraslot freq. hopping. + else { + for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1; ++rb_idx) { + const prb_interval prbs_low_spectrum{rb_idx, rb_idx + 1}; + // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve + // balancing of the PUCCH resources on both sides of the BWP. + const prb_interval prbs_hi_spectrum{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; + + // Generate resource for increasing Symbol index, until the num. of required resources is reached. + for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f4_symbols) { + const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f4_symbols}; + for (unsigned occ_index = 0; occ_index < occ_length; ++occ_index) { + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_4, + .symbols = symbols, + .prbs = prbs_low_spectrum, + .occ_cs_idx = occ_index}); + if (res_list.size() == nof_res_f4) { + return res_list; + } + } + } + + // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of + // the BWP. + for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= 14; sym_idx += nof_f4_symbols) { + const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f4_symbols}; + for (unsigned occ_index = 0; occ_index < occ_length; ++occ_index) { + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_4, .symbols = symbols, .prbs = prbs_hi_spectrum, .occ_cs_idx = occ_index}); + if (res_list.size() == nof_res_f4) { + return res_list; + } + } + } + } + } + + return res_list; +} + +error_type srs_du::pucch_parameters_validator( + unsigned nof_res_f0_f1, + unsigned nof_res_f2_f3_f4, + const std::variant& f0_f1_params, + const std::variant& f2_f3_f4_params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { const bool has_f0 = std::holds_alternative(f0_f1_params); unsigned nof_f0_f1_rbs = 0; @@ -494,11 +587,11 @@ error_type srs_du::pucch_parameters_validator(unsigned } } - const bool has_f2 = std::holds_alternative(f2_f3_params); - unsigned nof_f2_f3_rbs = 0; + unsigned nof_f2_f3_f4_rbs = 0; - if (has_f2) { - const auto& f2_params = std::get(f2_f3_params); + if (std::holds_alternative(f2_f3_f4_params)) { + // PUCCH Format 2. + const auto& f2_params = std::get(f2_f3_f4_params); // > If intraslot_freq_hopping is enabled, check if PUCCH Format 2 has more than symbol. if (f2_params.intraslot_freq_hopping and f2_params.nof_symbols == 1) { @@ -517,15 +610,17 @@ error_type srs_du::pucch_parameters_validator(unsigned // We define a block as a set of Resources (either F0/F1 or F2/F3) aligned over the same starting PRB. const unsigned nof_f2_blocks = max_nof_symbols.to_uint() / f2_params.nof_symbols.to_uint(); - nof_f2_f3_rbs = - static_cast(std::ceil(static_cast(nof_res_f2_f3) / static_cast(nof_f2_blocks))) * + nof_f2_f3_f4_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f2_blocks))) * f2_max_rbs; // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. if (f2_params.intraslot_freq_hopping) { - nof_f2_f3_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_rbs) / 2.0F)) * 2; + nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; } - } else { - const auto& f3_params = std::get(f2_f3_params); + } else if (std::holds_alternative(f2_f3_f4_params)) { + // PUCCH Format 3. + const auto& f3_params = std::get(f2_f3_f4_params); + if (f3_params.nof_symbols.to_uint() > max_nof_symbols.to_uint()) { return make_unexpected("The number of symbols for PUCCH Format 3 exceeds the maximum number of symbols available " "for PUCCH resources"); @@ -545,12 +640,23 @@ error_type srs_du::pucch_parameters_validator(unsigned } const unsigned nof_f3_blocks = max_nof_symbols.to_uint() / f3_params.nof_symbols.to_uint(); - nof_f2_f3_rbs = - static_cast(std::ceil(static_cast(nof_res_f2_f3) / static_cast(nof_f3_blocks))) * + nof_f2_f3_f4_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f3_blocks))) * f3_max_rbs; // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. if (f3_params.intraslot_freq_hopping) { - nof_f2_f3_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_rbs) / 2.0F)) * 2; + nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; + } + } else { + // PUCCH Format 4. + const auto& f4_params = std::get(f2_f3_f4_params); + + const unsigned nof_f4_blocks = max_nof_symbols.to_uint() / f4_params.nof_symbols.to_uint(); + nof_f2_f3_f4_rbs = + static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f4_blocks))); + // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. + if (f4_params.intraslot_freq_hopping) { + nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_f2_f3_f4_rbs) / 2.0F)) * 2; } } @@ -558,7 +664,8 @@ error_type srs_du::pucch_parameters_validator(unsigned // [Implementation-defined] We do not allow the PUCCH resources to occupy more than 50% of the BWP. This is an extreme // case, and ideally the PUCCH configuration should result in a much lower PRBs usage. constexpr float max_allowed_prbs_usage = 0.5F; - if (static_cast(nof_f0_f1_rbs + nof_f2_f3_rbs) / static_cast(bwp_size_rbs) >= max_allowed_prbs_usage) { + if (static_cast(nof_f0_f1_rbs + nof_f2_f3_f4_rbs) / static_cast(bwp_size_rbs) >= + max_allowed_prbs_usage) { return make_unexpected("With the given parameters, the number of PRBs for PUCCH exceeds the 50% of the BWP PRBs"); } @@ -566,19 +673,19 @@ error_type srs_du::pucch_parameters_validator(unsigned } static std::vector -merge_f0_f1_f2_f3_resource_lists(const std::vector& pucch_f0_f1_resource_list, - const std::vector& pucch_f2_f3_resource_list, - std::optional nof_cs, - unsigned bwp_size_rbs) +merge_f0_f1_f2_f3_f4_resource_lists(const std::vector& pucch_f0_f1_resource_list, + const std::vector& pucch_f2_f3_f4_resource_list, + std::optional nof_cs, + unsigned bwp_size_rbs) { - // This function merges the lists of PUCCH F0/F1 and F2/F3 resource. It first allocates the F0/F1 resources on the - // sides of the BWP; second, it allocates the F2/F3 resources beside F0/F1 ones. + // This function merges the lists of PUCCH F0/F1 and F2/F3/F4 resource. It first allocates the F0/F1 resources on the + // sides of the BWP; second, it allocates the F2/F3/F4 resources beside F0/F1 ones. std::vector resource_list; const bool has_f0 = not nof_cs.has_value(); - // NOTE: PUCCH F0/F1 resource are located at the sides of the BWP. PUCCH F2/F3 are located beside the F0/F1 resources, - // specifically on F0/F1's right (on the frequency axis) for frequencies < BWP/2, and F0/F1's left (on the frequency - // axis) for frequencies > BWP/2 and < BWP. + // NOTE: PUCCH F0/F1 resource are located at the sides of the BWP. PUCCH F2/F3/F4 are located beside the F0/F1 + // resources, specifically on F0/F1's right (on the frequency axis) for frequencies < BWP/2, and F0/F1's left (on the + // frequency axis) for frequencies > BWP/2 and < BWP. unsigned f0_f1_rbs_occupancy_low_freq = 0; unsigned f0_f1_rbs_occupancy_hi_freq = 0; @@ -593,7 +700,7 @@ merge_f0_f1_f2_f3_resource_lists(const std::vector& pucch_f0_f1_res } pucch_format_0_cfg format0{.initial_cyclic_shift = 0U, .starting_sym_idx = res_f0.symbols.start()}; - // Update the frequency shift for PUCCH F2/F3. + // Update the frequency shift for PUCCH F2/F3/F4. if (res_f0.prbs.start() < bwp_size_rbs / 2 - 1U) { // f0_f1_rbs_occupancy_low_freq accounts for the PUCCH F0/F1 resource occupancy on the first half of the BWP; // PUCCH F0/F1 resources are located on the lowest RBs indices. @@ -630,7 +737,7 @@ merge_f0_f1_f2_f3_resource_lists(const std::vector& pucch_f0_f1_res } pucch_format_1_cfg format1{.starting_sym_idx = res_f1.symbols.start()}; - // Update the frequency shift for PUCCH F2/F3. + // Update the frequency shift for PUCCH F2/F3/F4. if (res_f1.prbs.start() < bwp_size_rbs / 2 - 1) { // f0_f1_rbs_occupancy_low_freq accounts for the PUCCH F0/F1 resource occupancy on the first half of the BWP; // PUCCH F0/F1 resources are located on the lowest RBs indices. @@ -662,83 +769,119 @@ merge_f0_f1_f2_f3_resource_lists(const std::vector& pucch_f0_f1_res } } - // TODO: when the list is empty, we are assuming F3. - const bool has_f2 = - not pucch_f2_f3_resource_list.empty() ? pucch_f2_f3_resource_list[0].format == pucch_format::FORMAT_2 : false; - - if (has_f2) { - for (const auto& res_f2 : pucch_f2_f3_resource_list) { - auto res_id = static_cast(resource_list.size()); - // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU - // before assigning the resources to the UE. - pucch_resource res{.res_id = {res_id, 0}}; - // Shift F2 RBs depending on previously allocated F0/F1 resources. - if (res_f2.prbs.start() < bwp_size_rbs / 2 - res_f2.prbs.length()) { - res.starting_prb = res_f2.prbs.start() + f0_f1_rbs_occupancy_low_freq; - if (res_f2.freq_hop_grant.has_value()) { - res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); - } - } else if (res_f2.prbs.start() > bwp_size_rbs / 2) { - res.starting_prb = res_f2.prbs.start() - f0_f1_rbs_occupancy_hi_freq; - if (res_f2.freq_hop_grant.has_value()) { - res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + // TODO: when the list is empty, we are assuming F2. + const pucch_format set1_format = + not pucch_f2_f3_f4_resource_list.empty() ? pucch_f2_f3_f4_resource_list[0].format : pucch_format::FORMAT_2; + + switch (set1_format) { + case pucch_format::FORMAT_2: { + for (const auto& res_f2 : pucch_f2_f3_f4_resource_list) { + auto res_id = static_cast(resource_list.size()); + // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU + // before assigning the resources to the UE. + pucch_resource res{.res_id = {res_id, 0}}; + // Shift F2 RBs depending on previously allocated F0/F1 resources. + if (res_f2.prbs.start() < bwp_size_rbs / 2 - res_f2.prbs.length()) { + res.starting_prb = res_f2.prbs.start() + f0_f1_rbs_occupancy_low_freq; + if (res_f2.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); + } + } else if (res_f2.prbs.start() > bwp_size_rbs / 2) { + res.starting_prb = res_f2.prbs.start() - f0_f1_rbs_occupancy_hi_freq; + if (res_f2.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f2.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + } + } else { + srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); + return {}; } - } else { - srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); - return {}; - } - pucch_format_2_3_cfg format2{.starting_sym_idx = res_f2.symbols.start()}; - format2.nof_symbols = res_f2.symbols.length(); - format2.nof_prbs = res_f2.prbs.length(); - res.format_params.emplace(format2); - res.format = pucch_format::FORMAT_2; - resource_list.emplace_back(res); - } - } else { - for (const auto& res_f3 : pucch_f2_f3_resource_list) { - auto res_id = static_cast(resource_list.size()); - // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU - // before assigning the resources to the UE. - pucch_resource res{.res_id = {res_id, 0}}; - // Shift F2 RBs depending on previously allocated F0/F1 resources. - if (res_f3.prbs.start() < bwp_size_rbs / 2 - res_f3.prbs.length()) { - res.starting_prb = res_f3.prbs.start() + f0_f1_rbs_occupancy_low_freq; - if (res_f3.freq_hop_grant.has_value()) { - res.second_hop_prb.emplace(res_f3.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); - } - } else if (res_f3.prbs.start() > bwp_size_rbs / 2) { - res.starting_prb = res_f3.prbs.start() - f0_f1_rbs_occupancy_hi_freq; - if (res_f3.freq_hop_grant.has_value()) { - res.second_hop_prb.emplace(res_f3.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + pucch_format_2_3_cfg format2{.starting_sym_idx = res_f2.symbols.start()}; + format2.nof_symbols = res_f2.symbols.length(); + format2.nof_prbs = res_f2.prbs.length(); + res.format_params.emplace(format2); + res.format = pucch_format::FORMAT_2; + resource_list.emplace_back(res); + } + } break; + case pucch_format::FORMAT_3: { + for (const auto& res_f3 : pucch_f2_f3_f4_resource_list) { + auto res_id = static_cast(resource_list.size()); + // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU + // before assigning the resources to the UE. + pucch_resource res{.res_id = {res_id, 0}}; + // Shift F3 RBs depending on previously allocated F0/F1 resources. + if (res_f3.prbs.start() < bwp_size_rbs / 2 - res_f3.prbs.length()) { + res.starting_prb = res_f3.prbs.start() + f0_f1_rbs_occupancy_low_freq; + if (res_f3.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f3.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); + } + } else if (res_f3.prbs.start() > bwp_size_rbs / 2) { + res.starting_prb = res_f3.prbs.start() - f0_f1_rbs_occupancy_hi_freq; + if (res_f3.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f3.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + } + } else { + srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); + return {}; } - } else { - srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); - return {}; + + pucch_format_2_3_cfg format3{.starting_sym_idx = res_f3.symbols.start()}; + format3.nof_symbols = res_f3.symbols.length(); + format3.nof_prbs = res_f3.prbs.length(); + res.format_params.emplace(format3); + res.format = pucch_format::FORMAT_3; + resource_list.emplace_back(res); } + } break; + case pucch_format::FORMAT_4: { + for (const auto& res_f4 : pucch_f2_f3_f4_resource_list) { + auto res_id = static_cast(resource_list.size()); + // No need to set res_id.second, which is the PUCCH resource ID for the ASN1 message. This will be set by the DU + // before assigning the resources to the UE. + pucch_resource res{.res_id = {res_id, 0}}; + // Shift F4 RBs depending on previously allocated F0/F1 resources. + if (res_f4.prbs.start() < bwp_size_rbs / 2 - res_f4.prbs.length()) { + res.starting_prb = res_f4.prbs.start() + f0_f1_rbs_occupancy_low_freq; + if (res_f4.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f4.freq_hop_grant.value().start() - f0_f1_rbs_occupancy_hi_freq); + } + } else if (res_f4.prbs.start() > bwp_size_rbs / 2) { + res.starting_prb = res_f4.prbs.start() - f0_f1_rbs_occupancy_hi_freq; + if (res_f4.freq_hop_grant.has_value()) { + res.second_hop_prb.emplace(res_f4.freq_hop_grant.value().start() + f0_f1_rbs_occupancy_low_freq); + } + } else { + srsran_assert(false, "PUCCH resources are not expected to be allocated at the centre of the BWP"); + return {}; + } - pucch_format_2_3_cfg format3{.starting_sym_idx = res_f3.symbols.start()}; - format3.nof_symbols = res_f3.symbols.length(); - format3.nof_prbs = res_f3.prbs.length(); - res.format_params.emplace(format3); - res.format = pucch_format::FORMAT_3; - resource_list.emplace_back(res); - } + pucch_format_4_cfg format4{.starting_sym_idx = res_f4.symbols.start()}; + format4.nof_symbols = res_f4.symbols.length(); + format4.occ_length = pucch_f4_occ_len::n4; + format4.occ_index = occ_cs_index_to_f4_occ(res_f4.occ_cs_idx.value()); + res.format_params.emplace(format4); + res.format = pucch_format::FORMAT_4; + resource_list.emplace_back(res); + } + } break; + default: + break; } return resource_list; } -std::vector -srs_du::generate_cell_pucch_res_list(unsigned nof_res_f0_f1, - unsigned nof_res_f2_f3, - std::variant f0_f1_params, - std::variant f2_f3_params, - unsigned bwp_size_rbs, - bounded_integer max_nof_symbols) +std::vector srs_du::generate_cell_pucch_res_list( + unsigned nof_res_f0_f1, + unsigned nof_res_f2_f3_f4, + const std::variant& f0_f1_params, + const std::variant& f2_f3_f4_params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols) { auto outcome = pucch_parameters_validator( - nof_res_f0_f1, nof_res_f2_f3, f0_f1_params, f2_f3_params, bwp_size_rbs, max_nof_symbols); + nof_res_f0_f1, nof_res_f2_f3_f4, f0_f1_params, f2_f3_f4_params, bwp_size_rbs, max_nof_symbols); if (not outcome.has_value()) { srsran_assertion_failure("The cell list could not be generated due to: {}", outcome.error()); return {}; @@ -746,7 +889,7 @@ srs_du::generate_cell_pucch_res_list(unsigned const bool has_f0 = std::holds_alternative(f0_f1_params); - // Compute the PUCCH F0/F1 and F2/F3 resources separately. + // Compute the PUCCH F0/F1 and F2/F3/F4 resources separately. std::vector pucch_f0_f1_resource_list; unsigned nof_css = 0; if (has_f0 and nof_res_f0_f1 > 0) { @@ -761,21 +904,22 @@ srs_du::generate_cell_pucch_res_list(unsigned compute_f1_res(nof_res_f0_f1, f1_params, bwp_size_rbs, nof_css * nof_occ_codes, max_nof_symbols); } - const bool has_f2 = std::holds_alternative(f2_f3_params); - - std::vector pucch_f2_f3_resource_list; - if (has_f2 and nof_res_f2_f3 > 0) { - const pucch_f2_params f2_params = std::get(f2_f3_params); - pucch_f2_f3_resource_list = compute_f2_res(nof_res_f2_f3, f2_params, bwp_size_rbs, max_nof_symbols); - } else if (nof_res_f2_f3 > 0) { - const pucch_f3_params f3_params = std::get(f2_f3_params); - pucch_f2_f3_resource_list = compute_f3_res(nof_res_f2_f3, f3_params, bwp_size_rbs, max_nof_symbols); + std::vector pucch_f2_f3_f4_resource_list; + if (std::holds_alternative(f2_f3_f4_params)) { + const auto& f2_params = std::get(f2_f3_f4_params); + pucch_f2_f3_f4_resource_list = compute_f2_res(nof_res_f2_f3_f4, f2_params, bwp_size_rbs, max_nof_symbols); + } else if (std::holds_alternative(f2_f3_f4_params)) { + const auto& f3_params = std::get(f2_f3_f4_params); + pucch_f2_f3_f4_resource_list = compute_f3_res(nof_res_f2_f3_f4, f3_params, bwp_size_rbs, max_nof_symbols); + } else { + const auto& f4_params = std::get(f2_f3_f4_params); + pucch_f2_f3_f4_resource_list = compute_f4_res(nof_res_f2_f3_f4, f4_params, bwp_size_rbs, max_nof_symbols); } - auto res_list = merge_f0_f1_f2_f3_resource_lists(pucch_f0_f1_resource_list, - pucch_f2_f3_resource_list, - has_f0 ? std::nullopt : std::optional{nof_css}, - bwp_size_rbs); + auto res_list = merge_f0_f1_f2_f3_f4_resource_lists(pucch_f0_f1_resource_list, + pucch_f2_f3_f4_resource_list, + has_f0 ? std::nullopt : std::optional{nof_css}, + bwp_size_rbs); if (res_list.size() > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { srsran_assertion_failure("With the given parameters, the number of PUCCH resources generated for the " @@ -787,13 +931,13 @@ srs_du::generate_cell_pucch_res_list(unsigned return res_list; } -static unsigned -cell_res_list_and_params_validator(const std::vector& res_list, - bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_f3_res_harq, - unsigned nof_harq_pucch_cfgs, - unsigned nof_cell_pucch_f0_f1_res_sr, - unsigned nof_cell_pucch_f2_f3_res_csi) +static unsigned cell_res_list_and_params_validator( + const std::vector& res_list, + bounded_integer nof_ue_pucch_f0_f1_res_harq, + bounded_integer nof_ue_pucch_f2_f3_f4_res_harq, + unsigned nof_harq_pucch_cfgs, + unsigned nof_cell_pucch_f0_f1_res_sr, + unsigned nof_cell_pucch_f2_f3_f4_res_csi) { constexpr unsigned FAILURE_CASE = 0U; @@ -820,8 +964,8 @@ cell_res_list_and_params_validator(const std::vector& "resources in set 0 are reserved."); return FAILURE_CASE; } - if (nof_ue_pucch_f2_f3_res_harq.to_uint() > 6U) { - srsran_assertion_failure("With Format 0, nof_ue_pucch_f2_f3_res_harq cannot be greater than 6, as 2 " + if (nof_ue_pucch_f2_f3_f4_res_harq.to_uint() > 6U) { + srsran_assertion_failure("With Format 0, nof_ue_pucch_f2_f3_f4_res_harq cannot be greater than 6, as 2 " "resources in set 1 are reserved."); return FAILURE_CASE; } @@ -831,55 +975,60 @@ cell_res_list_and_params_validator(const std::vector& const unsigned tot_nof_f1_res = count_resources(pucch_format::FORMAT_1); const unsigned tot_nof_f2_res = count_resources(pucch_format::FORMAT_2); const unsigned tot_nof_f3_res = count_resources(pucch_format::FORMAT_3); + const unsigned tot_nof_f4_res = count_resources(pucch_format::FORMAT_4); if (tot_nof_f0_res != 0 and tot_nof_f1_res != 0) { srsran_assertion_failure("The cell PUCCH resource list can contain either F0 or F1 PUCCH resources, but not both."); return FAILURE_CASE; } - if (tot_nof_f2_res != 0 and tot_nof_f3_res != 0) { - srsran_assertion_failure("The cell PUCCH resource list can contain either F2 or F3 PUCCH resources, but not both."); + if ((tot_nof_f2_res != 0) + (tot_nof_f3_res != 0) + (tot_nof_f4_res != 0) > 1) { + srsran_assertion_failure( + "The cell PUCCH resource list can contain either F2, F3 or F4 PUCCH resources, but not a mix of those types."); return FAILURE_CASE; } - if (tot_nof_f0_res != 0 and (tot_nof_f3_res != 0)) { + if (tot_nof_f0_res != 0 and (tot_nof_f3_res != 0 or tot_nof_f4_res != 0)) { srsran_assertion_failure( - "The implementation is not currently prepared to handle PUCCH F0 and F3 resources at the same time."); + "The implementation is not prepared to handle PUCCH F0 and F3 or F0 and F4 resources at the same time."); return FAILURE_CASE; } - const unsigned tot_nof_f0_f1_res = tot_nof_f0_res + tot_nof_f1_res; - const unsigned tot_nof_f2_f3_res = tot_nof_f2_res + tot_nof_f3_res; + const unsigned tot_nof_f0_f1_res = tot_nof_f0_res + tot_nof_f1_res; + const unsigned tot_nof_f2_f3_f4_res = tot_nof_f2_res + tot_nof_f3_res + tot_nof_f4_res; - if (tot_nof_f0_f1_res + tot_nof_f2_f3_res != res_list.size()) { + if (tot_nof_f0_f1_res + tot_nof_f2_f3_f4_res != res_list.size()) { srsran_assertion_failure( - "The sum of F0/F1 and F2/F3 PUCCH resources must be equal to the cell PUCCH resource list size."); + "The sum of F0/F1 and F2/F3/F4 PUCCH resources must be equal to the cell PUCCH resource list size."); return FAILURE_CASE; } - if (tot_nof_f0_f1_res < 2 or tot_nof_f2_f3_res < 2) { - srsran_assertion_failure("The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2/F3 PUCCH resources."); + if (tot_nof_f0_f1_res < 2 or tot_nof_f2_f3_f4_res < 2) { + srsran_assertion_failure( + "The cell PUCCH resource list must contain at least 2 F0/F1 and 2 F2/F3/F4 PUCCH resources."); return FAILURE_CASE; } if (nof_ue_pucch_f0_f1_res_harq.to_uint() > tot_nof_f0_f1_res - nof_cell_pucch_f0_f1_res_sr or - nof_ue_pucch_f2_f3_res_harq.to_uint() > tot_nof_f2_f3_res - nof_cell_pucch_f2_f3_res_csi) { + nof_ue_pucch_f2_f3_f4_res_harq.to_uint() > tot_nof_f2_f3_f4_res - nof_cell_pucch_f2_f3_f4_res_csi) { srsran_assertion_failure( "The nof requested UE PUCCH resources is greater than the nof of resources available in the cell."); return FAILURE_CASE; } if ((nof_ue_pucch_f0_f1_res_harq.to_uint() * nof_harq_pucch_cfgs > tot_nof_f0_f1_res - nof_cell_pucch_f0_f1_res_sr) or - (nof_ue_pucch_f2_f3_res_harq.to_uint() * nof_harq_pucch_cfgs > - tot_nof_f2_f3_res - nof_cell_pucch_f2_f3_res_csi)) { + (nof_ue_pucch_f2_f3_f4_res_harq.to_uint() * nof_harq_pucch_cfgs > + tot_nof_f2_f3_f4_res - nof_cell_pucch_f2_f3_f4_res_csi)) { srsran_assertion_failure( "The cell PUCCH resource list doesn't contain enough resources to allocate all requested UEs."); return FAILURE_CASE; } for (unsigned res_idx = 0; res_idx != tot_nof_f0_f1_res; ++res_idx) { - if (res_list[res_idx].format == pucch_format::FORMAT_2 || res_list[res_idx].format == pucch_format::FORMAT_3) { - srsran_assertion_failure("The F0/F1 resources in the cell PUCCH resource list must precede all F2/F3 resources."); + if (res_list[res_idx].format == pucch_format::FORMAT_2 || res_list[res_idx].format == pucch_format::FORMAT_3 || + res_list[res_idx].format == pucch_format::FORMAT_4) { + srsran_assertion_failure( + "The F0/F1 resources in the cell PUCCH resource list must precede all F2/F3/F4 resources."); return FAILURE_CASE; } } @@ -887,23 +1036,24 @@ cell_res_list_and_params_validator(const std::vector& return tot_nof_f0_res != 0 ? tot_nof_f0_res : tot_nof_f1_res; } -bool srs_du::ue_pucch_config_builder(serving_cell_config& serv_cell_cfg, - const std::vector& res_list, - unsigned du_harq_set_idx, - unsigned du_sr_res_idx, - unsigned du_csi_res_idx, - bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_f3_res_harq, - unsigned nof_harq_pucch_sets, - unsigned nof_cell_pucch_f0_f1_res_sr, - unsigned nof_cell_pucch_f2_f3_res_csi) +bool srs_du::ue_pucch_config_builder( + serving_cell_config& serv_cell_cfg, + const std::vector& res_list, + unsigned du_harq_set_idx, + unsigned du_sr_res_idx, + unsigned du_csi_res_idx, + bounded_integer nof_ue_pucch_f0_f1_res_harq, + bounded_integer nof_ue_pucch_f2_f3_f4_res_harq, + unsigned nof_harq_pucch_sets, + unsigned nof_cell_pucch_f0_f1_res_sr, + unsigned nof_cell_pucch_f2_f3_f4_res_csi) { const unsigned tot_nof_cell_f0_f1_res = cell_res_list_and_params_validator(res_list, nof_ue_pucch_f0_f1_res_harq, - nof_ue_pucch_f2_f3_res_harq, + nof_ue_pucch_f2_f3_f4_res_harq, nof_harq_pucch_sets, nof_cell_pucch_f0_f1_res_sr, - nof_cell_pucch_f2_f3_res_csi); + nof_cell_pucch_f2_f3_f4_res_csi); if (tot_nof_cell_f0_f1_res == 0U) { return false; @@ -926,10 +1076,11 @@ bool srs_du::ue_pucch_config_builder(serving_cell_config& pucch_res_set_idx::set_1; const unsigned f0_f1_idx_offset = (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq.to_uint(); - const bool is_format_0 = res_list[f0_f1_idx_offset].format == pucch_format::FORMAT_0; - const unsigned f2_f3_idx_offset = - tot_nof_cell_f0_f1_res + (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_res_harq.to_uint(); - const bool is_format_2 = res_list[f2_f3_idx_offset].format == pucch_format::FORMAT_2; + const unsigned f2_f3_f4_idx_offset = + tot_nof_cell_f0_f1_res + (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_f4_res_harq.to_uint(); + // Check for the special case of F0 and F2. + const bool is_format_0 = res_list[f0_f1_idx_offset].format == pucch_format::FORMAT_0; + const bool is_format_2 = res_list[f2_f3_f4_idx_offset].format == pucch_format::FORMAT_2; // Add F0/F1 for HARQ. for (unsigned ue_f0_f1_cnt = 0; ue_f0_f1_cnt < nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f0_f1_cnt) { @@ -991,9 +1142,9 @@ bool srs_du::ue_pucch_config_builder(serving_cell_config& pucch_res_id_t{sr_cell_res.res_id.cell_res_id, ue_pucch_res_id_for_sr}); } - // Add F2/F3 for HARQ. - for (unsigned ue_f2_f3_cnt = 0; ue_f2_f3_cnt < nof_ue_pucch_f2_f3_res_harq.to_uint(); ++ue_f2_f3_cnt) { - const auto& cell_res = res_list[f2_f3_idx_offset + ue_f2_f3_cnt]; + // Add F2/F3/F4 for HARQ. + for (unsigned ue_f2_f3_f4_cnt = 0; ue_f2_f3_f4_cnt < nof_ue_pucch_f2_f3_f4_res_harq.to_uint(); ++ue_f2_f3_f4_cnt) { + const auto& cell_res = res_list[f2_f3_f4_idx_offset + ue_f2_f3_f4_cnt]; // Add PUCCH resource to pucch_res_list. pucch_cfg.pucch_res_list.emplace_back(pucch_resource{.res_id = {cell_res.res_id.cell_res_id, ue_pucch_res_id}, @@ -1012,7 +1163,7 @@ bool srs_du::ue_pucch_config_builder(serving_cell_config& if (serv_cell_cfg.csi_meas_cfg.has_value()) { // Add CSI resource. const unsigned csi_res_idx = - tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_f3_res_harq.to_uint() * nof_harq_pucch_sets + du_csi_res_idx; + tot_nof_cell_f0_f1_res + nof_ue_pucch_f2_f3_f4_res_harq.to_uint() * nof_harq_pucch_sets + du_csi_res_idx; const auto& csi_cell_res = res_list[csi_res_idx]; const unsigned ue_pucch_res_id_for_csi = ue_pucch_res_id; pucch_cfg.pucch_res_list.emplace_back( @@ -1021,7 +1172,16 @@ bool srs_du::ue_pucch_config_builder(serving_cell_config& .second_hop_prb = csi_cell_res.second_hop_prb, .format = csi_cell_res.format, .format_params = csi_cell_res.format_params}); - const auto& csi_params_cfg = std::get(csi_cell_res.format_params); + + unsigned char csi_nof_symbols; + unsigned char csi_starting_sym_idx; + std::visit( + [&csi_nof_symbols, &csi_starting_sym_idx](const auto& csi_params) { + csi_nof_symbols = csi_params.nof_symbols; + csi_starting_sym_idx = csi_params.starting_sym_idx; + }, + csi_cell_res.format_params); + std::get( serv_cell_cfg.csi_meas_cfg->csi_report_cfg_list[0].report_cfg_type) .pucch_csi_res_list.front() @@ -1046,10 +1206,8 @@ bool srs_du::ue_pucch_config_builder(serving_cell_config& auto& f0_harq_on_csi_resources = pucch_cfg.pucch_res_list[f0_f1_res_on_csi_prbs_syms_idx]; f0_harq_on_csi_resources.starting_prb = csi_cell_res.starting_prb; f0_harq_on_csi_resources.second_hop_prb = csi_cell_res.second_hop_prb; - f0_harq_on_csi_resources.format_params.emplace( - pucch_format_0_cfg{.initial_cyclic_shift = 0U, - .nof_symbols = csi_params_cfg.nof_symbols, - .starting_sym_idx = csi_params_cfg.starting_sym_idx}); + f0_harq_on_csi_resources.format_params.emplace(pucch_format_0_cfg{ + .initial_cyclic_shift = 0U, .nof_symbols = csi_nof_symbols, .starting_sym_idx = csi_starting_sym_idx}); } } diff --git a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h index 4d98017049..59f635d5b8 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h +++ b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.h @@ -18,51 +18,53 @@ namespace srsran::srs_du { /// The following values have to be set according to the \ref pucch_resource_manager capabilities. /// Maximum number of PUCCH F0/F1 resources per UE for HARQ-ACK reporting. constexpr unsigned max_ue_f0_f1_res_harq = 8; -/// Maximum number of PUCCH F2/F3 resources per UE for HARQ-ACK reporting. -constexpr unsigned max_ue_f2_f3_res_harq = 8; +/// Maximum number of PUCCH F2/F3/F4 resources per UE for HARQ-ACK reporting. +constexpr unsigned max_ue_f2_f3_f4_res_harq = 8; /// \brief Validates the user-defined parameters for building the PUCCH resource list. /// \param[in] nof_res_f0_f1 number of PUCCH F0/F1 resources to be generated. -/// \param[in] nof_res_f2_f3 number of PUCCH F2/F3 resources to be generated. +/// \param[in] nof_res_f2_f3_f4 number of PUCCH F2/F3/F4 resources to be generated. /// \param[in] f0_f1_params PUCCH F0/F1 resource parameters. -/// \param[in] f2_f3_params PUCCH F2 resource parameters. +/// \param[in] f2_f3_f4_params PUCCH F2/F3/F4 resource parameters. /// \param[in] bwp_size_rbs size of the BWP in RBs. /// \param[in] max_nof_symbols maximum number of symbols. /// \return In case an invalid parameter is detected, returns a string containing an error message. -error_type pucch_parameters_validator(unsigned nof_res_f0_f1, - unsigned nof_res_f2_f3, - std::variant f0_f1_params, - std::variant f2_f3_params, - unsigned bwp_size_rbs, - bounded_integer max_nof_symbols); +error_type +pucch_parameters_validator(unsigned nof_res_f0_f1, + unsigned nof_res_f2_f3_f4, + const std::variant& f0_f1_params, + const std::variant& f2_f3_f4_params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols); -/// \brief Generates the list of cell PUCCH resources (Format 0/1 and 2/3) given the number of requested resources. +/// \brief Generates the list of cell PUCCH resources (Format 0/1 and 2/3/4) given the number of requested resources. /// -/// PUCCH resources F0/F1 and F2/F3 are allocated on different RBs. The function attempts to spread the resources on +/// PUCCH resources F0/F1 and F2/F3/F4 are allocated on different RBs. The function attempts to spread the resources on /// both sides of the BWP. /// /// \param[in] nof_res_f0_f1 number of PUCCH F0/F1 resources to be generated. -/// \param[in] nof_res_f2_f3 number of PUCCH F2/F3 resources to be generated. +/// \param[in] nof_res_f2_f3_f4 number of PUCCH F2/F3/F4 resources to be generated. /// \param[in] f0_f1_params PUCCH F0/F1 resource parameters. -/// \param[in] f2_f3_params PUCCH F2/F3 resource parameters. +/// \param[in] f2_f3_f4_params PUCCH F2/F3/F4 resource parameters. /// \param[in] bwp_size_rbs Size of the BWP in RBs. /// \param[in] max_nof_symbols Maximum number of symbols. /// \return The list of PUCCH resources for a cell. The list has the PUCCH Format 0/1 resources in front of the list, -/// and the PUCCH Format 2/3 in the back of the list. +/// and the PUCCH Format 2/3/4 in the back of the list. /// \remark The function returns an empty list in the following cases: (i) If overall the RBs occupancy is larger than /// the BWP size. (ii) If F2 intra-slot frequency hopping is enabled with only 1 symbol. -std::vector generate_cell_pucch_res_list(unsigned nof_res_f0_f1, - unsigned nof_res_f2_f3, - std::variant f0_f1_params, - std::variant f2_f3_params, - unsigned bwp_size_rbs, - bounded_integer max_nof_symbols); +std::vector +generate_cell_pucch_res_list(unsigned nof_res_f0_f1, + unsigned nof_res_f2_f3_f4, + const std::variant& f0_f1_params, + const std::variant& f2_f3_f4_params, + unsigned bwp_size_rbs, + bounded_integer max_nof_symbols); /// \brief Generates the list of PUCCH resources for a given UE. /// -/// This function generates the list of PUCCH F0/F1 and F2/F3 resources for a given UE, including the resources for +/// This function generates the list of PUCCH F0/F1 and F2/F3/F4 resources for a given UE, including the resources for /// HARQ-ACK reporting, SR and CSI. It also updates the PUCCH resource sets accordingly, as well as the pointers to the -/// PUCCH F0/F1 resource for SR and to the PUCCH F2/F3 resource for CSI. This function overwrites the default \c +/// PUCCH F0/F1 resource for SR and to the PUCCH F2/F3/F4 resource for CSI. This function overwrites the default \c /// ServingCellConfig passed as a function input. /// /// The UE's PUCCH resource list composed of: @@ -70,31 +72,31 @@ std::vector generate_cell_pucch_res_list(unsigned /// \ref nof_harq_pucch_sets possible sets of PUCCH Format 0/1 cell resources. /// - 1 PUCCH Format 0/1 resource for SR chosen from \ref nof_cell_pucch_f0_f1_res_sr possible sets of PUCCH Format 0/1 /// cell resources. -/// - \ref nof_ue_pucch_f2_f3_res_harq PUCCH Format 2/3 resources for HARQ-ACK reporting, chosen from -/// \ref nof_harq_pucch_sets possible sets of PUCCH Format 2/3 cell resources. -/// - 1 PUCCH Format 2/3 resource for CSI chosen from \ref nof_cell_pucch_f2_f3_res_csi possible sets of PUCCH Format -/// 2/3 -/// cell resources. +/// - \ref nof_ue_pucch_f2_f3_f4_res_harq PUCCH Format 2/3/4 resources for HARQ-ACK reporting, chosen from +/// \ref nof_harq_pucch_sets possible sets of PUCCH Format 2/3/4 cell resources. +/// - 1 PUCCH Format 2/3/4 resource for CSI chosen from \ref nof_cell_pucch_f2_f3_f4_res_csi possible sets of PUCCH +/// Format +/// 2/3/4 cell resources. /// /// The returned UE PUCCH resource list \ref pucch_res_list contains the following resources, sorted as follows: -/// [ F0/F1-HARQ_0 ... F0/F1-HARQ_N-1 F0/F1-SR F2/F3-HARQ_0 ... F2/F3-HARQ_M-1 F2/F3-CSI ] -/// where N = nof_ue_pucch_f0_f1_res_harq and M = nof_ue_pucch_f2_f3_res_harq, +/// [ F0/F1-HARQ_0 ... F0/F1-HARQ_N-1 F0/F1-SR F2/F3-HARQ_0 ... F2/F3/F4-HARQ_M-1 F2/F3/F4-CSI ] +/// where N = nof_ue_pucch_f0_f1_res_harq and M = nof_ue_pucch_f2_f3_f4_res_harq, /// and with the following indices \ref res_id: /// - The first \ref nof_ue_pucch_f0_f1_res_harq are the PUCCH F0/F1 resources for HARQ-ACK and have index /// [ (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq, /// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f0_f1_res_harq + nof_ue_pucch_f0_f1_res_harq ). /// - The next resource in the list is the PUCCH F0/F1 resource for SR, which have index: /// nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + du_sr_res_idx % nof_cell_pucch_f0_f1_res_sr. -/// - The next \ref nof_ue_pucch_f2_f3_res_harq are the PUCCH F2/F3 resources for HARQ-ACK and have index +/// - The next \ref nof_ue_pucch_f2_f3_f4_res_harq are the PUCCH F2/F3/F4 resources for HARQ-ACK and have index /// [ nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + -/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_res_harq, +/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_f4_res_harq, /// nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + -/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_res_harq + -/// nof_ue_pucch_f2_f3_res_harq). -/// - The last resource in the list is the PUCCH F2/F3 resource for CSI, which has index: +/// (du_harq_set_idx % nof_harq_pucch_sets) * nof_ue_pucch_f2_f3_f4_res_harq + +/// nof_ue_pucch_f2_f3_f4_res_harq). +/// - The last resource in the list is the PUCCH F2/F3/F4 resource for CSI, which has index: //// nof_harq_pucch_sets * nof_ue_pucch_f0_f1_res_harq + nof_cell_pucch_f0_f1_res_sr + -/// nof_ue_pucch_f2_f3_res_harq * nof_harq_pucch_sets + du_csi_res_idx % -/// nof_cell_pucch_f2_f3_res_csi. +/// nof_ue_pucch_f2_f3_f4_res_harq * nof_harq_pucch_sets + du_csi_res_idx % +/// nof_cell_pucch_f2_f3_f4_res_csi. /// /// \param[in,out] serv_cell_cfg default \c ServingCellConfig that will be overwritten by this function. /// \param[in] res_list cell PUCCH resource list from which the function picks the UE PUCCH resources. @@ -104,21 +106,21 @@ std::vector generate_cell_pucch_res_list(unsigned /// \param[in] du_sr_res_idx defines which PUCCH resource for SR to be assigned to this UE among /// \ref nof_cell_pucch_f0_f1_res_sr possible ones. Values: {0, ..., nof_cell_pucch_f0_f1_res_sr-1}. /// \param[in] du_csi_res_idx defines which PUCCH resource for CSI to be assigned to this UE among -/// \ref nof_cell_pucch_f2_res_csi possible ones. Values: {0, ..., nof_cell_pucch_f2_res_csi-1}. +/// \ref nof_cell_pucch_f2_f3_f4_res_csi possible ones. Values: {0, ..., nof_cell_pucch_f2_f3_f4_res_csi-1}. /// \param[in] nof_ue_pucch_f0_f1_res_harq desired number of UE PUCCH F0/F1 resources (HARQ-ACK) in UE configuration. -/// \param[in] nof_ue_pucch_f2_f3_res_harq desired number of UE PUCCH F2/F3 resources (HARQ-ACK) in UE configuration. -/// \param[in] nof_harq_pucch_sets number of possible HARQ sets available in the cell. -/// \param[in] nof_cell_pucch_f0_f1_res_sr number of PUCCH F0/F1 resources for SR available in the cell. -/// \param[in] nof_cell_pucch_f2_f3_res_csi number of PUCCH F2/F3 resources for CSI available in the cell. -/// \return true if the building is successful, false otherwise. -bool ue_pucch_config_builder(serving_cell_config& serv_cell_cfg, - const std::vector& res_list, - unsigned du_harq_set_idx, - unsigned du_sr_res_idx, - unsigned du_csi_res_idx, - bounded_integer nof_ue_pucch_f0_f1_res_harq, - bounded_integer nof_ue_pucch_f2_f3_res_harq, - unsigned nof_harq_pucch_sets, - unsigned nof_cell_pucch_f0_f1_res_sr, - unsigned nof_cell_pucch_f2_f3_res_csi = 1); +/// \param[in] nof_ue_pucch_f2_f3_f4_res_harq desired number of UE PUCCH F2/F3/F4 resources (HARQ-ACK) in UE +/// configuration. \param[in] nof_harq_pucch_sets number of possible HARQ sets available in the cell. \param[in] +/// nof_cell_pucch_f0_f1_res_sr number of PUCCH F0/F1 resources for SR available in the cell. \param[in] +/// nof_cell_pucch_f2_f3_f4_res_csi number of PUCCH F2/F3/F4 resources for CSI available in the cell. \return true if +/// the building is successful, false otherwise. +bool ue_pucch_config_builder(serving_cell_config& serv_cell_cfg, + const std::vector& res_list, + unsigned du_harq_set_idx, + unsigned du_sr_res_idx, + unsigned du_csi_res_idx, + bounded_integer nof_ue_pucch_f0_f1_res_harq, + bounded_integer nof_ue_pucch_f2_f3_f4_res_harq, + unsigned nof_harq_pucch_sets, + unsigned nof_cell_pucch_f0_f1_res_sr, + unsigned nof_cell_pucch_f2_f3_f4_res_csi = 1); } // namespace srsran::srs_du diff --git a/lib/du/du_update_config_helpers.cpp b/lib/du/du_update_config_helpers.cpp index 6309f38bd2..eba45dc6a5 100644 --- a/lib/du/du_update_config_helpers.cpp +++ b/lib/du/du_update_config_helpers.cpp @@ -28,14 +28,6 @@ static prb_interval find_pucch_inner_prbs(const pucch_resource& res, unsigned bw // NOTE: for odd bwp_size and the for central PRB, both is_on_bwp_right_side() and is_on_bwp_left_side() are false. auto is_on_bwp_right_side = [bwp_size](unsigned prb) { return prb >= bwp_size - bwp_size / 2; }; - srsran_assert((res.format == srsran::pucch_format::FORMAT_0 and - std::holds_alternative(res.format_params)) or - (res.format == srsran::pucch_format::FORMAT_1 and - std::holds_alternative(res.format_params)) or - (res.format == srsran::pucch_format::FORMAT_2 or - std::holds_alternative(res.format_params)), - "Only PUCCH Format 0, 1 and 2 currently supported."); - constexpr unsigned nof_prbs_f0_f1 = 1U; const unsigned nof_prbs = res.format == srsran::pucch_format::FORMAT_0 or res.format == srsran::pucch_format::FORMAT_1 ? nof_prbs_f0_f1 @@ -68,10 +60,10 @@ srsran::config_helpers::find_largest_prb_interval_without_pucch(const srs_du::pu const std::vector& res_list = srs_du::generate_cell_pucch_res_list( user_params.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_sr_resources, - user_params.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + + user_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_csi_resources, user_params.f0_or_f1_params, - user_params.f2_or_f3_params, + user_params.f2_or_f3_or_f4_params, bwp_size, user_params.max_nof_symbols); srsran_assert(not res_list.empty(), "The PUCCH resource list cannot be empty"); diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index 4f7597e0f5..e7f0258b4a 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -153,7 +153,7 @@ static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_common_parameters(mac_pdu.format, f4.slot_repetition, f4.pi_2_bpsk); // Scrambling. - builder.set_scrambling_parameters(f4.n_id_scambling); + builder.set_scrambling_parameters(f4.n_id_scrambling); // DM-RS. builder.set_dmrs_parameters(f4.additional_dmrs, f4.n_id_0_scrambling, f4.m_0_cyclic_shift); diff --git a/lib/ran/pucch/pucch_info.cpp b/lib/ran/pucch/pucch_info.cpp index 8dfad1ead0..f7e3476760 100644 --- a/lib/ran/pucch/pucch_info.cpp +++ b/lib/ran/pucch/pucch_info.cpp @@ -182,3 +182,49 @@ unsigned srsran::get_pucch_format3_max_payload(unsigned max_nof_prbs, const unsigned nof_crc_bits = get_uci_nof_crc_bits(estimated_pucch_f3_capacity - long_crc_length, e_uci); return std::min(estimated_pucch_f3_capacity - long_crc_length, estimated_pucch_f3_capacity - nof_crc_bits); } + +unsigned srsran::get_pucch_format4_max_payload(unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk, + pucch_f4_occ_len occ_length) +{ + const unsigned nof_dmrs_symbols = + get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); + const unsigned mod_order = pi2_bpsk ? 1 : 2; + const float spreading_factor = occ_length == pucch_f4_occ_len::n2 ? 2.0f : 4.0f; + + // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213; the + // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and + // max_code_rate. + // NOTE: The maximum number of bits that can be carried by a PUCCH Format 4 resource is 115, which is obtained for 14 + // symbols, a spreading factor of 2, QPSK, no additional DM-RS and 0.8 max code rate. + const unsigned estimated_pucch_f4_capacity = static_cast(std::floor( + static_cast((nof_symbols - nof_dmrs_symbols) * NRE * mod_order) * max_code_rate / spreading_factor)); + + // Get the payload depending on the estimated PUCCH F4 capacity (which we define as the nof bits that the PUCCH F4 can + // carry). + // NOTE: Given the max capacity of PUCCH, which is 144 bits (see above), the UCI in PUCCH F4 can have max 1 codeword + // (as per Section 6.3.1.2.1, TS 38.212); this implies only 6-bit and 11-bit can be added as CRC to the PUCCH F4 + // payload. + + // Case: no CRC for payload <= 11 bits. + constexpr unsigned min_capacity_for_more_than_11_bit_payload = 18U; + constexpr unsigned max_payload_without_crc_addition = 11U; + if (estimated_pucch_f4_capacity < min_capacity_for_more_than_11_bit_payload) { + return std::min(estimated_pucch_f4_capacity, max_payload_without_crc_addition); + } + + // Case: 6-bit CRC for 12 <= payload <= 19 bits. + constexpr unsigned min_capacity_for_more_than_19_bit_payload = 31U; + constexpr unsigned max_payload_with_6_bit_crc_addition = 19U; + constexpr unsigned short_crc_length = 6U; + if (estimated_pucch_f4_capacity < min_capacity_for_more_than_19_bit_payload) { + return std::min(estimated_pucch_f4_capacity - short_crc_length, max_payload_with_6_bit_crc_addition); + } + + // Case: 11-bit CRC for payload >= 20. + const unsigned long_crc_length = 11U; + return estimated_pucch_f4_capacity - long_crc_length; +} diff --git a/lib/scheduler/config/sched_cell_config_helpers.cpp b/lib/scheduler/config/sched_cell_config_helpers.cpp index 55f638cc06..08cf8595f0 100644 --- a/lib/scheduler/config/sched_cell_config_helpers.cpp +++ b/lib/scheduler/config/sched_cell_config_helpers.cpp @@ -23,10 +23,10 @@ srsran::config_helpers::build_pucch_guardbands_list(const srs_du::pucch_builder_ std::vector res_list = srs_du::generate_cell_pucch_res_list( user_params.nof_ue_pucch_f0_or_f1_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_sr_resources, - user_params.nof_ue_pucch_f2_or_f3_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + + user_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() * user_params.nof_cell_harq_pucch_res_sets + user_params.nof_csi_resources, user_params.f0_or_f1_params, - user_params.f2_or_f3_params, + user_params.f2_or_f3_or_f4_params, bwp_size, user_params.max_nof_symbols); @@ -39,11 +39,6 @@ srsran::config_helpers::build_pucch_guardbands_list(const srs_du::pucch_builder_ }; for (const auto& pucch_res : res_list) { - srsran_assert(std::holds_alternative(pucch_res.format_params) or - std::holds_alternative(pucch_res.format_params) or - std::holds_alternative(pucch_res.format_params), - "Only PUCCH format 0, 1 and 2 and 3 are currently supported"); - unsigned starting_sym = 0; unsigned nof_symbols = 0; std::visit( @@ -53,7 +48,7 @@ srsran::config_helpers::build_pucch_guardbands_list(const srs_du::pucch_builder_ }, pucch_res.format_params); - // For PUCCH format 1, the resource has 1 PRB only. + // For PUCCH Formats 0/1/4, the resource has 1 PRB only. const unsigned nof_prbs = std::holds_alternative(pucch_res.format_params) ? std::get(pucch_res.format_params).nof_prbs : 1U; diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 3a3a14e79c..7ab33a1945 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -599,11 +599,11 @@ class du_high_bench dependencies.sched_ue_metrics_notifier = &metrics_handler; // Increase nof. PUCCH resources to accommodate more UEs. - cfg.ran.cells[0].pucch_cfg.nof_sr_resources = 30; - cfg.ran.cells[0].pucch_cfg.nof_csi_resources = 30; - cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = 8; - cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 8; - cfg.ran.cells[0].pucch_cfg.nof_cell_harq_pucch_res_sets = 4; + cfg.ran.cells[0].pucch_cfg.nof_sr_resources = 30; + cfg.ran.cells[0].pucch_cfg.nof_csi_resources = 30; + cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq = 8; + cfg.ran.cells[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 8; + cfg.ran.cells[0].pucch_cfg.nof_cell_harq_pucch_res_sets = 4; auto& f1_params = cfg.ran.cells[0].pucch_cfg.f0_or_f1_params.emplace(); f1_params.nof_cyc_shifts = nof_cyclic_shifts::six; f1_params.occ_supported = true; diff --git a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp index 31ac866fbb..ed4935d768 100644 --- a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp @@ -80,12 +80,12 @@ class multi_ue_sched_simulator next_sl_tx(builder_params.scs_common, 0) { du_cell_cfgs = {config_helpers::make_default_du_cell_config(builder_params)}; - std::get(du_cell_cfgs[0].pucch_cfg.f2_or_f3_params).max_code_rate = + std::get(du_cell_cfgs[0].pucch_cfg.f2_or_f3_or_f4_params).max_code_rate = max_pucch_code_rate::dot_35; - du_cell_cfgs[0].pucch_cfg.nof_csi_resources = 4; - du_cell_cfgs[0].pucch_cfg.nof_sr_resources = 2; - du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 3; - du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq = 6; + du_cell_cfgs[0].pucch_cfg.nof_csi_resources = 4; + du_cell_cfgs[0].pucch_cfg.nof_sr_resources = 2; + du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = 3; + du_cell_cfgs[0].pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq = 6; sched_cell_configuration_request_message cell_cfg_msg = sched_config_helper::make_default_sched_cell_configuration_request(builder_params); diff --git a/tests/integrationtests/du_high/du_high_many_ues_test.cpp b/tests/integrationtests/du_high/du_high_many_ues_test.cpp index 552e6acb62..95b9be6a59 100644 --- a/tests/integrationtests/du_high/du_high_many_ues_test.cpp +++ b/tests/integrationtests/du_high/du_high_many_ues_test.cpp @@ -31,9 +31,9 @@ static du_high_env_sim_params create_custom_params() params.builder_params.value().tdd_ul_dl_cfg_common = tdd_ul_dl_config_common{subcarrier_spacing::kHz30, {10, 8, 5, 1, 4}}; params.pucch_cfg.emplace(); - params.pucch_cfg->nof_ue_pucch_f0_or_f1_res_harq = 8; - params.pucch_cfg->nof_ue_pucch_f2_or_f3_res_harq = 8; - params.pucch_cfg->nof_sr_resources = 1; + params.pucch_cfg->nof_ue_pucch_f0_or_f1_res_harq = 8; + params.pucch_cfg->nof_ue_pucch_f2_or_f3_or_f4_res_harq = 8; + params.pucch_cfg->nof_sr_resources = 1; // Set the PRACH frequency start to avoid PRACH collisions with the PUCCH on the upper RBs of the BWP (this would // trigger an error and abort the test). // NOTE: this results in the PRACH overlapping with the PUCCH resources on the lower RBs of the BWP, but it doesn't diff --git a/tests/test_doubles/scheduler/scheduler_config_helper.cpp b/tests/test_doubles/scheduler/scheduler_config_helper.cpp index f5b8409343..0b6deba8d9 100644 --- a/tests/test_doubles/scheduler/scheduler_config_helper.cpp +++ b/tests/test_doubles/scheduler/scheduler_config_helper.cpp @@ -44,10 +44,10 @@ sched_cell_configuration_request_message srsran::sched_config_helper::make_defau sched_req.searchspace0 = params.search_space0_index; sched_req.sib1_payload_size = 101; // Random size. - srs_du::pucch_builder_params default_pucch_builder_params = srs_du::du_cell_config{}.pucch_cfg; - default_pucch_builder_params.nof_ue_pucch_f0_or_f1_res_harq = 3; - default_pucch_builder_params.nof_ue_pucch_f2_or_f3_res_harq = 6; - default_pucch_builder_params.nof_sr_resources = 2; + srs_du::pucch_builder_params default_pucch_builder_params = srs_du::du_cell_config{}.pucch_cfg; + default_pucch_builder_params.nof_ue_pucch_f0_or_f1_res_harq = 3; + default_pucch_builder_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq = 6; + default_pucch_builder_params.nof_sr_resources = 2; sched_req.pucch_guardbands = config_helpers::build_pucch_guardbands_list( default_pucch_builder_params, sched_req.ul_cfg_common.init_ul_bwp.generic_params.crbs.length()); diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 67e8a6806e..505ab82888 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -118,7 +118,7 @@ class du_ran_resource_manager_tester_base const unsigned nof_csi_f2_res_per_ue = 1U; bool pucch_checker = pucch_cfg.pucch_res_list.size() == du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + - du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint() + + du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() + nof_sr_f1_res_per_ue + nof_csi_f2_res_per_ue; // Check whether the SR resource point to the correct one (we give a range where the SR resource is located), each @@ -131,10 +131,10 @@ class du_ran_resource_manager_tester_base // We always put the CSI PUCCH resource is always at the end of the list. if (csi_pucch_res.has_value()) { - pucch_checker = - pucch_checker and csi_pucch_res.value() >= du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + - du_cfg.pucch_cfg.nof_sr_resources + - du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint(); + pucch_checker = pucch_checker and + csi_pucch_res.value() >= du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + + du_cfg.pucch_cfg.nof_sr_resources + + du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint(); } return pucch_checker; @@ -323,16 +323,16 @@ using namespace du_test_multiple_pucch_cfg; static du_cell_config make_custom_du_cell_config(const pucch_cfg_builder_params& pucch_params_) { - du_cell_config du_cfg = config_helpers::make_default_du_cell_config(); - auto& pucch_params = du_cfg.pucch_cfg; - pucch_params.nof_ue_pucch_f0_or_f1_res_harq = pucch_params_.nof_res_f1_harq; - pucch_params.nof_ue_pucch_f2_or_f3_res_harq = pucch_params_.nof_res_f2_harq; - pucch_params.nof_sr_resources = pucch_params_.nof_res_sr; - pucch_params.nof_csi_resources = pucch_params_.nof_res_csi; - pucch_params.nof_cell_harq_pucch_res_sets = pucch_params_.nof_harq_cfg; - auto& f1_params = std::get(pucch_params.f0_or_f1_params); - f1_params.nof_cyc_shifts = nof_cyclic_shifts::six; - f1_params.occ_supported = true; + du_cell_config du_cfg = config_helpers::make_default_du_cell_config(); + auto& pucch_params = du_cfg.pucch_cfg; + pucch_params.nof_ue_pucch_f0_or_f1_res_harq = pucch_params_.nof_res_f1_harq; + pucch_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq = pucch_params_.nof_res_f2_harq; + pucch_params.nof_sr_resources = pucch_params_.nof_res_sr; + pucch_params.nof_csi_resources = pucch_params_.nof_res_csi; + pucch_params.nof_cell_harq_pucch_res_sets = pucch_params_.nof_harq_cfg; + auto& f1_params = std::get(pucch_params.f0_or_f1_params); + f1_params.nof_cyc_shifts = nof_cyclic_shifts::six; + f1_params.occ_supported = true; return du_cfg; } @@ -366,7 +366,7 @@ class du_ran_res_mng_multiple_cfg_tester : public du_ran_resource_manager_tester const auto& pucch_res_set = pucch_cfg.pucch_res_set[pucch_res_set_id].pucch_res_id_list; const unsigned expected_pucch_res_set_size = format == pucch_format::FORMAT_1 ? cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() - : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint(); + : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint(); if (expected_pucch_res_set_size != pucch_res_set.size()) { return {}; } @@ -385,9 +385,9 @@ class du_ran_res_mng_multiple_cfg_tester : public du_ran_resource_manager_tester // for HARQ. interval get_expected_pucch_res_id_interval(unsigned ue_idx, pucch_format format) const { - const unsigned expected_nof_pucch_res = format == pucch_format::FORMAT_1 - ? cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() - : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_or_f3_res_harq.to_uint(); + const unsigned expected_nof_pucch_res = + format == pucch_format::FORMAT_1 ? cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + : cell_cfg_list[0].pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint(); if (expected_nof_pucch_res == 0) { return interval{}; @@ -796,16 +796,16 @@ INSTANTIATE_TEST_SUITE_P( // SRS resources. static du_cell_config make_custom_pucch_srs_du_cell_config(bool pucch_has_more_res_than_srs) { - du_cell_config du_cfg = config_helpers::make_default_du_cell_config(); - auto& pucch_params = du_cfg.pucch_cfg; - pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6U; - pucch_params.nof_ue_pucch_f2_or_f3_res_harq = 6U; - pucch_params.nof_sr_resources = pucch_has_more_res_than_srs ? 10U : 1U; - pucch_params.nof_csi_resources = pucch_has_more_res_than_srs ? 10U : 1U; - pucch_params.nof_cell_harq_pucch_res_sets = 1U; - auto& f1_params = std::get(pucch_params.f0_or_f1_params); - f1_params.nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift; - f1_params.occ_supported = false; + du_cell_config du_cfg = config_helpers::make_default_du_cell_config(); + auto& pucch_params = du_cfg.pucch_cfg; + pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6U; + pucch_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq = 6U; + pucch_params.nof_sr_resources = pucch_has_more_res_than_srs ? 10U : 1U; + pucch_params.nof_csi_resources = pucch_has_more_res_than_srs ? 10U : 1U; + pucch_params.nof_cell_harq_pucch_res_sets = 1U; + auto& f1_params = std::get(pucch_params.f0_or_f1_params); + f1_params.nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift; + f1_params.occ_supported = false; auto& tdd_cfg = du_cfg.tdd_ul_dl_cfg_common.emplace(); tdd_cfg.pattern1.dl_ul_tx_period_nof_slots = 10; diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index 35ab10fb58..d7eb206959 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -25,6 +25,7 @@ struct pucch_gen_params { unsigned nof_res_f1; unsigned nof_res_f2; unsigned nof_res_f3; + unsigned nof_res_f4; bounded_integer f0_nof_symbols{2}; bool f0_intraslot_freq_hopping{false}; nof_cyclic_shifts nof_cyc_shifts{nof_cyclic_shifts::no_cyclic_shift}; @@ -40,6 +41,11 @@ struct pucch_gen_params { bool f3_intraslot_freq_hopping{false}; bool f3_additional_dmrs{false}; bool f3_pi2_bpsk{false}; + bounded_integer f4_nof_symbols{4}; + bool f4_intraslot_freq_hopping{false}; + bool f4_additional_dmrs{false}; + bool f4_pi2_bpsk{false}; + pucch_f4_occ_len f4_occ_length{pucch_f4_occ_len::n2}; }; // Dummy function overload of template void testing::internal::PrintTo(const T& value, ::std::ostream* os). @@ -60,9 +66,9 @@ std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) params.f1_nof_symbols, params.f1_intraslot_freq_hopping); } - std::string f2_f3_str; + std::string f2_f3_f4_str; if (params.nof_res_f2 != 0) { - f2_f3_str = fmt::format( + f2_f3_f4_str = fmt::format( "F2: nof_res={} nof_symbols={} max_nof_rbs={} {} max_code_rate={} freq_hop={}", params.nof_res_f2, params.f2_nof_symbols, @@ -70,9 +76,9 @@ std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) params.max_payload_bits.has_value() ? fmt::format("max_payload_bits={}", params.max_payload_bits.value()) : "", to_max_code_rate_float(params.max_code_rate), params.f2_intraslot_freq_hopping); - } else { - f2_f3_str = fmt::format( - "F3: nof_res={} nof_symbols={} max_nof_rbs={} max_payload_bits={} max_code_rate={} " + } else if (params.nof_res_f3 != 0) { + f2_f3_f4_str = fmt::format( + "F3: nof_res={} nof_symbols={} max_nof_rbs={} {} max_code_rate={} " "freq_hop={} add_dmrs={} pi2_bpsk={}", params.nof_res_f3, params.f3_nof_symbols, @@ -82,8 +88,19 @@ std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) params.f3_intraslot_freq_hopping, params.f3_additional_dmrs, params.f3_pi2_bpsk); + } else { + f2_f3_f4_str = fmt::format( + "F4: nof_res={} nof_symbols={} {} max_code_rate={} freq_hop={} add_dmrs={} pi2_bpsk={} occ_len={}", + params.nof_res_f4, + params.f4_nof_symbols, + params.max_payload_bits.has_value() ? fmt::format("max_payload_bits={}", params.max_payload_bits.value()) : "", + to_max_code_rate_float(params.max_code_rate), + params.f4_intraslot_freq_hopping, + params.f4_additional_dmrs, + params.f4_pi2_bpsk, + params.f4_occ_length == pucch_f4_occ_len::n2 ? 2 : 4); } - fmt::print(os, "{} {}", f0_f1_str, f2_f3_str); + fmt::print(os, "{} {}", f0_f1_str, f2_f3_f4_str); return os; } @@ -93,6 +110,7 @@ struct pucch_cfg_builder_params { unsigned nof_res_f1_harq = 3; unsigned nof_res_f2_harq = 6; unsigned nof_res_f3_harq = 6; + unsigned nof_res_f4_harq = 6; unsigned nof_harq_cfg = 1; unsigned nof_res_sr = 2; unsigned nof_res_csi = 1; @@ -101,11 +119,12 @@ struct pucch_cfg_builder_params { std::ostream& operator<<(std::ostream& os, const pucch_cfg_builder_params& params) { fmt::print(os, - "f0_harq={} f1_harq={} f2_harq={} f3_harq={} nof_harq_cfg={} nof_sr={} nof_csi={}", + "f0_harq={} f1_harq={} f2_harq={} f3_harq={} f4_harq={} nof_harq_cfg={} nof_sr={} nof_csi={}", params.nof_res_f0_harq, params.nof_res_f1_harq, params.nof_res_f2_harq, params.nof_res_f3_harq, + params.nof_res_f4_harq, params.nof_harq_cfg, params.nof_res_sr, params.nof_res_csi); @@ -207,8 +226,7 @@ class pucch_grid grid_elem.allocated_occ_cs_list[occ_cs_idx] = true; } } - - } else if (res.format == srsran::pucch_format::FORMAT_2) { + } else if (res.format == pucch_format::FORMAT_2) { srsran_assert(std::holds_alternative(res.format_params), "Expected PUCCH Format 2"); const auto& res_f2 = std::get(res.format_params); @@ -244,6 +262,75 @@ class pucch_grid } } } + } else if (res.format == pucch_format::FORMAT_3) { + srsran_assert(std::holds_alternative(res.format_params), "Expected PUCCH Format 3"); + const auto& res_f3 = std::get(res.format_params); + + if (res.second_hop_prb.has_value()) { + // First hop. + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f3.nof_prbs; ++rb_idx) { + for (unsigned sym_idx = res_f3.starting_sym_idx; sym_idx < res_f3.starting_sym_idx + res_f3.nof_symbols / 2; + ++sym_idx) { + auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; + grid_elem.element_used = true; + grid_elem.format = pucch_format::FORMAT_3; + } + } + // Second hop. + for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + res_f3.nof_prbs; + ++rb_idx) { + for (unsigned sym_idx = res_f3.starting_sym_idx + res_f3.nof_symbols / 2; + sym_idx < res_f3.starting_sym_idx + res_f3.nof_symbols; + ++sym_idx) { + auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; + grid_elem.element_used = true; + grid_elem.format = pucch_format::FORMAT_3; + } + } + } else { + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f3.nof_prbs; ++rb_idx) { + for (unsigned sym_idx = res_f3.starting_sym_idx; sym_idx < res_f3.starting_sym_idx + res_f3.nof_symbols; + ++sym_idx) { + auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; + grid_elem.element_used = true; + grid_elem.format = pucch_format::FORMAT_3; + } + } + } + } else if (res.format == pucch_format::FORMAT_4) { + srsran_assert(std::holds_alternative(res.format_params), "Expected PUCCH Format 4"); + const auto& res_f4 = std::get(res.format_params); + + if (res.second_hop_prb.has_value()) { + // First hop. + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + ++sym_idx) { + auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; + grid_elem.element_used = true; + grid_elem.format = pucch_format::FORMAT_4; + } + } + // Second hop. + for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + 1; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + ++sym_idx) { + auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; + grid_elem.element_used = true; + grid_elem.format = pucch_format::FORMAT_4; + } + } + } else { + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + ++sym_idx) { + auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; + grid_elem.element_used = true; + grid_elem.format = pucch_format::FORMAT_4; + } + } + } } } @@ -385,7 +472,70 @@ class pucch_grid } } } + } else if (res.format == pucch_format::FORMAT_4) { + srsran_assert(std::holds_alternative(res.format_params), "Expected PUCCH Format 4"); + const auto& res_f4 = std::get(res.format_params); + // Intra-slot frequency hopping. + if (res.second_hop_prb.has_value()) { + // First hop. + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + ++sym_idx) { + const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; + if (grid_unit.element_used) { + if (grid_unit.format != pucch_format::FORMAT_4) { + return true; + } + const unsigned occ_index = static_cast(res_f4.occ_index); + srsran_assert(occ_index < (res_f4.occ_length == pucch_f4_occ_len::n2 ? 2 : 4), + " OCC index exceeds OCC length"); + if (grid_unit.allocated_occ_cs_list[occ_index]) { + return true; + } + } + } + } + // Second hop. + for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + 1; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + ++sym_idx) { + const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; + if (grid_unit.element_used) { + if (grid_unit.format != pucch_format::FORMAT_4) { + return true; + } + const unsigned occ_index = static_cast(res_f4.occ_index); + srsran_assert(occ_index < (res_f4.occ_length == pucch_f4_occ_len::n2 ? 2 : 4), + " OCC index exceeds OCC length"); + if (grid_unit.allocated_occ_cs_list[occ_index]) { + return true; + } + } + } + } + } + // No intra-slot frequency hopping. + else { + for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + ++sym_idx) { + const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; + if (grid_unit.element_used) { + if (grid_unit.format != pucch_format::FORMAT_4) { + return true; + } + const unsigned occ_index = static_cast(res_f4.occ_index); + srsran_assert(occ_index < (res_f4.occ_length == pucch_f4_occ_len::n2 ? 2 : 4), + " OCC index exceeds OCC length"); + if (grid_unit.allocated_occ_cs_list[occ_index]) { + return true; + } + } + } + } + } } else { return true; } @@ -440,8 +590,11 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) const unsigned nof_res_f1 = GetParam().nof_res_f1; const unsigned nof_res_f2 = GetParam().nof_res_f2; const unsigned nof_res_f3 = GetParam().nof_res_f3; + const unsigned nof_res_f4 = GetParam().nof_res_f4; ASSERT_FALSE(nof_res_f0 != 0 and nof_res_f1 != 0) << "PUCCH Format 0 and Format 1 resources cannot be used together"; + ASSERT_FALSE((nof_res_f2 != 0) + (nof_res_f3 != 0) + (nof_res_f4 != 0) > 1) + << "PUCCH Format 2/3/4 resources cannot be used together"; pucch_f0_params params_f0{.nof_symbols = GetParam().f0_nof_symbols, .intraslot_freq_hopping = GetParam().f0_intraslot_freq_hopping}; @@ -465,6 +618,12 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) .additional_dmrs = GetParam().f3_additional_dmrs, .pi2_bpsk = GetParam().f3_pi2_bpsk}; + pucch_f4_params params_f4{.nof_symbols = GetParam().f4_nof_symbols, + .max_code_rate = GetParam().max_code_rate, + .intraslot_freq_hopping = GetParam().f4_intraslot_freq_hopping, + .additional_dmrs = GetParam().f4_additional_dmrs, + .pi2_bpsk = GetParam().f4_pi2_bpsk}; + std::variant f0_f1_params; unsigned nof_res_f0_f1; if (nof_res_f0 != 0) { @@ -475,21 +634,24 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) nof_res_f0_f1 = nof_res_f1; } - std::variant f2_f3_params; - unsigned nof_res_f2_f3; + std::variant f2_f3_f4_params; + unsigned nof_res_f2_f3_f4; if (nof_res_f2 != 0) { - f2_f3_params.emplace(params_f2); - nof_res_f2_f3 = nof_res_f2; + f2_f3_f4_params.emplace(params_f2); + nof_res_f2_f3_f4 = nof_res_f2; + } else if (nof_res_f3 != 0) { + f2_f3_f4_params.emplace(params_f3); + nof_res_f2_f3_f4 = nof_res_f3; } else { - f2_f3_params.emplace(params_f3); - nof_res_f2_f3 = nof_res_f3; + f2_f3_f4_params.emplace(params_f4); + nof_res_f2_f3_f4 = nof_res_f4; } std::vector res_list = generate_cell_pucch_res_list( - nof_res_f0_f1, nof_res_f2_f3, f0_f1_params, f2_f3_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + nof_res_f0_f1, nof_res_f2_f3_f4, f0_f1_params, f2_f3_f4_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); ASSERT_TRUE(res_list.size() > 0); - ASSERT_EQ(nof_res_f0_f1 + nof_res_f2_f3, res_list.size()); + ASSERT_EQ(nof_res_f0_f1 + nof_res_f2_f3_f4, res_list.size()); for (const auto& pucch_res : res_list) { ASSERT_FALSE(grid.verify_collision(pucch_res)); @@ -499,237 +661,333 @@ TEST_P(test_pucch_res_generator_params, test_pucch_res_given_number) INSTANTIATE_TEST_SUITE_P(test_res_generation_given_number, test_pucch_res_generator_params, - ::testing::Values(pucch_gen_params{.nof_res_f1 = 15, - .nof_res_f2 = 10, - .nof_cyc_shifts = nof_cyclic_shifts::twelve, - .occ_supported = false, - .f1_nof_symbols = 7, - .f1_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_25, - .f2_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f1 = 39, - .nof_res_f2 = 19, - .nof_cyc_shifts = nof_cyclic_shifts::twelve, - .occ_supported = false, - .f1_nof_symbols = 7, - .f1_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 39, - .nof_res_f2 = 19, - .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, - .occ_supported = true, - .f1_nof_symbols = 7, - .f1_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_25, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 39, - .nof_res_f2 = 19, - .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, - .occ_supported = true, - .f1_nof_symbols = 11, - .f1_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 137, - .nof_res_f2 = 25, - .nof_cyc_shifts = nof_cyclic_shifts::twelve, - .occ_supported = true, - .f1_nof_symbols = 14, - .f1_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f1 = 36, - .nof_res_f2 = 27, - .nof_cyc_shifts = nof_cyclic_shifts::three, - .occ_supported = true, - .f1_nof_symbols = 9, - .f1_intraslot_freq_hopping = false, - .f2_nof_symbols = 2, - .max_nof_rbs = 7, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 34, - .nof_res_f2 = 10, - .nof_cyc_shifts = nof_cyclic_shifts::two, - .occ_supported = false, - .f1_nof_symbols = 9, - .f1_intraslot_freq_hopping = false, - .f2_nof_symbols = 1, - .max_nof_rbs = 7, - .max_payload_bits = 11, - .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f2_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f1 = 15, - .nof_res_f2 = 10, - .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, - .occ_supported = false, - .f1_nof_symbols = 9, - .f1_intraslot_freq_hopping = false, - .f2_nof_symbols = 2, - .max_nof_rbs = 7, - .max_payload_bits = 11, - .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f0 = 15, - .nof_res_f2 = 10, - .f0_nof_symbols = 2, - .f0_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_25, - .f2_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f0 = 39, - .nof_res_f2 = 19, - .f0_nof_symbols = 2, - .f0_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f0 = 39, - .nof_res_f2 = 19, - .f0_nof_symbols = 1, - .f0_intraslot_freq_hopping = false, - .f2_nof_symbols = 2, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f0 = 9, - .nof_res_f2 = 19, - .f0_nof_symbols = 2, - .f0_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f0 = 39, - .nof_res_f2 = 25, - .f0_nof_symbols = 2, - .f0_intraslot_freq_hopping = true, - .f2_nof_symbols = 2, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f0 = 36, - .nof_res_f2 = 27, - .f0_nof_symbols = 1, - .f0_intraslot_freq_hopping = false, - .f2_nof_symbols = 2, - .max_nof_rbs = 7, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f2_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 34, - .nof_res_f2 = 10, - .f0_nof_symbols = 1, - .f0_intraslot_freq_hopping = false, - .f2_nof_symbols = 1, - .max_nof_rbs = 7, - .max_payload_bits = 11, - .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f2_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f0 = 15, - .nof_res_f2 = 10, - .f0_nof_symbols = 1, - .f0_intraslot_freq_hopping = false, - .f2_nof_symbols = 2, - .max_nof_rbs = 7, - .max_payload_bits = 11, - .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f2_intraslot_freq_hopping = true}, - // Format 3 test cases. - pucch_gen_params{.nof_res_f1 = 15, - .nof_res_f3 = 10, - .nof_cyc_shifts = nof_cyclic_shifts::twelve, - .occ_supported = false, - .f1_nof_symbols = 7, - .f1_intraslot_freq_hopping = true, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_25, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f1 = 39, - .nof_res_f3 = 19, - .nof_cyc_shifts = nof_cyclic_shifts::twelve, - .occ_supported = false, - .f1_nof_symbols = 7, - .f1_intraslot_freq_hopping = true, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 39, - .nof_res_f3 = 19, - .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, - .occ_supported = true, - .f1_nof_symbols = 7, - .f1_intraslot_freq_hopping = true, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_25, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 39, - .nof_res_f3 = 19, - .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, - .occ_supported = true, - .f1_nof_symbols = 11, - .f1_intraslot_freq_hopping = true, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 137, - .nof_res_f3 = 25, - .nof_cyc_shifts = nof_cyclic_shifts::twelve, - .occ_supported = true, - .f1_nof_symbols = 14, - .f1_intraslot_freq_hopping = true, - .max_nof_rbs = 1, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f1 = 36, - .nof_res_f3 = 27, - .nof_cyc_shifts = nof_cyclic_shifts::three, - .occ_supported = true, - .f1_nof_symbols = 9, - .f1_intraslot_freq_hopping = false, - .max_nof_rbs = 2, - .max_code_rate = srsran::max_pucch_code_rate::dot_15, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = true}, - pucch_gen_params{.nof_res_f1 = 34, - .nof_res_f3 = 10, - .nof_cyc_shifts = nof_cyclic_shifts::two, - .occ_supported = false, - .f1_nof_symbols = 9, - .f1_intraslot_freq_hopping = false, - .max_nof_rbs = 7, - .max_payload_bits = 11, - .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = false}, - pucch_gen_params{.nof_res_f1 = 15, - .nof_res_f3 = 10, - .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, - .occ_supported = false, - .f1_nof_symbols = 9, - .f1_intraslot_freq_hopping = false, - .max_nof_rbs = 7, - .max_payload_bits = 11, - .max_code_rate = srsran::max_pucch_code_rate::dot_08, - .f3_nof_symbols = 4, - .f3_intraslot_freq_hopping = true})); + ::testing::Values( + // F1 and F2 test cases. + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f2 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f2_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f2 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f2 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f2 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 11, + .f1_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 137, + .nof_res_f2 = 25, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = true, + .f1_nof_symbols = 14, + .f1_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 36, + .nof_res_f2 = 27, + .nof_cyc_shifts = nof_cyclic_shifts::three, + .occ_supported = true, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .f2_nof_symbols = 2, + .max_nof_rbs = 7, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 34, + .nof_res_f2 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::two, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .f2_nof_symbols = 1, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f2_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f2 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .f2_nof_symbols = 2, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 34, + .nof_res_f2 = 10, + .f0_nof_symbols = 1, + .f0_intraslot_freq_hopping = false, + .f2_nof_symbols = 1, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f2_intraslot_freq_hopping = false}, + // F0 and F2 test cases. + pucch_gen_params{.nof_res_f0 = 15, + .nof_res_f2 = 10, + .f0_nof_symbols = 2, + .f0_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f2_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f0 = 39, + .nof_res_f2 = 19, + .f0_nof_symbols = 2, + .f0_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f0 = 39, + .nof_res_f2 = 19, + .f0_nof_symbols = 1, + .f0_intraslot_freq_hopping = false, + .f2_nof_symbols = 2, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f0 = 9, + .nof_res_f2 = 19, + .f0_nof_symbols = 2, + .f0_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f0 = 39, + .nof_res_f2 = 25, + .f0_nof_symbols = 2, + .f0_intraslot_freq_hopping = true, + .f2_nof_symbols = 2, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f0 = 36, + .nof_res_f2 = 27, + .f0_nof_symbols = 1, + .f0_intraslot_freq_hopping = false, + .f2_nof_symbols = 2, + .max_nof_rbs = 7, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f2_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f0 = 15, + .nof_res_f2 = 10, + .f0_nof_symbols = 1, + .f0_intraslot_freq_hopping = false, + .f2_nof_symbols = 2, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f2_intraslot_freq_hopping = true}, + // F1 and F3 test cases. + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f3 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f3 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f3 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f3 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 11, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 137, + .nof_res_f3 = 25, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = true, + .f1_nof_symbols = 14, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 36, + .nof_res_f3 = 27, + .nof_cyc_shifts = nof_cyclic_shifts::three, + .occ_supported = true, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 34, + .nof_res_f3 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::two, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f3 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f3_nof_symbols = 4, + .f3_intraslot_freq_hopping = true}, + // F1 and F4 test cases. + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f4 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f4 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = false, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f4 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 7, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_25, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 39, + .nof_res_f4 = 19, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = true, + .f1_nof_symbols = 11, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 137, + .nof_res_f4 = 25, + .nof_cyc_shifts = nof_cyclic_shifts::twelve, + .occ_supported = true, + .f1_nof_symbols = 14, + .f1_intraslot_freq_hopping = true, + .max_nof_rbs = 1, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 36, + .nof_res_f4 = 27, + .nof_cyc_shifts = nof_cyclic_shifts::three, + .occ_supported = true, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 2, + .max_code_rate = srsran::max_pucch_code_rate::dot_15, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 34, + .nof_res_f4 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::two, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = false}, + pucch_gen_params{.nof_res_f1 = 15, + .nof_res_f4 = 10, + .nof_cyc_shifts = nof_cyclic_shifts::no_cyclic_shift, + .occ_supported = false, + .f1_nof_symbols = 9, + .f1_intraslot_freq_hopping = false, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = true}, + pucch_gen_params{.nof_res_f1 = 34, + .nof_res_f4 = 10, + .f0_nof_symbols = 1, + .f0_intraslot_freq_hopping = false, + .f2_nof_symbols = 1, + .max_nof_rbs = 7, + .max_payload_bits = 11, + .max_code_rate = srsran::max_pucch_code_rate::dot_08, + .f4_nof_symbols = 4, + .f4_intraslot_freq_hopping = false})); /////////////////// @@ -741,6 +999,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParamfront().serv_cell_cfg) { if (GetParam().nof_res_f0_harq != 0) { @@ -778,6 +1043,13 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParampucch_res_list; + for (auto& res : pucch_res_list) { + if (res.format == pucch_format::FORMAT_2) { + res.format = pucch_format::FORMAT_4; + } + } } if (GetParam().nof_res_csi == 0) { @@ -801,37 +1073,42 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam 0; - const unsigned nof_f0_f1_res_harq_per_ue = has_f0_res ? nof_f0_res_harq_per_ue : nof_f1_res_harq_per_ue; - const bool has_f2_res = nof_f2_res_harq_per_ue > 0; - const unsigned nof_f2_f3_res_harq_per_ue = has_f2_res ? nof_f2_res_harq_per_ue : nof_f3_res_harq_per_ue; + const bool has_f0_res = nof_f0_res_harq_per_ue > 0; + const unsigned nof_f0_f1_res_harq_per_ue = has_f0_res ? nof_f0_res_harq_per_ue : nof_f1_res_harq_per_ue; + const bool has_f2_res = nof_f2_res_harq_per_ue > 0; + unsigned nof_f2_f3_f4_res_harq_per_ue = nof_f2_res_harq_per_ue; + if (nof_f3_res_harq_per_ue > 0) { + nof_f2_f3_f4_res_harq_per_ue = nof_f3_res_harq_per_ue; + } else if (nof_f4_res_harq_per_ue > 0) { + nof_f2_f3_f4_res_harq_per_ue = nof_f4_res_harq_per_ue; + } bool test_result = true; - // Check the number of resources in the PUCCH resource list is correct. if (has_f0_res and has_f2_res) { - // For Format 0, the pucch_res_list contains 2 extra resources, 1 per PUCCH resource set. + // For Format 0 and Format 2, the pucch_res_list contains 2 extra resources, 1 per PUCCH resource set. const unsigned extra_resources = has_csi ? 2U : 1U; - test_result = pucch_cfg.pucch_res_list.size() == nof_f0_f1_res_harq_per_ue + nof_f2_f3_res_harq_per_ue + + test_result = pucch_cfg.pucch_res_list.size() == nof_f0_f1_res_harq_per_ue + nof_f2_f3_f4_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue + extra_resources; } else { test_result = pucch_cfg.pucch_res_list.size() == - nof_f0_f1_res_harq_per_ue + nof_f2_f3_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue; + nof_f0_f1_res_harq_per_ue + nof_f2_f3_f4_res_harq_per_ue + nof_sr_res_per_ue + nof_csi_res_per_ue; } - // Check the number of PUCCH F1 resources in the PUCCH resource sets is correct. + // Check the number of resources in the PUCCH resource sets is correct. if (has_f0_res and has_f2_res) { - // For Format 0, each PUCCH resource set contains extra resources. If CSI is enabled, then each PUCCH resource set - // contains 1 (new) PUCCH resource that is added to the pucch_res_list plus 1 that maps to the SR (in set 0) or - // CSI (in set 1). If CSI is not enabled, 1 PUCCH then each PUCCH resource set contains 1 PUCCH resource only. + // For Format 0 and Format 2, each PUCCH resource set contains extra resources. If CSI is enabled, then each PUCCH + // resource set contains 1 (new) PUCCH resource that is added to the pucch_res_list plus 1 that maps to the + // SR (in set 0) or CSI (in set 1). If CSI is not enabled, 1 PUCCH then each PUCCH resource set contains + // 1 PUCCH resource only. const unsigned extra_res_per_set = has_csi ? 2U : 1U; test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == nof_f0_f1_res_harq_per_ue + extra_res_per_set; test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == - nof_f2_f3_res_harq_per_ue + extra_res_per_set; + nof_f2_f3_f4_res_harq_per_ue + extra_res_per_set; } else { test_result = test_result && pucch_cfg.pucch_res_set[0].pucch_res_id_list.size() == nof_f0_f1_res_harq_per_ue; - test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_f3_res_harq_per_ue; + test_result = test_result && pucch_cfg.pucch_res_set[1].pucch_res_id_list.size() == nof_f2_f3_f4_res_harq_per_ue; } // Helper to retrieve a given PUCCH resource given its ID from the PUCCH resource list. @@ -846,7 +1123,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam= nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_f3_res_harq_per_ue * harq_cfg_idx and + nof_f2_f3_f4_res_harq_per_ue * harq_cfg_idx and res_idx.cell_res_id < nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_f3_res_harq_per_ue * (harq_cfg_idx + 1); + nof_f2_f3_f4_res_harq_per_ue * (harq_cfg_idx + 1); // The PUCCH resource ID for the ASN1 message for PUCCH // F2 resources is expected to be from (nof_f0_f1_res_harq_per_ue + 1) to (nof_f0_f1_res_harq_per_ue + 1 + - // nof_f2_res_harq_per_ue) for all UEs. - const bool pucch_ue_res_id_test = res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1 and - res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_f3_res_harq_per_ue; + // nof_f2_f3_f4_res_harq_per_ue) for all UEs. + const bool pucch_ue_res_id_test = + res_idx.ue_res_id >= nof_f0_f1_res_harq_per_ue + 1 and + res_idx.ue_res_id < nof_f0_f1_res_harq_per_ue + 1 + nof_f2_f3_f4_res_harq_per_ue; // Check if the PUCCH cell resourece ID is set correspondingly to the PUCCH UE resource ID. const bool pucch_ue_cell_res_id_test = res_idx.cell_res_id - (nof_f0_f1_res_harq_per_ue * nof_harq_cfg_per_ue + nof_sr_res_per_cell + - nof_f2_f3_res_harq_per_ue * harq_cfg_idx) == + nof_f2_f3_f4_res_harq_per_ue * harq_cfg_idx) == res_idx.ue_res_id - (nof_f0_f1_res_harq_per_ue + 1); test_result = test_result and pucch_cell_res_id_test and pucch_ue_res_id_test and pucch_ue_cell_res_id_test and @@ -999,7 +1277,12 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam 0) { + format_set_1 = pucch_format::FORMAT_3; + } else if (nof_f4_res_harq_per_ue > 0) { + format_set_1 = pucch_format::FORMAT_4; + } for (const auto& res : pucch_cfg.pucch_res_list) { // Take into account the extra resource introduced in set 0 in the case of F0 and F2. @@ -1071,6 +1354,7 @@ class test_ue_pucch_config_builder : public ::testing::TestWithParam res_list; ASSERT_FALSE(nof_f0_res_harq_per_ue != 0 and nof_f1_res_harq_per_ue != 0) @@ -1100,6 +1386,9 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) ASSERT_FALSE(nof_f0_res_harq_per_ue != 0 and nof_f3_res_harq_per_ue != 0) << "PUCCH Format 0 and Format 3 resources cannot be used together"; + ASSERT_FALSE(nof_f0_res_harq_per_ue != 0 and nof_f4_res_harq_per_ue != 0) + << "PUCCH Format 0 and Format 4 resources cannot be used together"; + unsigned nof_res_f0_f1; unsigned nof_ue_pucch_f0_f1_res_harq; std::variant f0_f1_params; @@ -1113,21 +1402,25 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) f0_f1_params.emplace(f1_params); } - unsigned nof_res_f2_f3; - unsigned nof_ue_pucch_f2_f3_res_harq; - std::variant f2_f3_params; + unsigned nof_res_f2_f3_f4; + unsigned nof_ue_pucch_f2_f3_f4_res_harq; + std::variant f2_f3_f4_params; if (nof_f2_res_harq_per_ue != 0) { - nof_res_f2_f3 = nof_f2_res; - nof_ue_pucch_f2_f3_res_harq = nof_f2_res_harq_per_ue; - f2_f3_params.emplace(f2_params); + nof_res_f2_f3_f4 = nof_f2_res; + nof_ue_pucch_f2_f3_f4_res_harq = nof_f2_res_harq_per_ue; + f2_f3_f4_params.emplace(f2_params); + } else if (nof_f3_res_harq_per_ue != 0) { + nof_res_f2_f3_f4 = nof_f3_res; + nof_ue_pucch_f2_f3_f4_res_harq = nof_f3_res_harq_per_ue; + f2_f3_f4_params.emplace(f3_params); } else { - nof_res_f2_f3 = nof_f3_res; - nof_ue_pucch_f2_f3_res_harq = nof_f3_res_harq_per_ue; - f2_f3_params.emplace(f3_params); + nof_res_f2_f3_f4 = nof_f4_res; + nof_ue_pucch_f2_f3_f4_res_harq = nof_f4_res_harq_per_ue; + f2_f3_f4_params.emplace(f4_params); } res_list = generate_cell_pucch_res_list( - nof_res_f0_f1, nof_res_f2_f3, f0_f1_params, f2_f3_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); + nof_res_f0_f1, nof_res_f2_f3_f4, f0_f1_params, f2_f3_f4_params, bwp_size, NOF_OFDM_SYM_PER_SLOT_NORMAL_CP); const auto harq_idx_cfg = test_rgen::uniform_int(0, nof_harq_cfg_per_ue - 1); const auto sr_idx_cfg = test_rgen::uniform_int(0, nof_sr_res_per_cell - 1); @@ -1140,7 +1433,7 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) sr_idx_cfg, csi_idx_cfg, nof_ue_pucch_f0_f1_res_harq, - nof_ue_pucch_f2_f3_res_harq, + nof_ue_pucch_f2_f3_f4_res_harq, nof_harq_cfg_per_ue, nof_sr_res_per_cell, nof_csi_res_per_cell); @@ -1151,42 +1444,54 @@ TEST_P(test_ue_pucch_config_builder, test_validator_too_many_resources) INSTANTIATE_TEST_SUITE_P(ue_pucch_config_builder, test_ue_pucch_config_builder, // clang-format off - // nof: f0 | f1 | f2 | f3 | harq | sr | csi - // nof: f0 | f1 | f2 | f3 | cfg | sr | csi + // nof: f0 | f1 | f2 | f3 | f4 | harq | sr | csi + // nof: f0 | f1 | f2 | f3 | f4 | cfg | sr | csi ::testing::Values( - pucch_cfg_builder_params{ 0, 3, 6, 0, 1, 2, 1 }, - pucch_cfg_builder_params{ 0, 7, 3, 0, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 8, 8, 0, 1, 4, 1 }, - pucch_cfg_builder_params{ 0, 1, 1, 0, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 7, 7, 0, 1, 3, 1 }, - pucch_cfg_builder_params{ 0, 8, 8, 0, 4, 4, 4 }, - pucch_cfg_builder_params{ 0, 5, 2, 0, 8, 2, 7 }, - pucch_cfg_builder_params{ 0, 2, 7, 0, 3, 7, 3 }, - pucch_cfg_builder_params{ 0, 6, 4, 0, 5, 6, 2 }, - pucch_cfg_builder_params{ 6, 0, 6, 0, 1, 8, 8 }, - pucch_cfg_builder_params{ 5, 0, 3, 0, 1, 1, 1 }, - pucch_cfg_builder_params{ 6, 0, 6, 0, 1, 4, 1 }, - pucch_cfg_builder_params{ 2, 0, 2, 0, 1, 1, 1 }, - pucch_cfg_builder_params{ 3, 0, 5, 0, 1, 3, 1 }, - pucch_cfg_builder_params{ 3, 0, 5, 0, 1, 1, 3 }, - pucch_cfg_builder_params{ 6, 0, 6, 0, 4, 4, 4 }, - pucch_cfg_builder_params{ 5, 0, 2, 0, 10, 2, 7 }, - pucch_cfg_builder_params{ 2, 0, 5, 0, 10, 2, 7 }, - pucch_cfg_builder_params{ 2, 0, 5, 0, 10, 7, 2 }, - pucch_cfg_builder_params{ 4, 0, 4, 0, 10, 21, 14 }, - pucch_cfg_builder_params{ 2, 0, 6, 0, 3, 7, 3 }, - pucch_cfg_builder_params{ 6, 0, 4, 0, 5, 6, 2 }, - pucch_cfg_builder_params{ 6, 0, 6, 0, 3, 6, 0 }, - // Format 3 test cases. - pucch_cfg_builder_params{ 0, 3, 0, 6, 1, 2, 1 }, - pucch_cfg_builder_params{ 0, 7, 0, 3, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 8, 0, 8, 1, 4, 1 }, - pucch_cfg_builder_params{ 0, 1, 0, 1, 1, 1, 1 }, - pucch_cfg_builder_params{ 0, 7, 0, 7, 1, 3, 1 }, - pucch_cfg_builder_params{ 0, 8, 0, 8, 4, 4, 4 }, - pucch_cfg_builder_params{ 0, 5, 0, 2, 8, 2, 7 }, - pucch_cfg_builder_params{ 0, 2, 0, 7, 3, 7, 3 }, - pucch_cfg_builder_params{ 0, 6, 0, 4, 5, 6, 2 } + // Format 0 and Format 2 test cases. + pucch_cfg_builder_params{ 6, 0, 6, 0, 0, 1, 8, 8 }, + pucch_cfg_builder_params{ 5, 0, 3, 0, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 0, 1, 4, 1 }, + pucch_cfg_builder_params{ 2, 0, 2, 0, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 3, 0, 5, 0, 0, 1, 3, 1 }, + pucch_cfg_builder_params{ 3, 0, 5, 0, 0, 1, 1, 3 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 0, 4, 4, 4 }, + pucch_cfg_builder_params{ 5, 0, 2, 0, 0, 10, 2, 7 }, + pucch_cfg_builder_params{ 2, 0, 5, 0, 0, 10, 2, 7 }, + pucch_cfg_builder_params{ 2, 0, 5, 0, 0, 10, 7, 2 }, + pucch_cfg_builder_params{ 4, 0, 4, 0, 0, 10, 21, 14 }, + pucch_cfg_builder_params{ 2, 0, 6, 0, 0, 3, 7, 3 }, + pucch_cfg_builder_params{ 6, 0, 4, 0, 0, 5, 6, 2 }, + pucch_cfg_builder_params{ 6, 0, 6, 0, 0, 3, 6, 0 }, + // Format 1 and Format 2 test cases. + pucch_cfg_builder_params{ 0, 3, 6, 0, 0, 1, 2, 1 }, + pucch_cfg_builder_params{ 0, 7, 3, 0, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 8, 8, 0, 0, 1, 4, 1 }, + pucch_cfg_builder_params{ 0, 1, 1, 0, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 7, 7, 0, 0, 1, 3, 1 }, + pucch_cfg_builder_params{ 0, 8, 8, 0, 0, 4, 4, 4 }, + pucch_cfg_builder_params{ 0, 5, 2, 0, 0, 8, 2, 7 }, + pucch_cfg_builder_params{ 0, 2, 7, 0, 0, 3, 7, 3 }, + pucch_cfg_builder_params{ 0, 6, 4, 0, 0, 5, 6, 2 }, + // Format 1 and Format 3 test cases. + pucch_cfg_builder_params{ 0, 3, 0, 6, 0, 1, 2, 1 }, + pucch_cfg_builder_params{ 0, 7, 0, 3, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 8, 0, 8, 0, 1, 4, 1 }, + pucch_cfg_builder_params{ 0, 1, 0, 1, 0, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 7, 0, 7, 0, 1, 3, 1 }, + pucch_cfg_builder_params{ 0, 8, 0, 8, 0, 4, 4, 4 }, + pucch_cfg_builder_params{ 0, 5, 0, 2, 0, 8, 2, 7 }, + pucch_cfg_builder_params{ 0, 2, 0, 7, 0, 3, 7, 3 }, + pucch_cfg_builder_params{ 0, 6, 0, 4, 0, 5, 6, 2 }, + // Format 1 and Format 4 test cases. + pucch_cfg_builder_params{ 0, 3, 0, 0, 6, 1, 2, 1 }, + pucch_cfg_builder_params{ 0, 7, 0, 0, 3, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 8, 0, 0, 8, 1, 4, 1 }, + pucch_cfg_builder_params{ 0, 1, 0, 0, 1, 1, 1, 1 }, + pucch_cfg_builder_params{ 0, 7, 0, 0, 7, 1, 3, 1 }, + pucch_cfg_builder_params{ 0, 8, 0, 0, 8, 4, 4, 4 }, + pucch_cfg_builder_params{ 0, 5, 0, 0, 2, 8, 2, 7 }, + pucch_cfg_builder_params{ 0, 2, 0, 0, 7, 3, 7, 3 }, + pucch_cfg_builder_params{ 0, 6, 0, 0, 4, 5, 6, 2 } ) // clang-format on ); diff --git a/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp b/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp index b2236ee3a8..1e0468c426 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp +++ b/tests/unittests/fapi_adaptor/mac/messages/helpers.cpp @@ -709,7 +709,7 @@ pucch_info_test_helper srsran::unittests::build_valid_pucch_format_4_pdu() pucch.format_4.harq_ack_nof_bits = 100; pucch.format_4.sr_bits = sr_nof_bits::one; pucch.format_4.n_id_0_scrambling = 256; - pucch.format_4.n_id_scambling = 382; + pucch.format_4.n_id_scrambling = 382; pucch.format_4.n_id_hopping = 180; pucch.format_4.additional_dmrs = false; pucch.format_4.pi_2_bpsk = true; diff --git a/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp b/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp index 39a50fdb9e..3b637f48b6 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp +++ b/tests/unittests/fapi_adaptor/mac/messages/ul_pucch_pdu_test.cpp @@ -158,7 +158,7 @@ TEST(mac_fapi_ul_pucch_format4_pdu_conversor_test, ul_pucch_format4_pdu_valid_sh const pucch_format_4& f4 = mac_pdu.format_4; ASSERT_EQ(static_cast(f4.max_code_rate), fapi_pdu.pucch_maintenance_v3.max_code_rate); ASSERT_EQ(f4.n_id_0_scrambling, fapi_pdu.nid0_pucch_dmrs_scrambling); - ASSERT_EQ(f4.n_id_scambling, fapi_pdu.nid_pucch_scrambling); + ASSERT_EQ(f4.n_id_scrambling, fapi_pdu.nid_pucch_scrambling); ASSERT_EQ(f4.n_id_hopping, fapi_pdu.nid_pucch_hopping); ASSERT_EQ(static_cast(f4.sr_bits), fapi_pdu.sr_bit_len); ASSERT_EQ(f4.harq_ack_nof_bits, fapi_pdu.bit_len_harq); diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index 8284c48690..57aba7059a 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -118,10 +118,10 @@ class scheduler_impl_tester test_logger.set_context(current_slot.sfn(), current_slot.slot_index()); bench->sched_res = &bench->sch.slot_indication(current_slot, to_du_cell_index(0)); - srs_du::pucch_builder_params pucch_basic_params{.nof_ue_pucch_f0_or_f1_res_harq = 8, - .nof_ue_pucch_f2_or_f3_res_harq = 8, - .nof_sr_resources = 8, - .nof_csi_resources = 8}; + srs_du::pucch_builder_params pucch_basic_params{.nof_ue_pucch_f0_or_f1_res_harq = 8, + .nof_ue_pucch_f2_or_f3_or_f4_res_harq = 8, + .nof_sr_resources = 8, + .nof_csi_resources = 8}; auto& f1_params = pucch_basic_params.f0_or_f1_params.emplace(); f1_params.nof_cyc_shifts = srs_du::nof_cyclic_shifts::twelve; f1_params.occ_supported = true; diff --git a/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp b/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp index 945eb38764..b9665cccbf 100644 --- a/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp +++ b/tests/unittests/scheduler/test_doubles/test_pucch_res_test_builder_helper.cpp @@ -86,7 +86,8 @@ TEST_P(sched_pucch_res_builder_tester, when_ues_are_added_their_cfg_have_differe // Each UE should have 2 PUCCH resource sets configured ASSERT_EQ(ue_pucch_cfg.pucch_res_set.size(), 2); ASSERT_EQ(ue_pucch_cfg.pucch_res_set[0].pucch_res_id_list.size(), pucch_params.nof_ue_pucch_f0_or_f1_res_harq); - ASSERT_EQ(ue_pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), pucch_params.nof_ue_pucch_f2_or_f3_res_harq); + ASSERT_EQ(ue_pucch_cfg.pucch_res_set[1].pucch_res_id_list.size(), + pucch_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq); // Make sure UE has all PUCCH resources with different cell_res_id. { std::set pucch_res_idxs; diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index f086113ebe..761593c78e 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -204,8 +204,8 @@ test_bench::test_bench(const test_bench_params& params, if (use_format_0) { srs_du::pucch_builder_params pucch_params{}; - pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6; - pucch_params.nof_ue_pucch_f2_or_f3_res_harq = 6; + pucch_params.nof_ue_pucch_f0_or_f1_res_harq = 6; + pucch_params.nof_ue_pucch_f2_or_f3_or_f4_res_harq = 6; pucch_params.f0_or_f1_params.emplace(); pucch_builder.setup( cell_cfg.ul_cfg_common.init_ul_bwp, params.is_tdd ? cell_cfg.tdd_cfg_common : std::nullopt, pucch_params); From 83fadf4a19b18d057dcd48d0805944f07324e46a Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Mon, 9 Dec 2024 16:13:05 +0100 Subject: [PATCH 093/227] mac: review support pucch f4 in pucch_resource_generator --- .../du_high/du_high_config_translators.cpp | 2 +- .../srsran/ran/pucch/pucch_configuration.h | 2 +- include/srsran/ran/pucch/pucch_info.h | 8 +- .../pucch_resource_generator.cpp | 157 +++++++++--------- lib/ran/pucch/pucch_info.cpp | 4 +- .../pucch_resource_generator_test.cpp | 155 ++++++++++------- 6 files changed, 184 insertions(+), 144 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index 02e9751a18..8df5ed177f 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -575,7 +575,7 @@ std::vector srsran::generate_du_cell_config(const du_hig f4_params.intraslot_freq_hopping = user_pucch_cfg.f4_intraslot_freq_hopping; f4_params.additional_dmrs = user_pucch_cfg.f4_additional_dmrs; f4_params.pi2_bpsk = user_pucch_cfg.f4_pi2_bpsk; - f4_params.occ_length = user_pucch_cfg.f4_occ_length == 2 ? pucch_f4_occ_len::n2 : pucch_f4_occ_len::n4; + f4_params.occ_length = static_cast(user_pucch_cfg.f4_occ_length); } break; default: break; diff --git a/include/srsran/ran/pucch/pucch_configuration.h b/include/srsran/ran/pucch/pucch_configuration.h index fc27c573b4..af14b24147 100644 --- a/include/srsran/ran/pucch/pucch_configuration.h +++ b/include/srsran/ran/pucch/pucch_configuration.h @@ -36,7 +36,7 @@ constexpr size_t MAX_NOF_UE_PUCCH_RESOURCES = 128; constexpr size_t MAX_NOF_PUCCH_RESOURCES_PER_PUCCH_RESOURCE_SET = 32; /// Options for \c occ-Length in \c PUCCH-format4, in \c PUCCH-Config, TS 38.331. -enum class pucch_f4_occ_len { n2, n4 }; +enum class pucch_f4_occ_len { n2 = 2, n4 = 4 }; /// Options for \c occ-Index in \c PUCCH-format4, in \c PUCCH-Config, TS 38.331. enum class pucch_f4_occ_idx { n0, n1, n2, n3 }; diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index 2dc7b4e65b..4e422371f6 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -151,7 +151,7 @@ get_pucch_format2_nof_prbs(unsigned nof_payload_bits, unsigned max_nof_prbs, uns /// \param[in] max_nof_prbs Transmission bandwidth in PRBs. /// \param[in] nof_symbols Transmission duration in symbols. /// \param[in] max_code_rate Maximum allowed PUCCH Format 2 code rate. -/// \return The maximum payload for a PUCCH Format 2 transmission. +/// \return The maximum payload (in bits) for a PUCCH Format 2 transmission. unsigned get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate); /// \brief Calculates the number of OFDM symbols filled with DM-RS in a PUCCH Format 3/4 resource. @@ -200,7 +200,7 @@ unsigned get_pucch_format3_max_nof_prbs(unsigned nof_pay /// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. /// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. /// \param[in] pi2_bpsk Flag indicating if pi/2-BPSK modulation is used. -/// \return The maximum payload for a PUCCH Format 3 transmission. +/// \return The maximum payload (in bits) for a PUCCH Format 3 transmission. unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate, @@ -213,9 +213,9 @@ unsigned get_pucch_format3_max_payload(unsigned max_nof_prbs, /// \param[in] max_code_rate Maximum allowed PUCCH Format 4 code rate. /// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. /// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. -/// \param[in] pi2_bpsk Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] pi2_bpsk Flag indicating if pi/2-BPSK modulation is used. /// \param[in] occ_length OCC length. -/// \return The maximum payload for a PUCCH Format 4 transmission. +/// \return The maximum payload (in bits) for a PUCCH Format 4 transmission. unsigned get_pucch_format4_max_payload(unsigned nof_symbols, float max_code_rate, bool intraslot_freq_hopping, diff --git a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp index b1d3813b8e..9c86cc2e1d 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/pucch_resource_generator.cpp @@ -65,35 +65,32 @@ static std::vector compute_f0_res(unsigned bounded_integer max_nof_symbols) { // Compute the number of symbols and RBs for F0. - std::vector res_list; - const unsigned nof_f0_symbols = params.nof_symbols.to_uint(); + std::vector res_list; + const unsigned nof_f0_symbols = params.nof_symbols.to_uint(); + static constexpr unsigned f0_max_rbs = 1U; // With intraslot freq. hopping. if (params.intraslot_freq_hopping) { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1U; ++rb_idx) { + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f0_max_rbs; rb_idx != rb_stop; ++rb_idx) { // Generate resource for increasing RB index, until the num. of required resources is reached. - const prb_interval prbs{rb_idx, rb_idx + 1U}; + const prb_interval prbs{rb_idx, rb_idx + f0_max_rbs}; // Pre-compute the second RBs for the frequency hop specularly to the first RBs. - const prb_interval freq_hop_prbs{bwp_size_rbs - 1U - rb_idx, bwp_size_rbs - rb_idx}; + const prb_interval freq_hop_prbs{bwp_size_rbs - f0_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f0_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f0_symbols}; // Allocate resources for first hop. - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_0, - .symbols = symbols, - .prbs = prbs, - .freq_hop_grant = freq_hop_prbs}); + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs, .freq_hop_grant = freq_hop_prbs}); if (res_list.size() == nof_res_f0) { break; } // Allocate resources for second hop. - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_2, - .symbols = symbols, - .prbs = freq_hop_prbs, - .freq_hop_grant = prbs}); + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_2, .symbols = symbols, .prbs = freq_hop_prbs, .freq_hop_grant = prbs}); if (res_list.size() == nof_res_f0) { break; } @@ -105,17 +102,17 @@ static std::vector compute_f0_res(unsigned } // Without intraslot freq. hopping. else { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1U; ++rb_idx) { - const prb_interval prbs_low_spectrum{rb_idx, rb_idx + 1U}; + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f0_max_rbs; rb_idx != rb_stop; ++rb_idx) { + const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f0_max_rbs}; // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve // balancing of the PUCCH resources on both sides of the BWP. - const prb_interval prbs_hi_spectrum{bwp_size_rbs - 1U - rb_idx, bwp_size_rbs - rb_idx}; + const prb_interval prbs_hi_spectrum{bwp_size_rbs - f0_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. for (unsigned sym_idx = 0; sym_idx + nof_f0_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f0_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f0_symbols}; res_list.emplace_back( - pucch_grant{.format = srsran::pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs_low_spectrum}); + pucch_grant{.format = pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs_low_spectrum}); if (res_list.size() == nof_res_f0) { break; } @@ -130,7 +127,7 @@ static std::vector compute_f0_res(unsigned sym_idx += nof_f0_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f0_symbols}; res_list.emplace_back( - pucch_grant{.format = srsran::pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs_hi_spectrum}); + pucch_grant{.format = pucch_format::FORMAT_0, .symbols = symbols, .prbs = prbs_hi_spectrum}); if (res_list.size() == nof_res_f0) { break; } @@ -151,15 +148,16 @@ static std::vector compute_f1_res(unsigned unsigned nof_occ_css, bounded_integer max_nof_symbols) { - std::vector res_list; + std::vector res_list; + static constexpr unsigned f1_max_rbs = 1U; // With intraslot_freq_hopping. if (params.intraslot_freq_hopping) { // Generate resource for increasing RB index, until the num. of required resources is reached. - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1; ++rb_idx) { - const prb_interval prbs{rb_idx, rb_idx + 1}; + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f1_max_rbs; rb_idx != rb_stop; ++rb_idx) { + const prb_interval prbs{rb_idx, rb_idx + f1_max_rbs}; // Pre-compute the second RBs for the frequency hop specularly to the first RBs. - const prb_interval freq_hop_prbs{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; + const prb_interval freq_hop_prbs{bwp_size_rbs - f1_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= max_nof_symbols.to_uint(); @@ -170,8 +168,8 @@ static std::vector compute_f1_res(unsigned // NOTE: occ_cs_idx is an index that will be mapped into Initial Cyclic Shift and Orthogonal Cover Code (OCC). // Two PUCCH F1 resources over the same symbols and RBs are orthogonal if they have different CS or different // OCC; this leads to a tot. nof OCCs x tot. nof CSs possible orthogonal F1 resources over the same REs. - for (unsigned occ_cs_idx = 0; occ_cs_idx < nof_occ_css; ++occ_cs_idx) { - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_1, + for (unsigned occ_cs_idx = 0; occ_cs_idx != nof_occ_css; ++occ_cs_idx) { + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_1, .symbols = symbols, .prbs = prbs, .freq_hop_grant = freq_hop_prbs, @@ -185,8 +183,8 @@ static std::vector compute_f1_res(unsigned } // Allocate all OCC and CSS resources for second hop, until the num. of required resources is reached. - for (unsigned occ_cs_idx = 0; occ_cs_idx < nof_occ_css; ++occ_cs_idx) { - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_1, + for (unsigned occ_cs_idx = 0; occ_cs_idx != nof_occ_css; ++occ_cs_idx) { + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_1, .symbols = symbols, .prbs = freq_hop_prbs, .freq_hop_grant = prbs, @@ -207,11 +205,11 @@ static std::vector compute_f1_res(unsigned // Without intraslot freq. hopping. else { // Generate resource for increasing RB index, until the num. of required resources is reached. - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1; ++rb_idx) { - const prb_interval prbs_low_spectrum{rb_idx, rb_idx + 1}; + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f1_max_rbs; rb_idx != rb_stop; ++rb_idx) { + const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f1_max_rbs}; // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve // balancing of the PUCCH resources on both sides of the BWP. - const prb_interval prbs_hi_spectrum{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; + const prb_interval prbs_hi_spectrum{bwp_size_rbs - f1_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. for (unsigned sym_idx = 0; sym_idx + params.nof_symbols.to_uint() <= max_nof_symbols.to_uint(); @@ -219,8 +217,8 @@ static std::vector compute_f1_res(unsigned const ofdm_symbol_range symbols{sym_idx, sym_idx + params.nof_symbols.to_uint()}; // Allocate all OCC and CS resources, until the num. of required resources is reached. - for (unsigned occ_cs_idx = 0; occ_cs_idx < nof_occ_css; ++occ_cs_idx) { - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_1, + for (unsigned occ_cs_idx = 0; occ_cs_idx != nof_occ_css; ++occ_cs_idx) { + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_1, .symbols = symbols, .prbs = prbs_low_spectrum, .occ_cs_idx = occ_cs_idx}); @@ -242,8 +240,8 @@ static std::vector compute_f1_res(unsigned sym_idx += params.nof_symbols.to_uint()) { const ofdm_symbol_range symbols{sym_idx, sym_idx + params.nof_symbols.to_uint()}; - for (unsigned occ_cs_idx = 0; occ_cs_idx < nof_occ_css; ++occ_cs_idx) { - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_1, + for (unsigned occ_cs_idx = 0; occ_cs_idx != nof_occ_css; ++occ_cs_idx) { + res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_1, .symbols = symbols, .prbs = prbs_hi_spectrum, .occ_cs_idx = occ_cs_idx}); @@ -285,7 +283,7 @@ static std::vector compute_f2_res(unsigned // With intraslot freq. hopping. if (params.intraslot_freq_hopping) { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f2_max_rbs; rb_idx += f2_max_rbs) { + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f2_max_rbs; rb_idx < rb_stop; rb_idx += f2_max_rbs) { // Generate resource for increasing RB index, until the num. of required resources is reached. const prb_interval prbs{rb_idx, rb_idx + f2_max_rbs}; // Pre-compute the second RBs for the frequency hop specularly to the first RBs. @@ -296,19 +294,15 @@ static std::vector compute_f2_res(unsigned const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f2_symbols}; // Allocate resources for first hop. - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_2, - .symbols = symbols, - .prbs = prbs, - .freq_hop_grant = freq_hop_prbs}); + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs, .freq_hop_grant = freq_hop_prbs}); if (res_list.size() == nof_res_f2) { break; } // Allocate resources for second hop. - res_list.emplace_back(pucch_grant{.format = srsran::pucch_format::FORMAT_2, - .symbols = symbols, - .prbs = freq_hop_prbs, - .freq_hop_grant = prbs}); + res_list.emplace_back(pucch_grant{ + .format = pucch_format::FORMAT_2, .symbols = symbols, .prbs = freq_hop_prbs, .freq_hop_grant = prbs}); if (res_list.size() == nof_res_f2) { break; } @@ -320,7 +314,7 @@ static std::vector compute_f2_res(unsigned } // Without intraslot freq. hopping. else { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f2_max_rbs; rb_idx += f2_max_rbs) { + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f2_max_rbs; rb_idx < rb_stop; rb_idx += f2_max_rbs) { const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f2_max_rbs}; // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve // balancing of the PUCCH resources on both sides of the BWP. @@ -330,7 +324,7 @@ static std::vector compute_f2_res(unsigned for (unsigned sym_idx = 0; sym_idx + nof_f2_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f2_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f2_symbols}; res_list.emplace_back( - pucch_grant{.format = srsran::pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs_low_spectrum}); + pucch_grant{.format = pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs_low_spectrum}); if (res_list.size() == nof_res_f2) { break; } @@ -345,7 +339,7 @@ static std::vector compute_f2_res(unsigned sym_idx += nof_f2_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f2_symbols}; res_list.emplace_back( - pucch_grant{.format = srsran::pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs_hi_spectrum}); + pucch_grant{.format = pucch_format::FORMAT_2, .symbols = symbols, .prbs = prbs_hi_spectrum}); if (res_list.size() == nof_res_f2) { break; } @@ -383,7 +377,7 @@ static std::vector compute_f3_res(unsigned // With intraslot freq. hopping. if (params.intraslot_freq_hopping) { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f3_max_rbs; rb_idx += f3_max_rbs) { + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f3_max_rbs; rb_idx < rb_stop; rb_idx += f3_max_rbs) { // Generate resource for increasing RB index, until the num. of required resources is reached. const prb_interval prbs{rb_idx, rb_idx + f3_max_rbs}; // Pre-compute the second RBs for the frequency hop specularly to the first RBs. @@ -414,7 +408,7 @@ static std::vector compute_f3_res(unsigned } // Without intraslot freq. hopping. else { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - f3_max_rbs; rb_idx += f3_max_rbs) { + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f3_max_rbs; rb_idx < rb_stop; rb_idx += f3_max_rbs) { const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f3_max_rbs}; // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve // balancing of the PUCCH resources on both sides of the BWP. @@ -459,23 +453,24 @@ static std::vector compute_f4_res(unsigned unsigned bwp_size_rbs, bounded_integer max_nof_symbols) { - std::vector res_list; - const unsigned nof_f4_symbols = params.nof_symbols.to_uint(); - const unsigned occ_length = params.occ_length == pucch_f4_occ_len::n2 ? 2 : 4; + std::vector res_list; + const unsigned nof_f4_symbols = params.nof_symbols.to_uint(); + const unsigned occ_length = static_cast(params.occ_length); + static constexpr unsigned f4_max_rbs = 1U; // With intraslot freq. hopping. if (params.intraslot_freq_hopping) { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1; ++rb_idx) { + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f4_max_rbs; rb_idx != rb_stop; ++rb_idx) { // Generate resource for increasing RB index, until the num. of required resources is reached. - const prb_interval prbs{rb_idx, rb_idx + 1}; + const prb_interval prbs{rb_idx, rb_idx + f4_max_rbs}; // Pre-compute the second RBs for the frequency hop specularly to the first RBs. - const prb_interval freq_hop_prbs{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; + const prb_interval freq_hop_prbs{bwp_size_rbs - f4_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f4_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f4_symbols}; - for (unsigned occ_index = 0; occ_index < occ_length; ++occ_index) { + for (unsigned occ_index = 0; occ_index != occ_length; ++occ_index) { // Allocate resources for first hop. res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_4, .symbols = symbols, @@ -499,18 +494,18 @@ static std::vector compute_f4_res(unsigned } } } - // With intraslot freq. hopping. + // Without intraslot freq. hopping. else { - for (unsigned rb_idx = 0; rb_idx < bwp_size_rbs / 2 - 1; ++rb_idx) { - const prb_interval prbs_low_spectrum{rb_idx, rb_idx + 1}; + for (unsigned rb_idx = 0, rb_stop = bwp_size_rbs / 2 - f4_max_rbs; rb_idx != rb_stop; ++rb_idx) { + const prb_interval prbs_low_spectrum{rb_idx, rb_idx + f4_max_rbs}; // Pre-compute the RBs for the resources to be allocated on the upper part of the spectrum. This is to achieve // balancing of the PUCCH resources on both sides of the BWP. - const prb_interval prbs_hi_spectrum{bwp_size_rbs - 1 - rb_idx, bwp_size_rbs - rb_idx}; + const prb_interval prbs_hi_spectrum{bwp_size_rbs - f4_max_rbs - rb_idx, bwp_size_rbs - rb_idx}; // Generate resource for increasing Symbol index, until the num. of required resources is reached. for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f4_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f4_symbols}; - for (unsigned occ_index = 0; occ_index < occ_length; ++occ_index) { + for (unsigned occ_index = 0; occ_index != occ_length; ++occ_index) { res_list.emplace_back(pucch_grant{.format = pucch_format::FORMAT_4, .symbols = symbols, .prbs = prbs_low_spectrum, @@ -523,9 +518,9 @@ static std::vector compute_f4_res(unsigned // Repeat the resource allocation on the upper part of the spectrum, to spread the PUCCH resource on both sides of // the BWP. - for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= 14; sym_idx += nof_f4_symbols) { + for (unsigned sym_idx = 0; sym_idx + nof_f4_symbols <= max_nof_symbols.to_uint(); sym_idx += nof_f4_symbols) { const ofdm_symbol_range symbols{sym_idx, sym_idx + nof_f4_symbols}; - for (unsigned occ_index = 0; occ_index < occ_length; ++occ_index) { + for (unsigned occ_index = 0; occ_index != occ_length; ++occ_index) { res_list.emplace_back(pucch_grant{ .format = pucch_format::FORMAT_4, .symbols = symbols, .prbs = prbs_hi_spectrum, .occ_cs_idx = occ_index}); if (res_list.size() == nof_res_f4) { @@ -550,6 +545,10 @@ error_type srs_du::pucch_parameters_validator( const bool has_f0 = std::holds_alternative(f0_f1_params); unsigned nof_f0_f1_rbs = 0; + if (nof_res_f0_f1 == 0 || nof_res_f2_f3_f4 == 0) { + return make_unexpected("The number of F0/F1 resources and F2/F3/F4 resources must be greater than zero."); + } + if (has_f0) { const auto& f0_params = std::get(f0_f1_params); // > If intraslot_freq_hopping is enabled, check if PUCCH Format 0 has more than symbol. @@ -651,7 +650,8 @@ error_type srs_du::pucch_parameters_validator( // PUCCH Format 4. const auto& f4_params = std::get(f2_f3_f4_params); - const unsigned nof_f4_blocks = max_nof_symbols.to_uint() / f4_params.nof_symbols.to_uint(); + const unsigned nof_f4_blocks = + static_cast(f4_params.occ_length) * max_nof_symbols.to_uint() / f4_params.nof_symbols.to_uint(); nof_f2_f3_f4_rbs = static_cast(std::ceil(static_cast(nof_res_f2_f3_f4) / static_cast(nof_f4_blocks))); // With intraslot_freq_hopping, the nof of RBs is an even number of the PUCCH resource size in RB. @@ -676,7 +676,8 @@ static std::vector merge_f0_f1_f2_f3_f4_resource_lists(const std::vector& pucch_f0_f1_resource_list, const std::vector& pucch_f2_f3_f4_resource_list, std::optional nof_cs, - unsigned bwp_size_rbs) + unsigned bwp_size_rbs, + pucch_f4_occ_len f4_occ_len) { // This function merges the lists of PUCCH F0/F1 and F2/F3/F4 resource. It first allocates the F0/F1 resources on the // sides of the BWP; second, it allocates the F2/F3/F4 resources beside F0/F1 ones. @@ -769,9 +770,8 @@ merge_f0_f1_f2_f3_f4_resource_lists(const std::vector& pucch_f0_f1_ } } - // TODO: when the list is empty, we are assuming F2. - const pucch_format set1_format = - not pucch_f2_f3_f4_resource_list.empty() ? pucch_f2_f3_f4_resource_list[0].format : pucch_format::FORMAT_2; + // The resource lists can't be empty as validated by `pucch_parameters_validator`. + const pucch_format set1_format = pucch_f2_f3_f4_resource_list[0].format; switch (set1_format) { case pucch_format::FORMAT_2: { @@ -858,7 +858,7 @@ merge_f0_f1_f2_f3_f4_resource_lists(const std::vector& pucch_f0_f1_ pucch_format_4_cfg format4{.starting_sym_idx = res_f4.symbols.start()}; format4.nof_symbols = res_f4.symbols.length(); - format4.occ_length = pucch_f4_occ_len::n4; + format4.occ_length = f4_occ_len; format4.occ_index = occ_cs_index_to_f4_occ(res_f4.occ_cs_idx.value()); res.format_params.emplace(format4); res.format = pucch_format::FORMAT_4; @@ -905,6 +905,7 @@ std::vector srs_du::generate_cell_pucch_res_list( } std::vector pucch_f2_f3_f4_resource_list; + pucch_f4_occ_len f4_occ_len(pucch_f4_occ_len::n2); if (std::holds_alternative(f2_f3_f4_params)) { const auto& f2_params = std::get(f2_f3_f4_params); pucch_f2_f3_f4_resource_list = compute_f2_res(nof_res_f2_f3_f4, f2_params, bwp_size_rbs, max_nof_symbols); @@ -914,12 +915,14 @@ std::vector srs_du::generate_cell_pucch_res_list( } else { const auto& f4_params = std::get(f2_f3_f4_params); pucch_f2_f3_f4_resource_list = compute_f4_res(nof_res_f2_f3_f4, f4_params, bwp_size_rbs, max_nof_symbols); + f4_occ_len = f4_params.occ_length; } auto res_list = merge_f0_f1_f2_f3_f4_resource_lists(pucch_f0_f1_resource_list, pucch_f2_f3_f4_resource_list, has_f0 ? std::nullopt : std::optional{nof_css}, - bwp_size_rbs); + bwp_size_rbs, + f4_occ_len); if (res_list.size() > pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES) { srsran_assertion_failure("With the given parameters, the number of PUCCH resources generated for the " @@ -960,13 +963,14 @@ static unsigned cell_res_list_and_params_validator( if (contain_format_0 and contain_format_2) { if (nof_ue_pucch_f0_f1_res_harq.to_uint() > 6U) { - srsran_assertion_failure("With Format 0, nof_ue_pucch_f0_f1_res_harq cannot be greater than 6, as 2 " + srsran_assertion_failure("With Format 0 and Format 2, nof_ue_pucch_f0_f1_res_harq cannot be greater than 6, as 2 " "resources in set 0 are reserved."); return FAILURE_CASE; } if (nof_ue_pucch_f2_f3_f4_res_harq.to_uint() > 6U) { - srsran_assertion_failure("With Format 0, nof_ue_pucch_f2_f3_f4_res_harq cannot be greater than 6, as 2 " - "resources in set 1 are reserved."); + srsran_assertion_failure( + "With Format 0 and Format 2, nof_ue_pucch_f2_f3_f4_res_harq cannot be greater than 6, as 2 " + "resources in set 1 are reserved."); return FAILURE_CASE; } } @@ -982,15 +986,16 @@ static unsigned cell_res_list_and_params_validator( return FAILURE_CASE; } - if ((tot_nof_f2_res != 0) + (tot_nof_f3_res != 0) + (tot_nof_f4_res != 0) > 1) { + if (static_cast(tot_nof_f2_res != 0) + static_cast(tot_nof_f3_res != 0) + + static_cast(tot_nof_f4_res != 0) > + 1) { srsran_assertion_failure( "The cell PUCCH resource list can contain either F2, F3 or F4 PUCCH resources, but not a mix of those types."); return FAILURE_CASE; } if (tot_nof_f0_res != 0 and (tot_nof_f3_res != 0 or tot_nof_f4_res != 0)) { - srsran_assertion_failure( - "The implementation is not prepared to handle PUCCH F0 and F3 or F0 and F4 resources at the same time."); + srsran_assertion_failure("The implementation is not prepared to handle PUCCH F3 or F4 when Format 0 is used."); return FAILURE_CASE; } @@ -1083,7 +1088,7 @@ bool srs_du::ue_pucch_config_builder( const bool is_format_2 = res_list[f2_f3_f4_idx_offset].format == pucch_format::FORMAT_2; // Add F0/F1 for HARQ. - for (unsigned ue_f0_f1_cnt = 0; ue_f0_f1_cnt < nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f0_f1_cnt) { + for (unsigned ue_f0_f1_cnt = 0; ue_f0_f1_cnt != nof_ue_pucch_f0_f1_res_harq.to_uint(); ++ue_f0_f1_cnt) { const auto& cell_res = res_list[ue_f0_f1_cnt + f0_f1_idx_offset]; // Add PUCCH resource to pucch_res_list. @@ -1143,7 +1148,7 @@ bool srs_du::ue_pucch_config_builder( } // Add F2/F3/F4 for HARQ. - for (unsigned ue_f2_f3_f4_cnt = 0; ue_f2_f3_f4_cnt < nof_ue_pucch_f2_f3_f4_res_harq.to_uint(); ++ue_f2_f3_f4_cnt) { + for (unsigned ue_f2_f3_f4_cnt = 0; ue_f2_f3_f4_cnt != nof_ue_pucch_f2_f3_f4_res_harq.to_uint(); ++ue_f2_f3_f4_cnt) { const auto& cell_res = res_list[f2_f3_f4_idx_offset + ue_f2_f3_f4_cnt]; // Add PUCCH resource to pucch_res_list. diff --git a/lib/ran/pucch/pucch_info.cpp b/lib/ran/pucch/pucch_info.cpp index f7e3476760..e0e9e4cc7a 100644 --- a/lib/ran/pucch/pucch_info.cpp +++ b/lib/ran/pucch/pucch_info.cpp @@ -193,7 +193,7 @@ unsigned srsran::get_pucch_format4_max_payload(unsigned nof_symbols, const unsigned nof_dmrs_symbols = get_pucch_format3_4_nof_dmrs_symbols(nof_symbols, intraslot_freq_hopping, additional_dmrs); const unsigned mod_order = pi2_bpsk ? 1 : 2; - const float spreading_factor = occ_length == pucch_f4_occ_len::n2 ? 2.0f : 4.0f; + const float spreading_factor = static_cast(occ_length); // This is derived from the inequality (or constraint) on \f$M^{PUCCH}_{RB,min}\f$, in Section 9.2.5.1, TS 38.213; the // max payloads is obtained by using the floor operation from the maximum PHY capacity, given the PRBs, symbols and @@ -205,7 +205,7 @@ unsigned srsran::get_pucch_format4_max_payload(unsigned nof_symbols, // Get the payload depending on the estimated PUCCH F4 capacity (which we define as the nof bits that the PUCCH F4 can // carry). - // NOTE: Given the max capacity of PUCCH, which is 144 bits (see above), the UCI in PUCCH F4 can have max 1 codeword + // NOTE: Given the max capacity of PUCCH, which is 115 bits (see above), the UCI in PUCCH F4 can have max 1 codeword // (as per Section 6.3.1.2.1, TS 38.212); this implies only 6-bit and 11-bit can be added as CRC to the PUCCH F4 // payload. diff --git a/tests/unittests/du_manager/pucch_resource_generator_test.cpp b/tests/unittests/du_manager/pucch_resource_generator_test.cpp index d7eb206959..cc0b5cd5ff 100644 --- a/tests/unittests/du_manager/pucch_resource_generator_test.cpp +++ b/tests/unittests/du_manager/pucch_resource_generator_test.cpp @@ -98,7 +98,7 @@ std::ostream& operator<<(std::ostream& os, const pucch_gen_params& params) params.f4_intraslot_freq_hopping, params.f4_additional_dmrs, params.f4_pi2_bpsk, - params.f4_occ_length == pucch_f4_occ_len::n2 ? 2 : 4); + static_cast(params.f4_occ_length)); } fmt::print(os, "{} {}", f0_f1_str, f2_f3_f4_str); @@ -163,22 +163,25 @@ class pucch_grid if (res.second_hop_prb.has_value()) { srsran_assert(res_f0.nof_symbols == 2U, "Intra-slot freq. hopping for PUCCH Format 0 requires 2 symbols"); // First hop. - for (unsigned sym_idx = res_f0.starting_sym_idx; sym_idx < res_f0.starting_sym_idx + res_f0.nof_symbols / 2; + for (unsigned sym_idx = res_f0.starting_sym_idx, sym_stop = res_f0.starting_sym_idx + res_f0.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; grid_elem.format = pucch_format::FORMAT_0; grid_elem.element_used = true; } // Second hop. - for (unsigned sym_idx = res_f0.starting_sym_idx + res_f0.nof_symbols / 2; - sym_idx < res_f0.starting_sym_idx + res_f0.nof_symbols; + for (unsigned sym_idx = res_f0.starting_sym_idx + res_f0.nof_symbols / 2, + sym_stop = res_f0.starting_sym_idx + res_f0.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * res.second_hop_prb.value()]; grid_elem.format = pucch_format::FORMAT_0; grid_elem.element_used = true; } } else { - for (unsigned sym_idx = res_f0.starting_sym_idx; sym_idx < res_f0.starting_sym_idx + res_f0.nof_symbols; + for (unsigned sym_idx = res_f0.starting_sym_idx, sym_stop = res_f0.starting_sym_idx + res_f0.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; grid_elem.format = pucch_format::FORMAT_0; @@ -192,7 +195,8 @@ class pucch_grid if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned sym_idx = res_f1.starting_sym_idx; sym_idx < res_f1.starting_sym_idx + res_f1.nof_symbols / 2; + for (unsigned sym_idx = res_f1.starting_sym_idx, sym_stop = res_f1.starting_sym_idx + res_f1.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; grid_elem.format = pucch_format::FORMAT_1; @@ -203,8 +207,9 @@ class pucch_grid grid_elem.allocated_occ_cs_list[occ_cs_idx] = true; } // Second hop. - for (unsigned sym_idx = res_f1.starting_sym_idx + res_f1.nof_symbols / 2; - sym_idx < res_f1.starting_sym_idx + res_f1.nof_symbols; + for (unsigned sym_idx = res_f1.starting_sym_idx + res_f1.nof_symbols / 2, + sym_stop = res_f1.starting_sym_idx + res_f1.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * res.second_hop_prb.value()]; grid_elem.format = pucch_format::FORMAT_1; @@ -215,7 +220,8 @@ class pucch_grid grid_elem.allocated_occ_cs_list[occ_cs_idx] = true; } } else { - for (unsigned sym_idx = res_f1.starting_sym_idx; sym_idx < res_f1.starting_sym_idx + res_f1.nof_symbols; + for (unsigned sym_idx = res_f1.starting_sym_idx, sym_stop = res_f1.starting_sym_idx + res_f1.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; grid_elem.format = pucch_format::FORMAT_1; @@ -233,8 +239,10 @@ class pucch_grid if (res.second_hop_prb.has_value()) { srsran_assert(res_f2.nof_symbols == 2U, "Intra-slot freq. hopping for PUCCH Format 0 requires 2 symbols"); // First hop. - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2.starting_sym_idx; sym_idx < res_f2.starting_sym_idx + res_f2.nof_symbols / 2; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + res_f2.nof_prbs; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f2.starting_sym_idx, sym_stop = res_f2.starting_sym_idx + res_f2.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -242,10 +250,12 @@ class pucch_grid } } // Second hop. - for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + res_f2.nof_prbs; + for (unsigned rb_idx = res.second_hop_prb.value(), rb_stop = res.second_hop_prb.value() + res_f2.nof_prbs; + rb_idx != rb_stop; ++rb_idx) { - for (unsigned sym_idx = res_f2.starting_sym_idx + res_f2.nof_symbols / 2; - sym_idx < res_f2.starting_sym_idx + res_f2.nof_symbols; + for (unsigned sym_idx = res_f2.starting_sym_idx + res_f2.nof_symbols / 2, + sym_stop = res_f2.starting_sym_idx + res_f2.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -253,8 +263,10 @@ class pucch_grid } } } else { - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2.starting_sym_idx; sym_idx < res_f2.starting_sym_idx + res_f2.nof_symbols; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + res_f2.nof_prbs; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f2.starting_sym_idx, sym_stop = res_f2.starting_sym_idx + res_f2.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -268,8 +280,10 @@ class pucch_grid if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f3.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f3.starting_sym_idx; sym_idx < res_f3.starting_sym_idx + res_f3.nof_symbols / 2; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + res_f3.nof_prbs; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f3.starting_sym_idx, sym_stop = res_f3.starting_sym_idx + res_f3.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -277,10 +291,12 @@ class pucch_grid } } // Second hop. - for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + res_f3.nof_prbs; + for (unsigned rb_idx = res.second_hop_prb.value(), rb_stop = res.second_hop_prb.value() + res_f3.nof_prbs; + rb_idx != rb_stop; ++rb_idx) { - for (unsigned sym_idx = res_f3.starting_sym_idx + res_f3.nof_symbols / 2; - sym_idx < res_f3.starting_sym_idx + res_f3.nof_symbols; + for (unsigned sym_idx = res_f3.starting_sym_idx + res_f3.nof_symbols / 2, + sym_stop = res_f3.starting_sym_idx + res_f3.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -288,8 +304,10 @@ class pucch_grid } } } else { - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f3.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f3.starting_sym_idx; sym_idx < res_f3.starting_sym_idx + res_f3.nof_symbols; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + res_f3.nof_prbs; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f3.starting_sym_idx, sym_stop = res_f3.starting_sym_idx + res_f3.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -303,8 +321,9 @@ class pucch_grid if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { - for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + 1; rb_idx != rb_stop; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx, sym_stop = res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -312,9 +331,11 @@ class pucch_grid } } // Second hop. - for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + 1; ++rb_idx) { - for (unsigned sym_idx = res_f4.starting_sym_idx + res_f4.nof_symbols / 2; - sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + for (unsigned rb_idx = res.second_hop_prb.value(), rb_stop = res.second_hop_prb.value() + 1; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx + res_f4.nof_symbols / 2, + sym_stop = res_f4.starting_sym_idx + res_f4.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -322,8 +343,9 @@ class pucch_grid } } } else { - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { - for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + 1; rb_idx != rb_stop; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx, sym_stop = res_f4.starting_sym_idx + res_f4.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { auto& grid_elem = grid[sym_idx + nof_symbols * rb_idx]; grid_elem.element_used = true; @@ -343,7 +365,8 @@ class pucch_grid // Intra-slot frequency hopping. if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned sym_idx = res_f0.starting_sym_idx; sym_idx < res_f0.starting_sym_idx + res_f0.nof_symbols / 2; + for (unsigned sym_idx = res_f0.starting_sym_idx, sym_stop = res_f0.starting_sym_idx + res_f0.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; if (grid_elem.element_used) { @@ -351,8 +374,9 @@ class pucch_grid } } // Second hop. - for (unsigned sym_idx = res_f0.starting_sym_idx + res_f0.nof_symbols / 2; - sym_idx < res_f0.starting_sym_idx + res_f0.nof_symbols; + for (unsigned sym_idx = res_f0.starting_sym_idx + res_f0.nof_symbols / 2, + sym_stop = res_f0.starting_sym_idx + res_f0.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_elem = grid[sym_idx + nof_symbols * res.second_hop_prb.value()]; if (grid_elem.element_used) { @@ -363,7 +387,8 @@ class pucch_grid } // No intra-slot frequency hopping. else { - for (unsigned sym_idx = res_f0.starting_sym_idx; sym_idx < res_f0.starting_sym_idx + res_f0.nof_symbols; + for (unsigned sym_idx = res_f0.starting_sym_idx, sym_stop = res_f0.starting_sym_idx + res_f0.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; if (grid_elem.element_used) { @@ -377,7 +402,8 @@ class pucch_grid // Intra-slot frequency hopping. if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned sym_idx = res_f1.starting_sym_idx; sym_idx < res_f1.starting_sym_idx + res_f1.nof_symbols / 2; + for (unsigned sym_idx = res_f1.starting_sym_idx, sym_stop = res_f1.starting_sym_idx + res_f1.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; if (grid_elem.element_used) { @@ -393,8 +419,9 @@ class pucch_grid } } // Second hop. - for (unsigned sym_idx = res_f1.starting_sym_idx + res_f1.nof_symbols / 2; - sym_idx < res_f1.starting_sym_idx + res_f1.nof_symbols; + for (unsigned sym_idx = res_f1.starting_sym_idx + res_f1.nof_symbols / 2, + sym_stop = res_f1.starting_sym_idx + res_f1.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_elem = grid[sym_idx + nof_symbols * res.second_hop_prb.value()]; if (grid_elem.element_used) { @@ -413,7 +440,8 @@ class pucch_grid } // No intra-slot frequency hopping. else { - for (unsigned sym_idx = res_f1.starting_sym_idx; sym_idx < res_f1.starting_sym_idx + res_f1.nof_symbols; + for (unsigned sym_idx = res_f1.starting_sym_idx, sym_stop = res_f1.starting_sym_idx + res_f1.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_elem = grid[sym_idx + nof_symbols * res.starting_prb]; if (grid_elem.element_used) { @@ -436,9 +464,11 @@ class pucch_grid // Intra-slot frequency hopping. if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2_f3.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2_f3.starting_sym_idx; - sym_idx < res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols / 2; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + res_f2_f3.nof_prbs; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f2_f3.starting_sym_idx, + sym_stop = res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -447,10 +477,12 @@ class pucch_grid } } // Second hop. - for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + res_f2_f3.nof_prbs; + for (unsigned rb_idx = res.second_hop_prb.value(), rb_stop = res.second_hop_prb.value() + res_f2_f3.nof_prbs; + rb_idx != rb_stop; ++rb_idx) { - for (unsigned sym_idx = res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols / 2; - sym_idx < res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols; + for (unsigned sym_idx = res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols / 2, + sym_stop = res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -461,9 +493,11 @@ class pucch_grid } // No intra-slot frequency hopping. else { - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + res_f2_f3.nof_prbs; ++rb_idx) { - for (unsigned sym_idx = res_f2_f3.starting_sym_idx; - sym_idx < res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + res_f2_f3.nof_prbs; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f2_f3.starting_sym_idx, + sym_stop = res_f2_f3.starting_sym_idx + res_f2_f3.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -479,8 +513,9 @@ class pucch_grid // Intra-slot frequency hopping. if (res.second_hop_prb.has_value()) { // First hop. - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { - for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + 1; rb_idx != rb_stop; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx, sym_stop = res_f4.starting_sym_idx + res_f4.nof_symbols / 2; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -488,8 +523,7 @@ class pucch_grid return true; } const unsigned occ_index = static_cast(res_f4.occ_index); - srsran_assert(occ_index < (res_f4.occ_length == pucch_f4_occ_len::n2 ? 2 : 4), - " OCC index exceeds OCC length"); + srsran_assert(occ_index < static_cast(res_f4.occ_length), " OCC index exceeds OCC length"); if (grid_unit.allocated_occ_cs_list[occ_index]) { return true; } @@ -497,9 +531,11 @@ class pucch_grid } } // Second hop. - for (unsigned rb_idx = res.second_hop_prb.value(); rb_idx < res.second_hop_prb.value() + 1; ++rb_idx) { - for (unsigned sym_idx = res_f4.starting_sym_idx + res_f4.nof_symbols / 2; - sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + for (unsigned rb_idx = res.second_hop_prb.value(), rb_stop = res.second_hop_prb.value() + 1; rb_idx != rb_stop; + ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx + res_f4.nof_symbols / 2, + sym_stop = res_f4.starting_sym_idx + res_f4.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -507,8 +543,7 @@ class pucch_grid return true; } const unsigned occ_index = static_cast(res_f4.occ_index); - srsran_assert(occ_index < (res_f4.occ_length == pucch_f4_occ_len::n2 ? 2 : 4), - " OCC index exceeds OCC length"); + srsran_assert(occ_index < static_cast(res_f4.occ_length), " OCC index exceeds OCC length"); if (grid_unit.allocated_occ_cs_list[occ_index]) { return true; } @@ -518,8 +553,9 @@ class pucch_grid } // No intra-slot frequency hopping. else { - for (unsigned rb_idx = res.starting_prb; rb_idx < res.starting_prb + 1; ++rb_idx) { - for (unsigned sym_idx = res_f4.starting_sym_idx; sym_idx < res_f4.starting_sym_idx + res_f4.nof_symbols; + for (unsigned rb_idx = res.starting_prb, rb_stop = res.starting_prb + 1; rb_idx != rb_stop; ++rb_idx) { + for (unsigned sym_idx = res_f4.starting_sym_idx, sym_stop = res_f4.starting_sym_idx + res_f4.nof_symbols; + sym_idx != sym_stop; ++sym_idx) { const auto& grid_unit = grid[sym_idx + nof_symbols * rb_idx]; if (grid_unit.element_used) { @@ -527,8 +563,7 @@ class pucch_grid return true; } const unsigned occ_index = static_cast(res_f4.occ_index); - srsran_assert(occ_index < (res_f4.occ_length == pucch_f4_occ_len::n2 ? 2 : 4), - " OCC index exceeds OCC length"); + srsran_assert(occ_index < static_cast(res_f4.occ_length), " OCC index exceeds OCC length"); if (grid_unit.allocated_occ_cs_list[occ_index]) { return true; } From 1756ca4f614613876be562542f3ba99d816c5d6b Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 6 Dec 2024 13:47:55 +0000 Subject: [PATCH 094/227] cu_up: added NG-U session manager This is used to select gateways in a round-robin fashion. --- lib/cu_up/CMakeLists.txt | 3 +- lib/cu_up/ngu_session_manager.h | 25 +++++++++++ lib/cu_up/ngu_session_manager_impl.cpp | 28 +++++++++++++ lib/cu_up/ngu_session_manager_impl.h | 29 +++++++++++++ tests/unittests/cu_up/CMakeLists.txt | 5 +++ .../cu_up/ngu_session_manager_test.cpp | 24 +++++++++++ .../cu_up/ngu_session_manager_test.h | 41 +++++++++++++++++++ 7 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 lib/cu_up/ngu_session_manager.h create mode 100644 lib/cu_up/ngu_session_manager_impl.cpp create mode 100644 lib/cu_up/ngu_session_manager_impl.h create mode 100644 tests/unittests/cu_up/ngu_session_manager_test.cpp create mode 100644 tests/unittests/cu_up/ngu_session_manager_test.h diff --git a/lib/cu_up/CMakeLists.txt b/lib/cu_up/CMakeLists.txt index a3512e9e26..c4244cd9da 100644 --- a/lib/cu_up/CMakeLists.txt +++ b/lib/cu_up/CMakeLists.txt @@ -11,9 +11,10 @@ set(SOURCES cu_up_factory.cpp cu_up_impl.cpp cu_up_manager_impl.cpp + ue_manager.cpp pdu_session_manager_impl.cpp + ngu_session_manager_impl.cpp routines/initial_cu_up_setup_routine.cpp - ue_manager.cpp ) add_library(srsran_cu_up STATIC ${SOURCES}) diff --git a/lib/cu_up/ngu_session_manager.h b/lib/cu_up/ngu_session_manager.h new file mode 100644 index 0000000000..0506400e55 --- /dev/null +++ b/lib/cu_up/ngu_session_manager.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 "srsran/gtpu/gtpu_gateway.h" + +namespace srsran::srs_cu_up { + +class ngu_session_manager +{ +public: + virtual ~ngu_session_manager() = default; + + virtual const gtpu_tnl_pdu_session& get_next_ngu_gateway() = 0; +}; + +} // namespace srsran::srs_cu_up diff --git a/lib/cu_up/ngu_session_manager_impl.cpp b/lib/cu_up/ngu_session_manager_impl.cpp new file mode 100644 index 0000000000..de4874d0b3 --- /dev/null +++ b/lib/cu_up/ngu_session_manager_impl.cpp @@ -0,0 +1,28 @@ +/* + * + * 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 "ngu_session_manager_impl.h" +#include "srsran/support/srsran_assert.h" + +using namespace srsran; +using namespace srs_cu_up; + +ngu_session_manager_impl::ngu_session_manager_impl(const std::vector>& ngu_gws_) : + ngu_gws(ngu_gws_) +{ + srsran_assert(not ngu_gws.empty(), "NG-U gateways cannot be empty"); +} + +const gtpu_tnl_pdu_session& ngu_session_manager_impl::get_next_ngu_gateway() +{ + uint32_t index = next_gw % ngu_gws.size(); + next_gw++; + return *ngu_gws[index]; +} diff --git a/lib/cu_up/ngu_session_manager_impl.h b/lib/cu_up/ngu_session_manager_impl.h new file mode 100644 index 0000000000..23de45e06c --- /dev/null +++ b/lib/cu_up/ngu_session_manager_impl.h @@ -0,0 +1,29 @@ +/* + * + * 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 "ngu_session_manager.h" + +namespace srsran::srs_cu_up { +class ngu_session_manager_impl : ngu_session_manager +{ +public: + ngu_session_manager_impl(const std::vector>& ngu_gws_); + ~ngu_session_manager_impl() override = default; + + const gtpu_tnl_pdu_session& get_next_ngu_gateway() override; + +private: + const std::vector>& ngu_gws; + uint32_t next_gw = 0; +}; + +} // namespace srsran::srs_cu_up diff --git a/tests/unittests/cu_up/CMakeLists.txt b/tests/unittests/cu_up/CMakeLists.txt index 42d0583ab5..c3575734af 100644 --- a/tests/unittests/cu_up/CMakeLists.txt +++ b/tests/unittests/cu_up/CMakeLists.txt @@ -22,3 +22,8 @@ add_executable(pdu_session_manager_test pdu_session_manager_test.cpp) target_link_libraries(pdu_session_manager_test srsran_cu_up srsran_support e1ap_asn1 srslog gtest gtest_main) target_include_directories(pdu_session_manager_test PRIVATE ${CMAKE_SOURCE_DIR}) gtest_discover_tests(pdu_session_manager_test) + +add_executable(ngu_session_manager_test ngu_session_manager_test.cpp) +target_link_libraries(ngu_session_manager_test srsran_cu_up srsran_support srslog gtest gtest_main) +target_include_directories(ngu_session_manager_test PRIVATE ${CMAKE_SOURCE_DIR}) +gtest_discover_tests(ngu_session_manager_test) diff --git a/tests/unittests/cu_up/ngu_session_manager_test.cpp b/tests/unittests/cu_up/ngu_session_manager_test.cpp new file mode 100644 index 0000000000..e598780098 --- /dev/null +++ b/tests/unittests/cu_up/ngu_session_manager_test.cpp @@ -0,0 +1,24 @@ +/* + * + * 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 "ngu_session_manager_test.h" +#include "cu_up_test_helpers.h" +#include + +using namespace srsran; +using namespace srs_cu_up; + +TEST_F(ngu_session_manager_test, round_robin_gw_selection) {} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/unittests/cu_up/ngu_session_manager_test.h b/tests/unittests/cu_up/ngu_session_manager_test.h new file mode 100644 index 0000000000..9cb7bd847f --- /dev/null +++ b/tests/unittests/cu_up/ngu_session_manager_test.h @@ -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. + * + */ + +#pragma once + +#include "cu_up_test_helpers.h" +#include + +namespace srsran::srs_cu_up { + +/// Fixture base class for PDU session manager tests +class ngu_session_manager_test : public ::testing::Test +{ + void init() + { + srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); + srslog::init(); + auto ngu_gw = std::make_unique(); + ngu_gws.push_back(std::move(ngu_gw)); + + // todo init ngu session manager + } + + void finish() + { + ngu_gws.clear(); + // flush logger after each test + srslog::flush(); + } + + std::vector> ngu_gws; +}; + +} // namespace srsran::srs_cu_up From df4089fa48413ebd6869c12552080678b98ddfea Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 6 Dec 2024 17:01:32 +0000 Subject: [PATCH 095/227] cu_up: use alternating sockets for NG-U reception This was done by passing the a ngu_session_manager so that ngu sessions can be picked in a round-robin fashion. --- lib/cu_up/cu_up_impl.cpp | 30 ++++--- lib/cu_up/cu_up_impl.h | 2 + lib/cu_up/cu_up_manager_impl.cpp | 2 +- lib/cu_up/cu_up_manager_impl.h | 21 ++--- lib/cu_up/ngu_session_manager.h | 3 +- lib/cu_up/ngu_session_manager_impl.h | 5 +- lib/cu_up/pdu_session_manager_impl.cpp | 19 ++-- lib/cu_up/pdu_session_manager_impl.h | 87 ++++++++++--------- lib/cu_up/ue_context.h | 37 ++++---- lib/cu_up/ue_manager.cpp | 4 +- lib/cu_up/ue_manager.h | 55 ++++++------ tests/unittests/cu_up/cu_up_test_helpers.h | 10 +++ .../cu_up/ngu_session_manager_test.cpp | 6 +- .../cu_up/ngu_session_manager_test.h | 10 ++- .../cu_up/pdu_session_manager_test.h | 10 +-- tests/unittests/cu_up/ue_manager_test.cpp | 12 +-- 16 files changed, 171 insertions(+), 142 deletions(-) diff --git a/lib/cu_up/cu_up_impl.cpp b/lib/cu_up/cu_up_impl.cpp index e697b4983b..3bc6bd45ca 100644 --- a/lib/cu_up/cu_up_impl.cpp +++ b/lib/cu_up/cu_up_impl.cpp @@ -10,6 +10,7 @@ #include "cu_up_impl.h" #include "cu_up_manager_impl.h" +#include "ngu_session_manager_impl.h" #include "routines/initial_cu_up_setup_routine.h" #include "srsran/e1ap/cu_up/e1ap_cu_up_factory.h" #include "srsran/gtpu/gtpu_demux_factory.h" @@ -38,18 +39,18 @@ static cu_up_manager_impl_config generate_cu_up_manager_impl_config(const cu_up_ } static cu_up_manager_impl_dependencies -generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, - e1ap_interface& e1ap, - gtpu_network_gateway_adapter& gtpu_gw_adapter, - gtpu_demux& ngu_demux, - const std::vector>& ngu_gws, - gtpu_teid_pool& n3_teid_allocator, - gtpu_teid_pool& f1u_teid_allocator) +generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, + e1ap_interface& e1ap, + gtpu_network_gateway_adapter& gtpu_gw_adapter, + gtpu_demux& ngu_demux, + ngu_session_manager& ngu_session_mngr, + gtpu_teid_pool& n3_teid_allocator, + gtpu_teid_pool& f1u_teid_allocator) { return {e1ap, gtpu_gw_adapter, ngu_demux, - ngu_gws, + ngu_session_mngr, n3_teid_allocator, f1u_teid_allocator, *dependencies.exec_mapper, @@ -95,6 +96,7 @@ cu_up::cu_up(const cu_up_config& config_, const cu_up_dependencies& dependencies } ngu_sessions.push_back(std::move(ngu_session)); } + ngu_session_mngr = std::make_unique(ngu_sessions); // Connect GTPU GW adapter to NG-U session in order to send UL PDUs. // We use the first UDP GW for UL. @@ -117,10 +119,14 @@ cu_up::cu_up(const cu_up_config& config_, const cu_up_dependencies& dependencies dependencies.exec_mapper->ctrl_executor()); /// > Create CU-UP manager - cu_up_mng = std::make_unique( - generate_cu_up_manager_impl_config(cfg), - generate_cu_up_manager_impl_dependencies( - dependencies, *e1ap, gtpu_gw_adapter, *ngu_demux, ngu_sessions, *n3_teid_allocator, *f1u_teid_allocator)); + cu_up_mng = std::make_unique(generate_cu_up_manager_impl_config(cfg), + generate_cu_up_manager_impl_dependencies(dependencies, + *e1ap, + gtpu_gw_adapter, + *ngu_demux, + *ngu_session_mngr, + *n3_teid_allocator, + *f1u_teid_allocator)); /// > Connect E1AP to CU-UP manager e1ap_cu_up_mng_adapter.connect_cu_up_manager(*cu_up_mng); diff --git a/lib/cu_up/cu_up_impl.h b/lib/cu_up/cu_up_impl.h index a90c3e9ece..dce4302d9e 100644 --- a/lib/cu_up/cu_up_impl.h +++ b/lib/cu_up/cu_up_impl.h @@ -13,6 +13,7 @@ #include "adapters/e1ap_adapters.h" #include "adapters/gtpu_adapters.h" #include "adapters/gw_adapters.h" +#include "ngu_session_manager.h" #include "ue_manager.h" #include "srsran/cu_up/cu_up.h" #include "srsran/cu_up/cu_up_config.h" @@ -63,6 +64,7 @@ class cu_up final : public cu_up_interface // Components std::atomic e1ap_connected = {false}; std::unique_ptr e1ap; + std::unique_ptr ngu_session_mngr; std::vector> ngu_sessions; std::unique_ptr ngu_demux; std::unique_ptr ngu_echo; diff --git a/lib/cu_up/cu_up_manager_impl.cpp b/lib/cu_up/cu_up_manager_impl.cpp index a532c2e4b4..37e0e4856d 100644 --- a/lib/cu_up/cu_up_manager_impl.cpp +++ b/lib/cu_up/cu_up_manager_impl.cpp @@ -39,7 +39,7 @@ static ue_manager_dependencies generate_ue_manager_dependencies(const cu_up_mana return {dependencies.e1ap, dependencies.timers, dependencies.f1u_gateway, - dependencies.ngu_gws, + dependencies.ngu_session_mngr, dependencies.gtpu_gw_adapter, dependencies.ngu_demux, dependencies.n3_teid_allocator, diff --git a/lib/cu_up/cu_up_manager_impl.h b/lib/cu_up/cu_up_manager_impl.h index fee21a50f6..7cb51192a7 100644 --- a/lib/cu_up/cu_up_manager_impl.h +++ b/lib/cu_up/cu_up_manager_impl.h @@ -11,6 +11,7 @@ #pragma once #include "adapters/gtpu_adapters.h" +#include "ngu_session_manager.h" #include "ue_manager.h" #include "srsran/cu_up/cu_up_config.h" #include "srsran/cu_up/cu_up_manager.h" @@ -29,16 +30,16 @@ struct cu_up_manager_impl_config { /// CU-UP manager implementation dependencies. struct cu_up_manager_impl_dependencies { - e1ap_interface& e1ap; - gtpu_network_gateway_adapter& gtpu_gw_adapter; - gtpu_demux& ngu_demux; - const std::vector>& ngu_gws; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_mapper; - f1u_cu_up_gateway& f1u_gateway; - timer_manager& timers; - dlt_pcap& gtpu_pcap; + e1ap_interface& e1ap; + gtpu_network_gateway_adapter& gtpu_gw_adapter; + gtpu_demux& ngu_demux; + ngu_session_manager& ngu_session_mngr; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_mapper; + f1u_cu_up_gateway& f1u_gateway; + timer_manager& timers; + dlt_pcap& gtpu_pcap; }; class cu_up_manager_impl final : public cu_up_manager diff --git a/lib/cu_up/ngu_session_manager.h b/lib/cu_up/ngu_session_manager.h index 0506400e55..c076339c96 100644 --- a/lib/cu_up/ngu_session_manager.h +++ b/lib/cu_up/ngu_session_manager.h @@ -17,8 +17,7 @@ namespace srsran::srs_cu_up { class ngu_session_manager { public: - virtual ~ngu_session_manager() = default; - + virtual ~ngu_session_manager() = default; virtual const gtpu_tnl_pdu_session& get_next_ngu_gateway() = 0; }; diff --git a/lib/cu_up/ngu_session_manager_impl.h b/lib/cu_up/ngu_session_manager_impl.h index 23de45e06c..c316b84e61 100644 --- a/lib/cu_up/ngu_session_manager_impl.h +++ b/lib/cu_up/ngu_session_manager_impl.h @@ -13,11 +13,12 @@ #include "ngu_session_manager.h" namespace srsran::srs_cu_up { -class ngu_session_manager_impl : ngu_session_manager + +class ngu_session_manager_impl : public ngu_session_manager { public: - ngu_session_manager_impl(const std::vector>& ngu_gws_); ~ngu_session_manager_impl() override = default; + explicit ngu_session_manager_impl(const std::vector>& ngu_gws_); const gtpu_tnl_pdu_session& get_next_ngu_gateway() override; diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 1739a211f8..56292b2094 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -27,12 +27,12 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t const n3_interface_config& n3_config_, const cu_up_test_mode_config& test_mode_config_, cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - const std::vector>& ngu_gws_, + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + ngu_session_manager& ngu_session_mngr_, gtpu_teid_pool& n3_teid_allocator_, gtpu_teid_pool& f1u_teid_allocator_, gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, @@ -62,7 +62,7 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t crypto_exec(crypto_exec_), gtpu_pcap(gtpu_pcap_), f1u_gw(f1u_gw_), - ngu_gws(ngu_gws_) + ngu_session_mngr(ngu_session_mngr_) { } @@ -105,8 +105,9 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ // Advertise either local or external IP address of N3 interface // TODO select correct GW based on slice or UE info. - std::string n3_addr; - if (not ngu_gws[0]->get_bind_address(n3_addr)) { + std::string n3_addr; + const gtpu_tnl_pdu_session& n3_gw = ngu_session_mngr.get_next_ngu_gateway(); + if (not n3_gw.get_bind_address(n3_addr)) { report_error("Could not get NG-U bind address to report to core."); } pdu_session_result.gtp_tunnel = diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index c40403c3c1..fafa00ceab 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -11,6 +11,7 @@ #pragma once #include "cu_up_ue_logger.h" +#include "ngu_session_manager.h" #include "pdu_session.h" #include "pdu_session_manager.h" #include "srsran/cu_up/cu_up_config.h" @@ -30,27 +31,27 @@ namespace srs_cu_up { class pdu_session_manager_impl final : public pdu_session_manager_ctrl { public: - pdu_session_manager_impl(ue_index_t ue_index_, - std::map qos_cfg_, - const security::sec_as_config& security_info_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - const std::vector>& ngu_gws_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - task_executor& ue_dl_exec_, - task_executor& ue_ul_exec_, - task_executor& ue_ctrl_exec_, - task_executor& crypto_exec_, - dlt_pcap& gtpu_pcap_); + pdu_session_manager_impl(ue_index_t ue_index_, + std::map qos_cfg_, + const security::sec_as_config& security_info_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + cu_up_ue_logger& logger_, + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + ngu_session_manager& ngu_session_mngr_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, + gtpu_demux_ctrl& gtpu_rx_demux_, + task_executor& ue_dl_exec_, + task_executor& ue_ul_exec_, + task_executor& ue_ctrl_exec_, + task_executor& crypto_exec_, + dlt_pcap& gtpu_pcap_); pdu_session_setup_result setup_pdu_session(const e1ap_pdu_session_res_to_setup_item& session) override; pdu_session_modification_result modify_pdu_session(const e1ap_pdu_session_res_to_modify_item& session, @@ -73,28 +74,28 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl drb_setup_result handle_drb_to_setup_item(pdu_session& new_session, const e1ap_drb_to_setup_item_ng_ran& drb_to_setup); - ue_index_t ue_index; - const std::map qos_cfg; - const security::sec_as_config& security_info; - const n3_interface_config& n3_config; - cu_up_test_mode_config test_mode_config; - cu_up_ue_logger& logger; - unique_timer& ue_inactivity_timer; - timer_factory ue_dl_timer_factory; - timer_factory ue_ul_timer_factory; - timer_factory ue_ctrl_timer_factory; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - gtpu_demux_ctrl& gtpu_rx_demux; - task_executor& ue_dl_exec; - task_executor& ue_ul_exec; - task_executor& ue_ctrl_exec; - task_executor& crypto_exec; - dlt_pcap& gtpu_pcap; - f1u_cu_up_gateway& f1u_gw; - const std::vector>& ngu_gws; - std::map> pdu_sessions; // key is pdu_session_id + ue_index_t ue_index; + const std::map qos_cfg; + const security::sec_as_config& security_info; + const n3_interface_config& n3_config; + cu_up_test_mode_config test_mode_config; + cu_up_ue_logger& logger; + unique_timer& ue_inactivity_timer; + timer_factory ue_dl_timer_factory; + timer_factory ue_ul_timer_factory; + timer_factory ue_ctrl_timer_factory; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + gtpu_demux_ctrl& gtpu_rx_demux; + task_executor& ue_dl_exec; + task_executor& ue_ul_exec; + task_executor& ue_ctrl_exec; + task_executor& crypto_exec; + dlt_pcap& gtpu_pcap; + f1u_cu_up_gateway& f1u_gw; + ngu_session_manager& ngu_session_mngr; + std::map> pdu_sessions; // key is pdu_session_id }; } // namespace srs_cu_up diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index e82a93a45c..9cf83c11c1 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -11,6 +11,7 @@ #pragma once #include "cu_up_ue_logger.h" +#include "ngu_session_manager.h" #include "pdu_session_manager.h" #include "pdu_session_manager_impl.h" #include "srsran/cu_up/cu_up_types.h" @@ -37,23 +38,23 @@ struct ue_context_cfg { class ue_context : public pdu_session_manager_ctrl { public: - ue_context(ue_index_t index_, - ue_context_cfg cfg_, - e1ap_control_message_handler& e1ap_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - std::unique_ptr ue_exec_mapper_, - fifo_async_task_scheduler& task_sched_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - const std::vector>& ngu_gws_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - dlt_pcap& gtpu_pcap) : + ue_context(ue_index_t index_, + ue_context_cfg cfg_, + e1ap_control_message_handler& e1ap_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + std::unique_ptr ue_exec_mapper_, + fifo_async_task_scheduler& task_sched_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + ngu_session_manager& ngu_session_mngr_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, + gtpu_demux_ctrl& gtpu_rx_demux_, + dlt_pcap& gtpu_pcap) : task_sched(task_sched_), ue_exec_mapper(std::move(ue_exec_mapper_)), index(index_), @@ -71,7 +72,7 @@ class ue_context : public pdu_session_manager_ctrl ue_ul_timer_factory_, ue_ctrl_timer_factory_, f1u_gw_, - ngu_gws_, + ngu_session_mngr_, n3_teid_allocator_, f1u_teid_allocator_, gtpu_tx_notifier_, diff --git a/lib/cu_up/ue_manager.cpp b/lib/cu_up/ue_manager.cpp index dcf40142de..5598762db5 100644 --- a/lib/cu_up/ue_manager.cpp +++ b/lib/cu_up/ue_manager.cpp @@ -19,7 +19,7 @@ ue_manager::ue_manager(const ue_manager_config& config, const ue_manager_depende test_mode_config(config.test_mode_config), e1ap(dependencies.e1ap), f1u_gw(dependencies.f1u_gw), - ngu_gws(dependencies.ngu_gws), + ngu_session_mngr(dependencies.ngu_session_mngr), gtpu_tx_notifier(dependencies.gtpu_tx_notifier), gtpu_rx_demux(dependencies.gtpu_rx_demux), n3_teid_allocator(dependencies.n3_teid_allocator), @@ -77,7 +77,7 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) ue_ul_timer_factory, ue_ctrl_timer_factory, f1u_gw, - ngu_gws, + ngu_session_mngr, n3_teid_allocator, f1u_teid_allocator, gtpu_tx_notifier, diff --git a/lib/cu_up/ue_manager.h b/lib/cu_up/ue_manager.h index 1d2b71eaea..116a63c297 100644 --- a/lib/cu_up/ue_manager.h +++ b/lib/cu_up/ue_manager.h @@ -10,6 +10,7 @@ #pragma once +#include "ngu_session_manager.h" #include "ue_manager_interfaces.h" #include "srsran/f1u/cu_up/f1u_gateway.h" #include "srsran/gtpu/gtpu_teid_pool.h" @@ -29,17 +30,17 @@ struct ue_manager_config { /// UE manager dependencies. struct ue_manager_dependencies { - e1ap_control_message_handler& e1ap; - timer_manager& timers; - f1u_cu_up_gateway& f1u_gw; - const std::vector>& ngu_gws; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - dlt_pcap& gtpu_pcap; - srslog::basic_logger& logger; + e1ap_control_message_handler& e1ap; + timer_manager& timers; + f1u_cu_up_gateway& f1u_gw; + ngu_session_manager& ngu_session_mngr; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + dlt_pcap& gtpu_pcap; + srslog::basic_logger& logger; }; class ue_manager : public ue_manager_ctrl @@ -63,22 +64,22 @@ class ue_manager : public ue_manager_ctrl /// \return The UE index. ue_index_t get_next_ue_index(); - const n3_interface_config& n3_config; - const cu_up_test_mode_config& test_mode_config; - e1ap_control_message_handler& e1ap; - f1u_cu_up_gateway& f1u_gw; - const std::vector>& ngu_gws; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - task_executor& ctrl_executor; - dlt_pcap& gtpu_pcap; - timer_manager& timers; - ue_db_t ue_db; - ue_task_schedulers_t ue_task_schedulers; - srslog::basic_logger& logger; + const n3_interface_config& n3_config; + const cu_up_test_mode_config& test_mode_config; + e1ap_control_message_handler& e1ap; + f1u_cu_up_gateway& f1u_gw; + ngu_session_manager& ngu_session_mngr; + gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + task_executor& ctrl_executor; + dlt_pcap& gtpu_pcap; + timer_manager& timers; + ue_db_t ue_db; + ue_task_schedulers_t ue_task_schedulers; + srslog::basic_logger& logger; }; } // namespace srs_cu_up diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index aae06d1b48..576228ccf5 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -10,6 +10,7 @@ #pragma once +#include "lib/cu_up/ngu_session_manager.h" #include "srsran/asn1/e1ap/e1ap_pdu_contents.h" #include "srsran/cu_up/cu_up_executor_mapper.h" #include "srsran/e1ap/common/e1ap_common.h" @@ -270,6 +271,15 @@ class dummy_ngu_gateway final : public gtpu_tnl_pdu_session void on_new_pdu(byte_buffer pdu, const sockaddr_storage& src_addr) override {} }; +class dummy_ngu_session_manager final : public srs_cu_up::ngu_session_manager +{ +public: + const gtpu_tnl_pdu_session& get_next_ngu_gateway() override { return ngu_gw; }; + +private: + dummy_ngu_gateway ngu_gw; +}; + class dummy_e1ap final : public srs_cu_up::e1ap_control_message_handler { public: diff --git a/tests/unittests/cu_up/ngu_session_manager_test.cpp b/tests/unittests/cu_up/ngu_session_manager_test.cpp index e598780098..e8af8f90dd 100644 --- a/tests/unittests/cu_up/ngu_session_manager_test.cpp +++ b/tests/unittests/cu_up/ngu_session_manager_test.cpp @@ -9,13 +9,15 @@ */ #include "ngu_session_manager_test.h" -#include "cu_up_test_helpers.h" #include using namespace srsran; using namespace srs_cu_up; -TEST_F(ngu_session_manager_test, round_robin_gw_selection) {} +TEST_F(ngu_session_manager_test, mngr_creation) +{ + ngu_session_mngr = std::make_unique(ngu_gws); +} int main(int argc, char** argv) { diff --git a/tests/unittests/cu_up/ngu_session_manager_test.h b/tests/unittests/cu_up/ngu_session_manager_test.h index 9cb7bd847f..46ff956d2f 100644 --- a/tests/unittests/cu_up/ngu_session_manager_test.h +++ b/tests/unittests/cu_up/ngu_session_manager_test.h @@ -11,6 +11,7 @@ #pragma once #include "cu_up_test_helpers.h" +#include "lib/cu_up/ngu_session_manager_impl.h" #include namespace srsran::srs_cu_up { @@ -18,7 +19,7 @@ namespace srsran::srs_cu_up { /// Fixture base class for PDU session manager tests class ngu_session_manager_test : public ::testing::Test { - void init() + void SetUp() override { srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); srslog::init(); @@ -26,15 +27,20 @@ class ngu_session_manager_test : public ::testing::Test ngu_gws.push_back(std::move(ngu_gw)); // todo init ngu session manager + ngu_session_mngr = std::make_unique(ngu_gws); } - void finish() + void TearDown() override { ngu_gws.clear(); + ngu_session_mngr.reset(); + // flush logger after each test srslog::flush(); } +protected: + std::unique_ptr ngu_session_mngr; std::vector> ngu_gws; }; diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 681f65066c..04c68dbb36 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -22,7 +22,7 @@ namespace srs_cu_up { class pdu_session_manager_test_base { protected: - virtual ~pdu_session_manager_test_base() = default; + ~pdu_session_manager_test_base() = default; void init() { @@ -36,8 +36,7 @@ class pdu_session_manager_test_base f1u_gw = std::make_unique(f1u_bearer); n3_allocator = std::make_unique(); f1u_allocator = std::make_unique(); - auto ngu_gw = std::make_unique(); - ngu_gws.push_back(std::move(ngu_gw)); + ngu_session_mngr = std::make_unique(); // create DUT object ue_inactivity_timer = timers_factory.create_timer(); @@ -58,7 +57,7 @@ class pdu_session_manager_test_base timers_factory, timers_factory, *f1u_gw, - ngu_gws, + *ngu_session_mngr, *n3_allocator, *f1u_allocator, *gtpu_tx_notifier, @@ -72,7 +71,6 @@ class pdu_session_manager_test_base void finish() { - ngu_gws.clear(); // flush logger after each test srslog::flush(); } @@ -85,7 +83,7 @@ class pdu_session_manager_test_base std::unique_ptr gtpu_tx_notifier; dummy_inner_f1u_bearer f1u_bearer; std::unique_ptr f1u_gw; - std::vector> ngu_gws; + std::unique_ptr ngu_session_mngr; std::unique_ptr n3_allocator; std::unique_ptr f1u_allocator; std::unique_ptr pdu_session_mng; diff --git a/tests/unittests/cu_up/ue_manager_test.cpp b/tests/unittests/cu_up/ue_manager_test.cpp index 64167d86af..690f4da042 100644 --- a/tests/unittests/cu_up/ue_manager_test.cpp +++ b/tests/unittests/cu_up/ue_manager_test.cpp @@ -33,11 +33,12 @@ class ue_manager_test : public ::testing::Test gtpu_f1u_allocator = std::make_unique(); gtpu_tx_notifier = std::make_unique(); f1u_gw = std::make_unique(f1u_bearer); - auto ngu_gw = std::make_unique(); - ngu_gws.push_back(std::move(ngu_gw)); - e1ap = std::make_unique(); + e1ap = std::make_unique(); + + ngu_session_mngr = std::make_unique(); cu_up_exec_mapper = std::make_unique(&worker); + // Create UE cfg ue_cfg = {security::sec_as_config{}, activity_notification_level_t::ue, std::chrono::seconds(0)}; @@ -46,7 +47,7 @@ class ue_manager_test : public ::testing::Test ue_manager_dependencies{*e1ap, timers, *f1u_gw, - ngu_gws, + *ngu_session_mngr, *gtpu_tx_notifier, *gtpu_rx_demux, *gtpu_n3_allocator, @@ -58,7 +59,6 @@ class ue_manager_test : public ::testing::Test void TearDown() override { - ngu_gws.clear(); // flush logger after each test srslog::flush(); } @@ -72,7 +72,7 @@ class ue_manager_test : public ::testing::Test dummy_inner_f1u_bearer f1u_bearer; null_dlt_pcap gtpu_pcap; std::unique_ptr f1u_gw; - std::vector> ngu_gws; + std::unique_ptr ngu_session_mngr; timer_manager timers; ue_context_cfg ue_cfg; std::unique_ptr ue_mng; From 913a1a6ee43a3f5fc680c52dc7ed4a2598b6168f Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 11 Dec 2024 15:58:02 +0000 Subject: [PATCH 096/227] cu_up: added rr gw selection unit test --- tests/unittests/cu_up/cu_up_test_helpers.h | 8 ++++++- .../cu_up/ngu_session_manager_test.cpp | 24 ++++++++++++++++++- .../cu_up/ngu_session_manager_test.h | 10 ++++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index 576228ccf5..fd80ca6047 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -258,9 +258,13 @@ class dummy_f1u_gateway final : public f1u_cu_up_gateway class dummy_ngu_gateway final : public gtpu_tnl_pdu_session { +public: + void set_bind_address(const std::string& ip_address) { ip_addr = ip_address; } + +private: bool get_bind_address(std::string& ip_address) const override { - ip_address = "127.0.0.2"; + ip_address = ip_addr; return true; } @@ -269,6 +273,8 @@ class dummy_ngu_gateway final : public gtpu_tnl_pdu_session void handle_pdu(byte_buffer pdu, const sockaddr_storage& dest_addr) override {} void on_new_pdu(byte_buffer pdu, const sockaddr_storage& src_addr) override {} + + std::string ip_addr = "127.0.0.2"; }; class dummy_ngu_session_manager final : public srs_cu_up::ngu_session_manager diff --git a/tests/unittests/cu_up/ngu_session_manager_test.cpp b/tests/unittests/cu_up/ngu_session_manager_test.cpp index e8af8f90dd..c0d9381409 100644 --- a/tests/unittests/cu_up/ngu_session_manager_test.cpp +++ b/tests/unittests/cu_up/ngu_session_manager_test.cpp @@ -16,7 +16,29 @@ using namespace srs_cu_up; TEST_F(ngu_session_manager_test, mngr_creation) { - ngu_session_mngr = std::make_unique(ngu_gws); + ASSERT_NE(ngu_session_mngr, nullptr); +} + +TEST_F(ngu_session_manager_test, rr_session_selection) +{ + { + const auto& ngu_gw = ngu_session_mngr->get_next_ngu_gateway(); + std::string ip_addr; + ASSERT_TRUE(ngu_gw.get_bind_address(ip_addr)); + ASSERT_EQ(ip_addr, "127.0.0.1"); + } + { + const auto& ngu_gw = ngu_session_mngr->get_next_ngu_gateway(); + std::string ip_addr; + ASSERT_TRUE(ngu_gw.get_bind_address(ip_addr)); + ASSERT_EQ(ip_addr, "127.0.0.2"); + } + { + const auto& ngu_gw = ngu_session_mngr->get_next_ngu_gateway(); + std::string ip_addr; + ASSERT_TRUE(ngu_gw.get_bind_address(ip_addr)); + ASSERT_EQ(ip_addr, "127.0.0.1"); + } } int main(int argc, char** argv) diff --git a/tests/unittests/cu_up/ngu_session_manager_test.h b/tests/unittests/cu_up/ngu_session_manager_test.h index 46ff956d2f..389e355101 100644 --- a/tests/unittests/cu_up/ngu_session_manager_test.h +++ b/tests/unittests/cu_up/ngu_session_manager_test.h @@ -23,8 +23,14 @@ class ngu_session_manager_test : public ::testing::Test { srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); srslog::init(); - auto ngu_gw = std::make_unique(); - ngu_gws.push_back(std::move(ngu_gw)); + + unsigned nof_gws = 2; + for (unsigned i = 0; i < nof_gws; i++) { + auto ngu_gw = std::make_unique(); + std::string addr = fmt::format("127.0.0.{}", 1 + i); + ngu_gw->set_bind_address(addr); + ngu_gws.push_back(std::move(ngu_gw)); + } // todo init ngu session manager ngu_session_mngr = std::make_unique(ngu_gws); From 4411d97b817298a025c1fbeb6d14b7ce537b36d5 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 9 Dec 2024 14:55:34 +0000 Subject: [PATCH 097/227] cu_up: create one gtpu_to_udp_adapter per pdu session --- lib/cu_up/cu_up_impl.cpp | 27 ++++------ lib/cu_up/cu_up_manager_impl.cpp | 1 - lib/cu_up/cu_up_manager_impl.h | 19 ++++--- lib/cu_up/ngu_session_manager.h | 4 +- lib/cu_up/ngu_session_manager_impl.cpp | 2 +- lib/cu_up/ngu_session_manager_impl.h | 2 +- lib/cu_up/pdu_session.h | 3 ++ lib/cu_up/pdu_session_manager_impl.cpp | 37 +++++++------ lib/cu_up/pdu_session_manager_impl.h | 2 - lib/cu_up/ue_context.h | 34 ++++++------ lib/cu_up/ue_manager.cpp | 2 - lib/cu_up/ue_manager.h | 52 +++++++++---------- tests/unittests/cu_up/cu_up_test_helpers.h | 2 +- .../cu_up/pdu_session_manager_test.h | 1 - tests/unittests/cu_up/ue_manager_test.cpp | 1 - 15 files changed, 86 insertions(+), 103 deletions(-) diff --git a/lib/cu_up/cu_up_impl.cpp b/lib/cu_up/cu_up_impl.cpp index 3bc6bd45ca..e5b882a1c4 100644 --- a/lib/cu_up/cu_up_impl.cpp +++ b/lib/cu_up/cu_up_impl.cpp @@ -38,17 +38,14 @@ static cu_up_manager_impl_config generate_cu_up_manager_impl_config(const cu_up_ return {config.qos, config.n3_cfg, config.test_mode_cfg}; } -static cu_up_manager_impl_dependencies -generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, - e1ap_interface& e1ap, - gtpu_network_gateway_adapter& gtpu_gw_adapter, - gtpu_demux& ngu_demux, - ngu_session_manager& ngu_session_mngr, - gtpu_teid_pool& n3_teid_allocator, - gtpu_teid_pool& f1u_teid_allocator) +static cu_up_manager_impl_dependencies generate_cu_up_manager_impl_dependencies(const cu_up_dependencies& dependencies, + e1ap_interface& e1ap, + gtpu_demux& ngu_demux, + ngu_session_manager& ngu_session_mngr, + gtpu_teid_pool& n3_teid_allocator, + gtpu_teid_pool& f1u_teid_allocator) { return {e1ap, - gtpu_gw_adapter, ngu_demux, ngu_session_mngr, n3_teid_allocator, @@ -119,14 +116,10 @@ cu_up::cu_up(const cu_up_config& config_, const cu_up_dependencies& dependencies dependencies.exec_mapper->ctrl_executor()); /// > Create CU-UP manager - cu_up_mng = std::make_unique(generate_cu_up_manager_impl_config(cfg), - generate_cu_up_manager_impl_dependencies(dependencies, - *e1ap, - gtpu_gw_adapter, - *ngu_demux, - *ngu_session_mngr, - *n3_teid_allocator, - *f1u_teid_allocator)); + cu_up_mng = std::make_unique( + generate_cu_up_manager_impl_config(cfg), + generate_cu_up_manager_impl_dependencies( + dependencies, *e1ap, *ngu_demux, *ngu_session_mngr, *n3_teid_allocator, *f1u_teid_allocator)); /// > Connect E1AP to CU-UP manager e1ap_cu_up_mng_adapter.connect_cu_up_manager(*cu_up_mng); diff --git a/lib/cu_up/cu_up_manager_impl.cpp b/lib/cu_up/cu_up_manager_impl.cpp index 37e0e4856d..c4c22abb8c 100644 --- a/lib/cu_up/cu_up_manager_impl.cpp +++ b/lib/cu_up/cu_up_manager_impl.cpp @@ -40,7 +40,6 @@ static ue_manager_dependencies generate_ue_manager_dependencies(const cu_up_mana dependencies.timers, dependencies.f1u_gateway, dependencies.ngu_session_mngr, - dependencies.gtpu_gw_adapter, dependencies.ngu_demux, dependencies.n3_teid_allocator, dependencies.f1u_teid_allocator, diff --git a/lib/cu_up/cu_up_manager_impl.h b/lib/cu_up/cu_up_manager_impl.h index 7cb51192a7..8e388dab77 100644 --- a/lib/cu_up/cu_up_manager_impl.h +++ b/lib/cu_up/cu_up_manager_impl.h @@ -30,16 +30,15 @@ struct cu_up_manager_impl_config { /// CU-UP manager implementation dependencies. struct cu_up_manager_impl_dependencies { - e1ap_interface& e1ap; - gtpu_network_gateway_adapter& gtpu_gw_adapter; - gtpu_demux& ngu_demux; - ngu_session_manager& ngu_session_mngr; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_mapper; - f1u_cu_up_gateway& f1u_gateway; - timer_manager& timers; - dlt_pcap& gtpu_pcap; + e1ap_interface& e1ap; + gtpu_demux& ngu_demux; + ngu_session_manager& ngu_session_mngr; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_mapper; + f1u_cu_up_gateway& f1u_gateway; + timer_manager& timers; + dlt_pcap& gtpu_pcap; }; class cu_up_manager_impl final : public cu_up_manager diff --git a/lib/cu_up/ngu_session_manager.h b/lib/cu_up/ngu_session_manager.h index c076339c96..278df5d878 100644 --- a/lib/cu_up/ngu_session_manager.h +++ b/lib/cu_up/ngu_session_manager.h @@ -17,8 +17,8 @@ namespace srsran::srs_cu_up { class ngu_session_manager { public: - virtual ~ngu_session_manager() = default; - virtual const gtpu_tnl_pdu_session& get_next_ngu_gateway() = 0; + virtual ~ngu_session_manager() = default; + virtual gtpu_tnl_pdu_session& get_next_ngu_gateway() = 0; }; } // namespace srsran::srs_cu_up diff --git a/lib/cu_up/ngu_session_manager_impl.cpp b/lib/cu_up/ngu_session_manager_impl.cpp index de4874d0b3..4b660f19f2 100644 --- a/lib/cu_up/ngu_session_manager_impl.cpp +++ b/lib/cu_up/ngu_session_manager_impl.cpp @@ -20,7 +20,7 @@ ngu_session_manager_impl::ngu_session_manager_impl(const std::vector>& ngu_gws_); - const gtpu_tnl_pdu_session& get_next_ngu_gateway() override; + gtpu_tnl_pdu_session& get_next_ngu_gateway() override; private: const std::vector>& ngu_gws; diff --git a/lib/cu_up/pdu_session.h b/lib/cu_up/pdu_session.h index 906bb292be..917bc97fd4 100644 --- a/lib/cu_up/pdu_session.h +++ b/lib/cu_up/pdu_session.h @@ -69,6 +69,9 @@ struct pdu_session { gtpu_sdap_adapter gtpu_to_sdap_adapter; sdap_gtpu_adapter sdap_to_gtpu_adapter; + // Adapters between GTP-U and UDP GW + gtpu_network_gateway_adapter gtpu_to_udp_adapter; + pdcp_f1u_adapter pdcp_to_f1u_adapter; pdu_session_id_t pdu_session_id; //< PDU session ID (0-255) std::string session_type; diff --git a/lib/cu_up/pdu_session_manager_impl.cpp b/lib/cu_up/pdu_session_manager_impl.cpp index 56292b2094..79c25774d9 100644 --- a/lib/cu_up/pdu_session_manager_impl.cpp +++ b/lib/cu_up/pdu_session_manager_impl.cpp @@ -27,21 +27,20 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t const n3_interface_config& n3_config_, const cu_up_test_mode_config& test_mode_config_, cu_up_ue_logger& logger_, - unique_timer& ue_inactivity_timer_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - ngu_session_manager& ngu_session_mngr_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - task_executor& ue_dl_exec_, - task_executor& ue_ul_exec_, - task_executor& ue_ctrl_exec_, - task_executor& crypto_exec_, - dlt_pcap& gtpu_pcap_) : + unique_timer& ue_inactivity_timer_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + ngu_session_manager& ngu_session_mngr_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_demux_ctrl& gtpu_rx_demux_, + task_executor& ue_dl_exec_, + task_executor& ue_ul_exec_, + task_executor& ue_ctrl_exec_, + task_executor& crypto_exec_, + dlt_pcap& gtpu_pcap_) : ue_index(ue_index_), qos_cfg(std::move(qos_cfg_)), security_info(security_info_), @@ -52,7 +51,6 @@ pdu_session_manager_impl::pdu_session_manager_impl(ue_index_t ue_dl_timer_factory(ue_dl_timer_factory_), ue_ul_timer_factory(ue_ul_timer_factory_), ue_ctrl_timer_factory(ue_ctrl_timer_factory_), - gtpu_tx_notifier(gtpu_tx_notifier_), n3_teid_allocator(n3_teid_allocator_), f1u_teid_allocator(f1u_teid_allocator_), gtpu_rx_demux(gtpu_rx_demux_), @@ -105,8 +103,8 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ // Advertise either local or external IP address of N3 interface // TODO select correct GW based on slice or UE info. - std::string n3_addr; - const gtpu_tnl_pdu_session& n3_gw = ngu_session_mngr.get_next_ngu_gateway(); + std::string n3_addr; + gtpu_tnl_pdu_session& n3_gw = ngu_session_mngr.get_next_ngu_gateway(); if (not n3_gw.get_bind_address(n3_addr)) { report_error("Could not get NG-U bind address to report to core."); } @@ -128,7 +126,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ msg.cfg.rx.warn_expired_t_reordering = n3_config.warn_on_drop; msg.cfg.rx.test_mode = test_mode_config.enabled; msg.rx_lower = &new_session->gtpu_to_sdap_adapter; - msg.tx_upper = >pu_tx_notifier; + msg.tx_upper = &new_session->gtpu_to_udp_adapter; msg.gtpu_pcap = >pu_pcap; msg.ue_dl_timer_factory = ue_dl_timer_factory; new_session->gtpu = create_gtpu_tunnel_ngu(msg); @@ -136,6 +134,7 @@ pdu_session_setup_result pdu_session_manager_impl::setup_pdu_session(const e1ap_ // Connect adapters new_session->sdap_to_gtpu_adapter.connect_gtpu(*new_session->gtpu->get_tx_lower_layer_interface()); new_session->gtpu_to_sdap_adapter.connect_sdap(new_session->sdap->get_sdap_tx_sdu_handler()); + new_session->gtpu_to_udp_adapter.connect_network_gateway(n3_gw); // Register tunnel at demux if (!gtpu_rx_demux.add_tunnel( diff --git a/lib/cu_up/pdu_session_manager_impl.h b/lib/cu_up/pdu_session_manager_impl.h index fafa00ceab..72ae4d040c 100644 --- a/lib/cu_up/pdu_session_manager_impl.h +++ b/lib/cu_up/pdu_session_manager_impl.h @@ -45,7 +45,6 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl ngu_session_manager& ngu_session_mngr_, gtpu_teid_pool& n3_teid_allocator_, gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, gtpu_demux_ctrl& gtpu_rx_demux_, task_executor& ue_dl_exec_, task_executor& ue_ul_exec_, @@ -84,7 +83,6 @@ class pdu_session_manager_impl final : public pdu_session_manager_ctrl timer_factory ue_dl_timer_factory; timer_factory ue_ul_timer_factory; timer_factory ue_ctrl_timer_factory; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; gtpu_teid_pool& n3_teid_allocator; gtpu_teid_pool& f1u_teid_allocator; gtpu_demux_ctrl& gtpu_rx_demux; diff --git a/lib/cu_up/ue_context.h b/lib/cu_up/ue_context.h index 9cf83c11c1..bc120edadc 100644 --- a/lib/cu_up/ue_context.h +++ b/lib/cu_up/ue_context.h @@ -38,23 +38,22 @@ struct ue_context_cfg { class ue_context : public pdu_session_manager_ctrl { public: - ue_context(ue_index_t index_, - ue_context_cfg cfg_, - e1ap_control_message_handler& e1ap_, - const n3_interface_config& n3_config_, - const cu_up_test_mode_config& test_mode_config_, - std::unique_ptr ue_exec_mapper_, - fifo_async_task_scheduler& task_sched_, - timer_factory ue_dl_timer_factory_, - timer_factory ue_ul_timer_factory_, - timer_factory ue_ctrl_timer_factory_, - f1u_cu_up_gateway& f1u_gw_, - ngu_session_manager& ngu_session_mngr_, - gtpu_teid_pool& n3_teid_allocator_, - gtpu_teid_pool& f1u_teid_allocator_, - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier_, - gtpu_demux_ctrl& gtpu_rx_demux_, - dlt_pcap& gtpu_pcap) : + ue_context(ue_index_t index_, + ue_context_cfg cfg_, + e1ap_control_message_handler& e1ap_, + const n3_interface_config& n3_config_, + const cu_up_test_mode_config& test_mode_config_, + std::unique_ptr ue_exec_mapper_, + fifo_async_task_scheduler& task_sched_, + timer_factory ue_dl_timer_factory_, + timer_factory ue_ul_timer_factory_, + timer_factory ue_ctrl_timer_factory_, + f1u_cu_up_gateway& f1u_gw_, + ngu_session_manager& ngu_session_mngr_, + gtpu_teid_pool& n3_teid_allocator_, + gtpu_teid_pool& f1u_teid_allocator_, + gtpu_demux_ctrl& gtpu_rx_demux_, + dlt_pcap& gtpu_pcap) : task_sched(task_sched_), ue_exec_mapper(std::move(ue_exec_mapper_)), index(index_), @@ -75,7 +74,6 @@ class ue_context : public pdu_session_manager_ctrl ngu_session_mngr_, n3_teid_allocator_, f1u_teid_allocator_, - gtpu_tx_notifier_, gtpu_rx_demux_, ue_exec_mapper->dl_pdu_executor(), ue_exec_mapper->ul_pdu_executor(), diff --git a/lib/cu_up/ue_manager.cpp b/lib/cu_up/ue_manager.cpp index 5598762db5..1a5ac01ae7 100644 --- a/lib/cu_up/ue_manager.cpp +++ b/lib/cu_up/ue_manager.cpp @@ -20,7 +20,6 @@ ue_manager::ue_manager(const ue_manager_config& config, const ue_manager_depende e1ap(dependencies.e1ap), f1u_gw(dependencies.f1u_gw), ngu_session_mngr(dependencies.ngu_session_mngr), - gtpu_tx_notifier(dependencies.gtpu_tx_notifier), gtpu_rx_demux(dependencies.gtpu_rx_demux), n3_teid_allocator(dependencies.n3_teid_allocator), f1u_teid_allocator(dependencies.f1u_teid_allocator), @@ -80,7 +79,6 @@ ue_context* ue_manager::add_ue(const ue_context_cfg& ue_cfg) ngu_session_mngr, n3_teid_allocator, f1u_teid_allocator, - gtpu_tx_notifier, gtpu_rx_demux, gtpu_pcap); diff --git a/lib/cu_up/ue_manager.h b/lib/cu_up/ue_manager.h index 116a63c297..80ae26404a 100644 --- a/lib/cu_up/ue_manager.h +++ b/lib/cu_up/ue_manager.h @@ -30,17 +30,16 @@ struct ue_manager_config { /// UE manager dependencies. struct ue_manager_dependencies { - e1ap_control_message_handler& e1ap; - timer_manager& timers; - f1u_cu_up_gateway& f1u_gw; - ngu_session_manager& ngu_session_mngr; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - dlt_pcap& gtpu_pcap; - srslog::basic_logger& logger; + e1ap_control_message_handler& e1ap; + timer_manager& timers; + f1u_cu_up_gateway& f1u_gw; + ngu_session_manager& ngu_session_mngr; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + dlt_pcap& gtpu_pcap; + srslog::basic_logger& logger; }; class ue_manager : public ue_manager_ctrl @@ -64,22 +63,21 @@ class ue_manager : public ue_manager_ctrl /// \return The UE index. ue_index_t get_next_ue_index(); - const n3_interface_config& n3_config; - const cu_up_test_mode_config& test_mode_config; - e1ap_control_message_handler& e1ap; - f1u_cu_up_gateway& f1u_gw; - ngu_session_manager& ngu_session_mngr; - gtpu_tunnel_common_tx_upper_layer_notifier& gtpu_tx_notifier; - gtpu_demux_ctrl& gtpu_rx_demux; - gtpu_teid_pool& n3_teid_allocator; - gtpu_teid_pool& f1u_teid_allocator; - cu_up_executor_mapper& exec_pool; - task_executor& ctrl_executor; - dlt_pcap& gtpu_pcap; - timer_manager& timers; - ue_db_t ue_db; - ue_task_schedulers_t ue_task_schedulers; - srslog::basic_logger& logger; + const n3_interface_config& n3_config; + const cu_up_test_mode_config& test_mode_config; + e1ap_control_message_handler& e1ap; + f1u_cu_up_gateway& f1u_gw; + ngu_session_manager& ngu_session_mngr; + gtpu_demux_ctrl& gtpu_rx_demux; + gtpu_teid_pool& n3_teid_allocator; + gtpu_teid_pool& f1u_teid_allocator; + cu_up_executor_mapper& exec_pool; + task_executor& ctrl_executor; + dlt_pcap& gtpu_pcap; + timer_manager& timers; + ue_db_t ue_db; + ue_task_schedulers_t ue_task_schedulers; + srslog::basic_logger& logger; }; } // namespace srs_cu_up diff --git a/tests/unittests/cu_up/cu_up_test_helpers.h b/tests/unittests/cu_up/cu_up_test_helpers.h index fd80ca6047..ab8bd74431 100644 --- a/tests/unittests/cu_up/cu_up_test_helpers.h +++ b/tests/unittests/cu_up/cu_up_test_helpers.h @@ -280,7 +280,7 @@ class dummy_ngu_gateway final : public gtpu_tnl_pdu_session class dummy_ngu_session_manager final : public srs_cu_up::ngu_session_manager { public: - const gtpu_tnl_pdu_session& get_next_ngu_gateway() override { return ngu_gw; }; + gtpu_tnl_pdu_session& get_next_ngu_gateway() override { return ngu_gw; }; private: dummy_ngu_gateway ngu_gw; diff --git a/tests/unittests/cu_up/pdu_session_manager_test.h b/tests/unittests/cu_up/pdu_session_manager_test.h index 04c68dbb36..2cf552882f 100644 --- a/tests/unittests/cu_up/pdu_session_manager_test.h +++ b/tests/unittests/cu_up/pdu_session_manager_test.h @@ -60,7 +60,6 @@ class pdu_session_manager_test_base *ngu_session_mngr, *n3_allocator, *f1u_allocator, - *gtpu_tx_notifier, *gtpu_rx_demux, teid_worker, teid_worker, diff --git a/tests/unittests/cu_up/ue_manager_test.cpp b/tests/unittests/cu_up/ue_manager_test.cpp index 690f4da042..dce0cac062 100644 --- a/tests/unittests/cu_up/ue_manager_test.cpp +++ b/tests/unittests/cu_up/ue_manager_test.cpp @@ -48,7 +48,6 @@ class ue_manager_test : public ::testing::Test timers, *f1u_gw, *ngu_session_mngr, - *gtpu_tx_notifier, *gtpu_rx_demux, *gtpu_n3_allocator, *gtpu_f1u_allocator, From 9b50d1f9592ed91bcc667fffbca2fe551551cf6e Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 11 Dec 2024 10:33:41 +0100 Subject: [PATCH 098/227] .gdbinit: pretty printer for bf16_t --- .gdbinit | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/.gdbinit b/.gdbinit index ba115581de..cad87885d4 100644 --- a/.gdbinit +++ b/.gdbinit @@ -12,6 +12,8 @@ python +import struct + ###### static_vector ######## class StaticVectorPrinter(object): @@ -213,5 +215,44 @@ def make_slotted_vector(val): gdb.pretty_printers.append(make_slotted_vector) +###### Brain Floating Point 16 (bf16_t) ###### + +class BFloat16(object): + def __init__(self, val): + self.__val = val + + def to_string(self): + value_uint16 = self.__val['val'] + value_uint32 = value_uint16.cast(gdb.lookup_type('uint32_t')) << 16 + value_float = struct.unpack('!f', struct.pack('!I', value_uint32))[0] + return value_float + + def display_hint(self): + return None + +def make_bf16_t(val): + s = str(val.type.strip_typedefs()) + if 'srsran::strong_bf16_tag' in s: + return BFloat16(val) + +gdb.pretty_printers.append(make_bf16_t) + +class BFloat16Complex(object): + def __init__(self, val): + self.__val = val + + def to_string(self): + return f'{self.__val["real"]} + {self.__val["imag"]}i' + + def display_hint(self): + return None + +def make_cbf16_t(val): + s = str(val.type.strip_typedefs()) + if s == 'srsran::cbf16_t': + return BFloat16Complex(val) + +gdb.pretty_printers.append(make_cbf16_t) + end From e89ab2bdcec259b89c4d9f09a800ae09aac7d1a9 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 11 Dec 2024 10:39:58 +0100 Subject: [PATCH 099/227] .clang-tidy: remove readability-math-missing-parentheses --- .clang-tidy | 1 + 1 file changed, 1 insertion(+) diff --git a/.clang-tidy b/.clang-tidy index 9ac1ace65b..7b39447264 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -36,6 +36,7 @@ Checks: '-*, -readability-identifier-length, -readability-implicit-bool-conversion, -readability-magic-numbers, + -readability-math-missing-parentheses, -readability-static-accessed-through-instance, -readability-uppercase-literal-suffix' CheckOptions: From e4132b72c44d769c8dd8d4f6533ec5d0717c4ecc Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 09:43:21 +0100 Subject: [PATCH 100/227] sched: remove unused methods from ue class --- .../ue_context/dl_logical_channel_manager.h | 7 +++--- lib/scheduler/ue_context/ue.cpp | 13 ---------- lib/scheduler/ue_context/ue.h | 24 ++----------------- .../ue_scheduling/logical_channel_test.cpp | 2 +- 4 files changed, 7 insertions(+), 39 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index 5f90c7287d..31914d6f4d 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -69,7 +69,7 @@ class dl_logical_channel_manager bool is_con_res_id_pending() const { return pending_con_res_id; } /// \brief Checks whether UE has pending CEs to be scheduled (ConRes excluded). - bool has_pending_ces() const { return not pending_ces.empty(); } + bool has_pending_ces() const { return pending_con_res_id or not pending_ces.empty(); } /// \brief Calculates total number of DL bytes, including MAC header overhead. /// \remark Excludes data for SRB0 and UE Contention Resolution Identity CE. @@ -86,7 +86,7 @@ class dl_logical_channel_manager /// \brief Returns the UE pending CEs' bytes to be scheduled, if any. unsigned pending_ce_bytes() const { - unsigned bytes = pending_ue_con_res_id_ce_bytes(); + unsigned bytes = pending_con_res_ce_bytes(); for (const auto& ce : pending_ces) { bytes += ce.ce_lcid.is_var_len_ce() ? get_mac_sdu_required_bytes(ce.ce_lcid.sizeof_ce()) : FIXED_SIZED_MAC_CE_SUBHEADER_SIZE + ce.ce_lcid.sizeof_ce(); @@ -95,7 +95,7 @@ class dl_logical_channel_manager } /// \brief Checks whether UE has pending UE Contention Resolution Identity CE to be scheduled. - unsigned pending_ue_con_res_id_ce_bytes() const + unsigned pending_con_res_ce_bytes() const { static const auto ce_size = lcid_dl_sch_t{lcid_dl_sch_t::UE_CON_RES_ID}.sizeof_ce(); return is_con_res_id_pending() ? FIXED_SIZED_MAC_CE_SUBHEADER_SIZE + ce_size : 0; @@ -118,6 +118,7 @@ class dl_logical_channel_manager void handle_mac_ce_indication(const mac_ce_info& ce) { if (ce.ce_lcid == lcid_dl_sch_t::UE_CON_RES_ID) { + // CON RES is a special case, as it needs to be always scheduled first. pending_con_res_id = true; return; } diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index c459546611..3b11c0ef64 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -127,19 +127,6 @@ unsigned ue::pending_dl_newtx_bytes(lcid_t lcid) const return lcid != INVALID_LCID ? dl_lc_ch_mgr.pending_bytes(lcid) : dl_lc_ch_mgr.pending_bytes(); } -unsigned ue::pending_dl_srb_newtx_bytes() const -{ - return dl_lc_ch_mgr.pending_bytes(LCID_SRB1) + dl_lc_ch_mgr.pending_bytes(LCID_SRB2); -} - -unsigned ue::pending_ul_srb_newtx_bytes() const -{ - // LCG ID 0 is used by default for SRBs as per TS 38.331, clause 9.2.1. - // NOTE: Ensure SRB LCG ID matches the one sent to UE. - const lcg_id_t srb_lcg_id = uint_to_lcg_id(0); - return ul_lc_ch_mgr.pending_bytes(srb_lcg_id); -} - unsigned ue::pending_ul_newtx_bytes() const { static constexpr unsigned SR_GRANT_BYTES = 512; diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index d87d3f6c3b..8393312b71 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -123,14 +123,6 @@ class ue /// \remark Excludes SRB0 and UE Contention Resolution Identity CE. bool has_pending_dl_newtx_bytes() const { return dl_lc_ch_mgr.has_pending_bytes(); } - /// \brief Checks if there are DL pending bytes in SRBs that are yet to be allocated in a DL HARQ. - /// This method is faster than computing \c pending_dl_newtx_bytes() > 0. - /// \remark Excludes SRB0 pending bytes. - bool has_pending_dl_srb_newtx_bytes() const - { - return dl_lc_ch_mgr.has_pending_bytes(LCID_SRB1) or dl_lc_ch_mgr.has_pending_bytes(LCID_SRB2); - } - /// \brief Checks if there are DL pending bytes for a specific LCID that are yet to be allocated in a DL HARQ. bool has_pending_dl_newtx_bytes(lcid_t lcid) const { return dl_lc_ch_mgr.has_pending_bytes(lcid); } @@ -138,13 +130,13 @@ class ue bool is_conres_ce_pending() const { return dl_lc_ch_mgr.is_con_res_id_pending(); } /// \brief Returns the UE pending ConRes CE bytes to be scheduled, if any. - unsigned pending_conres_ce_bytes() const { return dl_lc_ch_mgr.pending_ue_con_res_id_ce_bytes(); } + unsigned pending_conres_ce_bytes() const { return dl_lc_ch_mgr.pending_con_res_ce_bytes(); } /// \brief Returns the UE pending CEs' bytes to be scheduled, if any. unsigned pending_ce_bytes() const { return dl_lc_ch_mgr.pending_ce_bytes(); } /// \brief Returns whether the UE has pending CEs' bytes to be scheduled, if any. - bool has_pending_ce_bytes() const { return dl_lc_ch_mgr.is_con_res_id_pending() or dl_lc_ch_mgr.has_pending_ces(); } + bool has_pending_ce_bytes() const { return dl_lc_ch_mgr.has_pending_ces(); } /// \brief Computes the number of DL pending bytes that are not already allocated in a DL HARQ. The value is used /// to derive the required transport block size for an DL grant. @@ -153,12 +145,6 @@ class ue /// \return The number of DL pending bytes that are not already allocated in a DL HARQ. unsigned pending_dl_newtx_bytes(lcid_t lcid = lcid_t::INVALID_LCID) const; - /// \brief Computes the number of DL pending bytes in SRBs that are not already allocated in a DL - /// HARQ. The value is used to derive the required transport block size for an DL grant. - /// \return The number of DL pending bytes in SRBs that are not already allocated in a DL HARQ. - /// \remark Excludes SRB0 pending bytes. - unsigned pending_dl_srb_newtx_bytes() const; - /// \brief Computes the number of UL pending bytes that are not already allocated in a UL HARQ. The value is used /// to derive the required transport block size for an UL grant. unsigned pending_ul_newtx_bytes() const; @@ -166,12 +152,6 @@ class ue /// \brief Computes the number of UL pending bytes for a LCG ID. unsigned pending_ul_newtx_bytes(lcg_id_t lcg_id) const; - /// \brief Computes the number of UL pending bytes in SRBs. The value is used to derive the required transport block - /// size for an UL grant. - /// \return The number of UL pending bytes in SRBs. - /// \remark The returned UL pending bytes does not exclude already allocated bytes in UL HARQ(s). - unsigned pending_ul_srb_newtx_bytes() const; - /// \brief Returns whether a SR indication handling is pending. bool has_pending_sr() const; diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index d46f8cdd6f..1218c62a15 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -249,7 +249,7 @@ TEST(dl_logical_channel_test, pending_ue_con_res_id_ce_bytes_does_not_include_ot const unsigned dummy_ce_payload = 0; lch_mng.handle_mac_ce_indication({.ce_lcid = ce_lcid, .ce_payload = dummy_ce_payload}); - ASSERT_EQ(lch_mng.pending_ue_con_res_id_ce_bytes(), 0); + ASSERT_EQ(lch_mng.pending_con_res_ce_bytes(), 0); } TEST(ul_logical_channel_test, when_logical_channel_groups_are_inactive_then_no_ul_bytes_are_pending) From 1b02759f9719e90921c03db1f2ab01eed59015e3 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 12:29:01 +0100 Subject: [PATCH 101/227] sched: save scheduled DL LCIDs in HARQ --- include/srsran/scheduler/sched_consts.h | 3 -- .../srsran/scheduler/scheduler_slot_handler.h | 6 ++-- lib/scheduler/cell/cell_harq_manager.cpp | 11 +++++-- lib/scheduler/cell/cell_harq_manager.h | 30 ++++++++++------- .../ue_scheduling/ue_cell_grid_allocator.cpp | 2 +- .../ue_scheduling/ue_fallback_scheduler.cpp | 2 +- .../scheduler/cell/cell_harq_manager_test.cpp | 33 +++++++++++-------- .../ue_harq_link_adaptation_test.cpp | 6 +++- 8 files changed, 58 insertions(+), 35 deletions(-) diff --git a/include/srsran/scheduler/sched_consts.h b/include/srsran/scheduler/sched_consts.h index 5652cb6561..bd933f7f5f 100644 --- a/include/srsran/scheduler/sched_consts.h +++ b/include/srsran/scheduler/sched_consts.h @@ -15,9 +15,6 @@ namespace srsran { -/// Maximum number of layers (implementation-defined) -const size_t MAX_NOF_LAYERS = 2; - /// SSB constants. /// FR1 = [ 410 MHz – 7125 MHz] (TS 38.101, Section 5.1) and ARFCN corresponding to 7.125GHz is 875000. const unsigned FR1_MAX_FREQUENCY_ARFCN = 875000; diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index 2fb61da351..0a4afae96c 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -217,10 +217,12 @@ struct dl_msg_tb_info { static_vector lc_chs_to_sched; }; +using dl_msg_tb_info_list = static_vector; + /// Dedicated DL Grant for UEs. struct dl_msg_alloc { - pdsch_information pdsch_cfg; - static_vector tb_list; + pdsch_information pdsch_cfg; + dl_msg_tb_info_list tb_list; /// \brief Information relative to a PDSCH allocation decision that is used for the purpose of logging or /// tracing, but not passed to the PHY. diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 92f8a24692..22f451c4d8 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -667,8 +667,11 @@ void dl_harq_process_handle::increment_pucch_counter() ++impl->pucch_ack_to_receive; } -void dl_harq_process_handle::save_grant_params(const dl_harq_alloc_context& ctx, const pdsch_information& pdsch) +void dl_harq_process_handle::save_grant_params(const dl_harq_alloc_context& ctx, const dl_msg_alloc& ue_pdsch) { + constexpr static size_t CW_INDEX = 0; + + const pdsch_information& pdsch = ue_pdsch.pdsch_cfg; srsran_assert(pdsch.codewords.size() == 1, "Only one codeword supported"); srsran_sanity_check(pdsch.rnti == impl->rnti, "RNTI mismatch"); srsran_sanity_check(pdsch.harq_id == impl->h_id, "HARQ-id mismatch"); @@ -676,7 +679,7 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_alloc_context& ctx, "Setting allocation parameters for DL HARQ process id={} in invalid state", id()); - const pdsch_codeword& cw = pdsch.codewords[0]; + const pdsch_codeword& cw = pdsch.codewords[CW_INDEX]; dl_harq_process_impl::alloc_params& prev_params = impl->prev_tx_params; if (impl->nof_retxs == 0) { @@ -687,6 +690,10 @@ void dl_harq_process_handle::save_grant_params(const dl_harq_alloc_context& ctx, prev_params.slice_id = ctx.slice_id; prev_params.cqi = ctx.cqi.has_value() ? ctx.cqi.value() : cqi_value{1}; prev_params.is_fallback = ctx.is_fallback; + prev_params.lc_sched_info.clear(); + for (const dl_msg_lc_info& lc : ue_pdsch.tb_list[CW_INDEX].lc_chs_to_sched) { + prev_params.lc_sched_info.push_back({lc.lcid, units::bytes{lc.sched_bytes}}); + } } else { srsran_assert(ctx.dci_cfg_type == prev_params.dci_cfg_type, "DCI format and RNTI type cannot change during DL HARQ retxs"); diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index ca50be1b71..15663657e3 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -14,8 +14,10 @@ #include "srsran/adt/intrusive_list.h" #include "srsran/ran/csi_report/csi_report_data.h" #include "srsran/ran/du_types.h" +#include "srsran/ran/logical_channel/lcid_dl_sch.h" #include "srsran/ran/pdsch/pdsch_mcs.h" #include "srsran/ran/pusch/pusch_mcs.h" +#include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/slot_point.h" #include "srsran/scheduler/harq_id.h" #include "srsran/scheduler/scheduler_dci.h" @@ -23,7 +25,7 @@ namespace srsran { -struct pdsch_information; +struct dl_msg_alloc; struct pusch_information; class unique_ue_harq_entity; @@ -71,15 +73,21 @@ struct dl_harq_process_impl : public base_harq_process { /// \brief Parameters relative to the last used PDSCH PDU that get stored in the HARQ process for future reuse. struct alloc_params { - dci_dl_rnti_config_type dci_cfg_type; - vrb_alloc rbs; - unsigned nof_symbols; - unsigned nof_layers{1}; - bool is_fallback{false}; - cqi_value cqi; - pdsch_mcs_table mcs_table; - sch_mcs_index mcs; - unsigned tbs_bytes; + struct lc_alloc_info { + lcid_dl_sch_t lcid; + units::bytes sched_bytes; + }; + + dci_dl_rnti_config_type dci_cfg_type; + vrb_alloc rbs; + unsigned nof_symbols; + unsigned nof_layers{1}; + bool is_fallback{false}; + cqi_value cqi; + pdsch_mcs_table mcs_table; + sch_mcs_index mcs; + unsigned tbs_bytes; + static_vector lc_sched_info; /// RAN slice identifier. std::optional slice_id; /// \brief MCS originally suggested by the OLLA. It might differ from the actual MCS used. @@ -274,7 +282,7 @@ class dl_harq_process_handle : public harq_utils::base_harq_process_handle /// \brief Stores grant parameters that are associated with the HARQ process (e.g. DCI format, PRBs, MCS) so that /// they can be later fetched and optionally reused. - void save_grant_params(const dl_harq_alloc_context& ctx, const pdsch_information& pdsch); + void save_grant_params(const dl_harq_alloc_context& ctx, const dl_msg_alloc& ue_pdsch); slot_point pdsch_slot() const { return impl->slot_tx; } slot_point uci_slot() const { return impl->slot_ack; } diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index fda052d304..b72d6c7cda 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -482,7 +482,7 @@ dl_alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& msg.context.buffer_occupancy = u.pending_dl_newtx_bytes(); } - h_dl->save_grant_params(pdsch_sched_ctx, msg.pdsch_cfg); + h_dl->save_grant_params(pdsch_sched_ctx, msg); // Update DRX state given the new allocation. u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index a0469400b2..bc73de9b44 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -930,7 +930,7 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u // Save in HARQ the parameters set for this PDCCH and PDSCH PDUs. dl_harq_alloc_context ctxt{pdcch.dci.type, std::nullopt, std::nullopt, std::nullopt, true}; - h_dl->save_grant_params(ctxt, msg.pdsch_cfg); + h_dl->save_grant_params(ctxt, msg); return std::make_pair(srb1_bytes_allocated, *h_dl); } diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index c2e51cd78e..d511475ca0 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -28,17 +28,22 @@ mac_harq_ack_report_status get_random_harq_ack() return static_cast(test_rgen::uniform_int(0, 2)); } -pdsch_information make_dummy_pdsch_info() +dl_msg_alloc make_dummy_ue_pdsch_info() { - pdsch_information pdsch; - pdsch.rnti = to_rnti(0x4601); - pdsch.harq_id = to_harq_id(0); + dl_msg_alloc msg; + pdsch_information& pdsch = msg.pdsch_cfg; + pdsch.rnti = to_rnti(0x4601); + pdsch.harq_id = to_harq_id(0); pdsch.codewords.resize(1); pdsch.codewords[0].mcs_table = srsran::pdsch_mcs_table::qam64; pdsch.codewords[0].mcs_index = 10; pdsch.codewords[0].tb_size_bytes = 10000; pdsch.rbs = vrb_interval{5, 10}; - return pdsch; + msg.context.ue_index = to_du_ue_index(0); + msg.context.ss_id = to_search_space_id(2); + msg.tb_list.push_back( + dl_msg_tb_info{{dl_msg_lc_info{lcid_dl_sch_t{LCID_SRB1}, pdsch.codewords[0].tb_size_bytes - 4}}}); + return msg; } pusch_information make_dummy_pusch_info() @@ -158,15 +163,15 @@ class single_harq_process_test : public base_single_harq_entity_test, public ::t protected: single_harq_process_test(unsigned ntn_cs_koffset_ = 0) : base_single_harq_entity_test(ntn_cs_koffset_) { - pdsch_info = make_dummy_pdsch_info(); + ue_pdsch = make_dummy_ue_pdsch_info(); dl_harq_alloc_context harq_ctxt{dci_dl_rnti_config_type::c_rnti_f1_0}; - h_dl.save_grant_params(harq_ctxt, pdsch_info); + h_dl.save_grant_params(harq_ctxt, ue_pdsch); pusch_info = make_dummy_pusch_info(); ul_harq_alloc_context ul_harq_ctxt{dci_ul_rnti_config_type::c_rnti_f0_0}; h_ul.save_grant_params(ul_harq_ctxt, pusch_info); } - pdsch_information pdsch_info; + dl_msg_alloc ue_pdsch; pusch_information pusch_info; dl_harq_process_handle h_dl{harq_ent.alloc_dl_harq(current_slot, k1, max_retxs, 0).value()}; ul_harq_process_handle h_ul{harq_ent.alloc_ul_harq(current_slot + k2 + ntn_cs_koffset, max_retxs).value()}; @@ -295,10 +300,10 @@ TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_params_have_co TEST_F(single_harq_process_test, when_harq_is_allocated_then_harq_grant_params_have_correct_values) { - ASSERT_EQ(h_dl.get_grant_params().mcs, pdsch_info.codewords[0].mcs_index); - ASSERT_EQ(h_dl.get_grant_params().mcs_table, pdsch_info.codewords[0].mcs_table); - ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); - ASSERT_EQ(h_dl.get_grant_params().rbs.type1(), pdsch_info.rbs.type1()); + ASSERT_EQ(h_dl.get_grant_params().mcs, ue_pdsch.pdsch_cfg.codewords[0].mcs_index); + ASSERT_EQ(h_dl.get_grant_params().mcs_table, ue_pdsch.pdsch_cfg.codewords[0].mcs_table); + ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, ue_pdsch.pdsch_cfg.codewords[0].tb_size_bytes); + ASSERT_EQ(h_dl.get_grant_params().rbs.type1(), ue_pdsch.pdsch_cfg.rbs.type1()); ASSERT_EQ(h_dl.get_grant_params().dci_cfg_type, dci_dl_rnti_config_type::c_rnti_f1_0); ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_ack()); } @@ -1068,7 +1073,7 @@ TEST_F(single_ntn_ue_harq_process_test, harq_history_is_reachable_after_timeout) h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot + ntn_cs_koffset, 0).value(); h_ul = harq_ent.find_ul_harq_waiting_ack(pusch_slot + ntn_cs_koffset).value(); ASSERT_FALSE(h_dl.empty() and h_ul.empty()); - ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); + ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, ue_pdsch.pdsch_cfg.codewords[0].tb_size_bytes); ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, pusch_info.tb_size_bytes); ASSERT_EQ(h_ul.get_grant_params().tbs_bytes, harq_ent.total_ul_bytes_waiting_ack()); @@ -1090,5 +1095,5 @@ TEST_F(single_ntn_ue_harq_process_test, when_harq_gets_acked_then_it_reports_the h_dl = harq_ent.find_dl_harq_waiting_ack(uci_slot + ntn_cs_koffset, 0).value(); ASSERT_EQ(h_dl.dl_ack_info(mac_harq_ack_report_status::ack, std::nullopt), dl_harq_process_handle::status_update::acked); - ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, pdsch_info.codewords[0].tb_size_bytes); + ASSERT_EQ(h_dl.get_grant_params().tbs_bytes, ue_pdsch.pdsch_cfg.codewords[0].tb_size_bytes); } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp index 1587b936c1..d827b300b3 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_harq_link_adaptation_test.cpp @@ -79,9 +79,13 @@ class ue_harq_link_adaptation_test : public ::testing::Test dci_dl_format::f1_1, h_dl.id(), std::nullopt}; + const dl_msg_alloc ue_pdsch{ + pdsch, + {{dl_msg_tb_info{{dl_msg_lc_info{lcid_dl_sch_t{lcid_t::LCID_SRB1}, cw.tb_size_bytes - 4, {}}}}}}, + {ue_ptr->ue_index}}; dl_harq_alloc_context ctxt{dci_dl_rnti_config_type::c_rnti_f1_1, pdsch.codewords[0].mcs_index, std::nullopt, 15}; - h_dl.save_grant_params(ctxt, pdsch); + h_dl.save_grant_params(ctxt, ue_pdsch); return h_dl; } From 986bbbd7b70ad5821b80285ff375d55b735b5065 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 15:27:32 +0100 Subject: [PATCH 102/227] sched: fix fallback scheduler test to avoid pushing multiple contention resolutions --- lib/scheduler/ue_context/dl_logical_channel_manager.cpp | 2 +- .../scheduler/ue_scheduling/fallback_scheduler_test.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp index be6266febb..6c53887a02 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp @@ -171,7 +171,7 @@ unsigned srsran::allocate_mac_ces(dl_msg_tb_info& tb_info, dl_logical_channel_ma { unsigned rem_tbs = total_tbs; - while ((lch_mng.is_con_res_id_pending() or lch_mng.has_pending_ces()) and not tb_info.lc_chs_to_sched.full()) { + while (lch_mng.has_pending_ces() and not tb_info.lc_chs_to_sched.full()) { dl_msg_lc_info subpdu; unsigned alloc_bytes = lch_mng.allocate_mac_ce(subpdu, rem_tbs); if (alloc_bytes == 0) { diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index a251c143aa..0048a023c7 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -1059,7 +1059,7 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public if (sl == slot_update_srb_traffic and nof_packet_to_tx > 0) { // Notify about SRB1 message in DL. pending_srb1_bytes = generate_srb1_buffer_size(); - parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false); + parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false, false); latest_rlc_update_slot.emplace(sl); --nof_packet_to_tx; test_logger.debug("rnti={}, slot={}: pushing SRB1 traffic of {} bytes", test_ue.crnti, sl, pending_srb1_bytes); @@ -1089,7 +1089,7 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public sl, to_harq_id(h_dl->id()), pending_srb1_bytes); - parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false); + parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false, false); latest_rlc_update_slot.emplace(sl); } } @@ -1104,7 +1104,7 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public test_ue.crnti, sl, pending_srb1_bytes); - parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false); + parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false, false); latest_rlc_update_slot.emplace(sl); } } @@ -1125,7 +1125,7 @@ class fallback_scheduler_srb1_segmentation : public base_fallback_tester, public sl, to_harq_id(h_dl->id()), pending_srb1_bytes); - parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false); + parent->push_buffer_state_to_dl_ue(test_ue.ue_index, sl, pending_srb1_bytes, false, false); } // Check if any HARQ process with pending transmissions is re-set by the scheduler. From dbe63886a980aa2cde650c1db6165f2c061868ac Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 15:56:23 +0100 Subject: [PATCH 103/227] sched: iterate HARQs rather than pending retxs to determine pending bytes for SRB1 --- .../ue_scheduling/ue_fallback_scheduler.cpp | 48 ++++++++----------- .../ue_scheduling/ue_fallback_scheduler.h | 2 +- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index bc73de9b44..25d719d473 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -127,7 +127,7 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i // in the fallback scheduler, the RLC buffer state update can only be 0. // For SRB1, due to the segmentation, we need to update the internal SRB1 buffer state. else if (not is_srb0) { - update_srb1_buffer_after_rlc_bsu(ue_index, sl, srb_buffer_bytes); + ue_it->pending_srb1_buffer_bytes = update_srb1_buffer_after_rlc_bsu(ue_index, sl, srb_buffer_bytes); } return; } @@ -1379,36 +1379,30 @@ void ue_fallback_scheduler::update_srb1_buffer_state_after_alloc(du_ue_index_t u } } -void ue_fallback_scheduler::update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_idx, - slot_point sl, - unsigned buffer_status_report) +unsigned ue_fallback_scheduler::update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_idx, + slot_point sl, + unsigned dl_rlc_bo_update) const { - // Retrieve the UE from the list of UEs that need to be scheduled. - auto ue_it = - std::find_if(pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_idx](const fallback_ue& ue) { - return ue.ue_index == ue_idx and ue.is_srb0.has_value() and not ue.is_srb0.value(); - }); - if (ue_it == pending_dl_ues_new_tx.end() or not ues.contains(ue_idx)) { - return; - } - - unsigned srb1_buffer_bytes = buffer_status_report; - - // Remove the LCID-1 bytes that are already scheduled for future new transmissions, but yet to be transmitted, from - // the RLC buffer state update received from upper layers. - for (auto& ack_tracker : ongoing_ues_ack_retxs) { - if (ack_tracker.ue_index != ue_idx or not ack_tracker.is_srb0.has_value() or - (ack_tracker.is_srb0.has_value() and ack_tracker.is_srb0.value())) { - continue; - } - if (ack_tracker.h_dl->is_waiting_ack() and ack_tracker.h_dl->pdsch_slot() >= sl and - ack_tracker.h_dl->nof_retxs() == 0) { - unsigned tx_ed_bytes = ack_tracker.srb1_payload_bytes; - srb1_buffer_bytes = srb1_buffer_bytes > tx_ed_bytes ? srb1_buffer_bytes - tx_ed_bytes : 0; + unsigned srb1_buffer_bytes = dl_rlc_bo_update; + + // Subtract the LCID1 bytes that are scheduled but not yet transmitted. + auto& u = ues[ue_idx]; + auto& ue_pcell = u.get_pcell(); + for (unsigned i = 0, e = ue_pcell.harqs.nof_dl_harqs(); i < e; ++i) { + auto h_dl = ue_pcell.harqs.dl_harq(to_harq_id(i)); + if (h_dl.has_value() and h_dl->is_waiting_ack() and h_dl->pdsch_slot() >= sl and h_dl->nof_retxs() == 0) { + for (const auto& lc : h_dl->get_grant_params().lc_sched_info) { + if (lc.lcid.to_lcid() == LCID_SRB1) { + srb1_buffer_bytes -= std::min(srb1_buffer_bytes, lc.sched_bytes.value()); + if (srb1_buffer_bytes == 0) { + return 0; + } + } + } } } - ue_it->pending_srb1_buffer_bytes = srb1_buffer_bytes; + return srb1_buffer_bytes; } void ue_fallback_scheduler::slot_indication(slot_point sl) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index fd7f7a8aa7..9c8cb97ac3 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -238,7 +238,7 @@ class ue_fallback_scheduler // \param[in] sl Slot at which the Buffer State Update was received. // \param[in] buffer_status_report Number of pending LCID 1 bytes reported by the RLC buffer state update (only LCID 1 // bytes, without any overhead). - void update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_idx, slot_point sl, unsigned buffer_status_report); + unsigned update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_idx, slot_point sl, unsigned dl_rlc_bo_update) const; const scheduler_ue_expert_config& expert_cfg; const cell_configuration& cell_cfg; From 54eee7bfad1b30ca2ef2a48e7d546dca2826d6ba Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 16:26:01 +0100 Subject: [PATCH 104/227] sched: remove unnecessary checks in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 53 ++++++++----------- .../ue_scheduling/ue_fallback_scheduler.h | 9 +--- 2 files changed, 23 insertions(+), 39 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 25d719d473..164f633cc1 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -107,35 +107,25 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i return; } + if ((srb_buffer_bytes > 0) != u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { + logger.error("ue={}: UE logical channel state is inconsistent with RLC buffer update"); + return; + } + auto ue_it = std::find_if( pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_index, is_srb0](const fallback_ue& ue) { return ue.ue_index == ue_index and (not ue.is_srb0.has_value() or ue.is_srb0.value() == is_srb0); }); if (ue_it != pending_dl_ues_new_tx.end()) { - // This case can happen when ConRes indication is received first and then receive Msg4 indication from upper layers. - if (not ue_it->is_srb0.has_value()) { - ue_it->is_srb0 = is_srb0; - ue_it->pending_srb1_buffer_bytes = srb_buffer_bytes; - return; - } - // Remove the UE from the pending UE list when the Buffer Status Update is 0. - if (not u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { - pending_dl_ues_new_tx.erase(ue_it); - } - // This case can happen only for SRB1; note that for SRB0 there is no segmentation and, when the UE already exists - // in the fallback scheduler, the RLC buffer state update can only be 0. - // For SRB1, due to the segmentation, we need to update the internal SRB1 buffer state. - else if (not is_srb0) { - ue_it->pending_srb1_buffer_bytes = update_srb1_buffer_after_rlc_bsu(ue_index, sl, srb_buffer_bytes); - } + // The UE has already data pending. + ue_it->is_srb0 = is_srb0; + ue_it->pending_srb1_buffer_bytes = get_pending_dl_srb_bytes(ue_index, sl, is_srb0, srb_buffer_bytes); return; } // The UE doesn't exist in the internal fallback scheduler list, add it. - if (u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { - pending_dl_ues_new_tx.push_back({ue_index, is_srb0, u.is_conres_ce_pending(), srb_buffer_bytes}); - } + pending_dl_ues_new_tx.push_back({ue_index, is_srb0, u.is_conres_ce_pending(), srb_buffer_bytes}); } void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) @@ -413,9 +403,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res if (pdcch_alloc.result.dl.dl_pdcchs.full() or pdsch_alloc.result.dl.ue_grants.full()) { logger.debug("rnti={}: Failed to allocate PDSCH for {}. Cause: No space available in scheduler output list", u.crnti, - not is_srb0.has_value() ? "ConRes CE" - : *is_srb0 ? "SRB0 PDU" - : "SRB1 PDU"); + not is_srb0.has_value() ? "ConRes CE" : (*is_srb0 ? "SRB0 PDU" : "SRB1 PDU")); slots_with_no_pdxch_space[next_slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; continue; } @@ -437,8 +425,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res const bool alloc_successful = sched_res.h_dl.has_value(); if (alloc_successful) { if (not is_retx) { - // The srb1_payload_bytes is meaningful only for SRB1. - store_harq_tx(u.ue_index, sched_res.h_dl, sched_res.nof_srb1_scheduled_bytes, is_srb0); + store_harq_tx(u.ue_index, sched_res.h_dl, is_srb0); } if (sched_res.is_srb_data_pending) { return dl_sched_outcome::srb_pending; @@ -452,9 +439,7 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // No resource found in UE's carriers and Search spaces. logger.debug("rnti={}: Skipped {} allocation in slots:[{},{}). Cause: no PDCCH/PDSCH/PUCCH resources available", u.crnti, - not is_srb0.has_value() ? "ConRes CE" - : *is_srb0 ? "SRB0 PDU" - : "SRB1 PDU", + not is_srb0.has_value() ? "ConRes CE" : (*is_srb0 ? "SRB0 PDU" : "SRB1 PDU"), starting_slot, sched_ref_slot + max_dl_slots_ahead_sched + 1); return dl_sched_outcome::next_ue; @@ -1325,7 +1310,6 @@ ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsch_config_common& void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ue_index, std::optional h_dl, - unsigned srb_payload_bytes, std::optional is_srb0) { srsran_sanity_check(ongoing_ues_ack_retxs.end() == @@ -1336,7 +1320,7 @@ void ue_fallback_scheduler::store_harq_tx(du_ue_index_t }), "This UE and HARQ process were already in the list"); - ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl, srb_payload_bytes, is_srb0); + ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl, is_srb0); } unsigned ue_fallback_scheduler::get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) const @@ -1379,10 +1363,15 @@ void ue_fallback_scheduler::update_srb1_buffer_state_after_alloc(du_ue_index_t u } } -unsigned ue_fallback_scheduler::update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_idx, - slot_point sl, - unsigned dl_rlc_bo_update) const +unsigned ue_fallback_scheduler::get_pending_dl_srb_bytes(du_ue_index_t ue_idx, + slot_point sl, + bool is_srb0, + unsigned dl_rlc_bo_update) const { + if (not is_srb0) { + return dl_rlc_bo_update; + } + unsigned srb1_buffer_bytes = dl_rlc_bo_update; // Subtract the LCID1 bytes that are scheduled but not yet transmitted. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 9c8cb97ac3..bd48e49708 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -189,9 +189,8 @@ class ue_fallback_scheduler public: explicit ack_and_retx_tracker(du_ue_index_t ue_idx, const std::optional& h_dl_, - unsigned srb_payload_bytes_, std::optional is_srb0_ = std::nullopt) : - ue_index(ue_idx), is_srb0(is_srb0_), h_dl(h_dl_), srb1_payload_bytes(srb_payload_bytes_) + ue_index(ue_idx), is_srb0(is_srb0_), h_dl(h_dl_) { } explicit ack_and_retx_tracker(const ack_and_retx_tracker& other) = default; @@ -205,14 +204,10 @@ class ue_fallback_scheduler // This field is empty if HARQ is used to schedule ConRes CE only. std::optional is_srb0; std::optional h_dl; - // Represents the number of LCID-1 bytes (excluding any overhead) that have been allocated for this TX. - // This is only meaningful for SRB1, - unsigned srb1_payload_bytes = 0; }; void store_harq_tx(du_ue_index_t ue_index, std::optional h_dl, - unsigned srb_payload_bytes, std::optional is_srb0 = std::nullopt); // Returns the total number of bytes pending for SRB1 for a given UE, including MAC CE and MAC subheaders. @@ -238,7 +233,7 @@ class ue_fallback_scheduler // \param[in] sl Slot at which the Buffer State Update was received. // \param[in] buffer_status_report Number of pending LCID 1 bytes reported by the RLC buffer state update (only LCID 1 // bytes, without any overhead). - unsigned update_srb1_buffer_after_rlc_bsu(du_ue_index_t ue_idx, slot_point sl, unsigned dl_rlc_bo_update) const; + unsigned get_pending_dl_srb_bytes(du_ue_index_t ue_idx, slot_point sl, bool is_srb0, unsigned dl_rlc_bo_update) const; const scheduler_ue_expert_config& expert_cfg; const cell_configuration& cell_cfg; From 3c2b2ec5d9c36457eae868a3e935e5b9ed440776 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 10 Dec 2024 11:12:41 +0100 Subject: [PATCH 105/227] sched: improve dl logical channel management for when harqs are allocated ahead of time --- lib/scheduler/ue_context/ue.cpp | 31 +++++++++++++++++++ lib/scheduler/ue_context/ue.h | 11 +++---- .../ue_scheduling/ue_fallback_scheduler.cpp | 19 +++++++----- .../ue_scheduling/ue_scheduler_impl.cpp | 6 ++-- .../ue_scheduling/fallback_scheduler_test.cpp | 4 ++- 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 3b11c0ef64..a1dc9199b3 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -43,6 +43,7 @@ ue::ue(const ue_creation_command& cmd) : void ue::slot_indication(slot_point sl_tx) { + last_sl_tx = sl_tx; ta_mgr.slot_indication(sl_tx); drx.slot_indication(sl_tx); } @@ -122,6 +123,36 @@ void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) } } +void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& msg) +{ + unsigned pending_bytes = msg.bs; + + // Subtract bytes pending for this LCID in scheduled HARQ allocations before forwarding to DL logical channel. + // Note: The RLC buffer occupancy updates never account for bytes associated with future HARQ transmissions. + for (unsigned c = 0, ce = nof_cells(); c != ce; ++c) { + auto& ue_cc = *ue_cells[c]; + + if (last_sl_tx.valid() and ue_cc.harqs.last_pdsch_slot().valid() and ue_cc.harqs.last_pdsch_slot() > last_sl_tx) { + unsigned rem_harqs = ue_cc.harqs.nof_dl_harqs() - ue_cc.harqs.nof_empty_dl_harqs(); + for (unsigned i = 0, e = ue_cc.harqs.nof_dl_harqs(); i != e and rem_harqs > 0; ++i) { + auto h_dl = ue_cc.harqs.dl_harq(to_harq_id(i)); + if (h_dl.has_value()) { + rem_harqs--; + if (h_dl->pdsch_slot() >= last_sl_tx and h_dl->nof_retxs() == 0 and h_dl->is_waiting_ack()) { + for (const auto& lc : h_dl->get_grant_params().lc_sched_info) { + if (lc.lcid.to_lcid() == msg.lcid) { + pending_bytes -= std::min(pending_bytes, lc.sched_bytes.value()); + } + } + } + } + } + } + } + + dl_lc_ch_mgr.handle_dl_buffer_status_indication(msg.lcid, pending_bytes); +} + unsigned ue::pending_dl_newtx_bytes(lcid_t lcid) const { return lcid != INVALID_LCID ? dl_lc_ch_mgr.pending_bytes(lcid) : dl_lc_ch_mgr.pending_bytes(); diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index 8393312b71..ba2cd7529d 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -110,14 +110,11 @@ class ue dl_lc_ch_mgr.handle_mac_ce_indication({.ce_lcid = msg.ce_lcid, .ce_payload = dummy_ce_payload{}}); } - /// \brief Handles DL Buffer State indication. - void handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& msg) - { - dl_lc_ch_mgr.handle_dl_buffer_status_indication(msg.lcid, msg.bs); - } - void handle_reconfiguration_request(const ue_reconf_command& params); + /// \brief Handles DL Buffer State indication. + void handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& msg); + /// \brief Checks if there are DL pending bytes that are yet to be allocated in a DL HARQ. /// This method is faster than computing \c pending_dl_newtx_bytes() > 0. /// \remark Excludes SRB0 and UE Contention Resolution Identity CE. @@ -196,6 +193,8 @@ class ue /// UE UL Logical Channel Manager. ul_logical_channel_manager ul_lc_ch_mgr; + slot_point last_sl_tx; + /// UE Timing Advance Manager. ta_manager ta_mgr; diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 164f633cc1..1133afa24d 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -107,11 +107,6 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i return; } - if ((srb_buffer_bytes > 0) != u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { - logger.error("ue={}: UE logical channel state is inconsistent with RLC buffer update"); - return; - } - auto ue_it = std::find_if( pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_index, is_srb0](const fallback_ue& ue) { return ue.ue_index == ue_index and (not ue.is_srb0.has_value() or ue.is_srb0.value() == is_srb0); @@ -121,6 +116,17 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i // The UE has already data pending. ue_it->is_srb0 = is_srb0; ue_it->pending_srb1_buffer_bytes = get_pending_dl_srb_bytes(ue_index, sl, is_srb0, srb_buffer_bytes); + + if ((ue_it->pending_srb1_buffer_bytes > 0) != u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { + logger.error("ue={}: UE logical channel state is inconsistent with RLC buffer update", ue_index); + return; + } + + return; + } + + if ((srb_buffer_bytes > 0) != u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { + logger.error("ue={}: UE logical channel state is inconsistent with RLC buffer update", ue_index); return; } @@ -369,7 +375,6 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res } if (slots_with_no_pdxch_space[next_slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE]) { - logger.debug("rnti={}: Skipping slot {}. Cause: no PDSCH/PDCCH space available", u.crnti, next_slot); continue; } @@ -1368,7 +1373,7 @@ unsigned ue_fallback_scheduler::get_pending_dl_srb_bytes(du_ue_index_t ue_idx, bool is_srb0, unsigned dl_rlc_bo_update) const { - if (not is_srb0) { + if (is_srb0) { return dl_rlc_bo_update; } diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 60deaabdc8..1a9ddb68f1 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -38,9 +38,6 @@ void ue_scheduler_impl::add_cell(const ue_scheduler_cell_params& params) void ue_scheduler_impl::run_sched_strategy(slot_point slot_tx, du_cell_index_t cell_index) { - // Update all UEs state. - ue_db.slot_indication(slot_tx); - if (not ue_res_grid_view.get_cell_cfg_common(cell_index).is_dl_enabled(slot_tx)) { // This slot is inactive for PDCCH in this cell. We therefore, can skip the scheduling strategy. // Note: we are currently assuming that all cells have the same TDD pattern and that the scheduling strategy @@ -195,6 +192,9 @@ void ue_scheduler_impl::run_slot(slot_point slot_tx) // Process any pending events that are directed at UEs. event_mng.run(slot_tx, cell_index); + // Update all UEs state. + ue_db.slot_indication(slot_tx); + // Mark the start of a new slot in the UE grid allocator. ue_alloc.slot_indication(slot_tx); diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 0048a023c7..4af5c15bba 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -195,6 +195,8 @@ class base_fallback_tester bench->csi_rs_sched.run_slot(bench->res_grid[0]); + bench->ue_db.slot_indication(current_slot); + bench->fallback_sched.run_slot(bench->res_grid); result_logger.on_scheduler_result(bench->res_grid[0].result); @@ -217,7 +219,7 @@ class base_fallback_tester sched_cell_configuration_request_message create_custom_cell_config_request(unsigned k0, const std::optional& tdd_cfg = {}) { - if (duplx_mode == srsran::duplex_mode::TDD and tdd_cfg.has_value()) { + if (duplx_mode == duplex_mode::TDD and tdd_cfg.has_value()) { builder_params.tdd_ul_dl_cfg_common = *tdd_cfg; } sched_cell_configuration_request_message msg = From 007dd8b348906ea9f1d7aab12957d3c409de92dc Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 10 Dec 2024 11:20:35 +0100 Subject: [PATCH 106/227] sched: remove unnecessary tracking of srb1 pending bytes in fallback scheduler --- .../ue_scheduling/ue_event_manager.cpp | 3 +- .../ue_scheduling/ue_fallback_scheduler.cpp | 70 ++----------------- .../ue_scheduling/ue_fallback_scheduler.h | 15 +--- .../ue_scheduling/fallback_scheduler_test.cpp | 2 +- 4 files changed, 9 insertions(+), 81 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 0483cce745..f13439decd 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -83,8 +83,7 @@ class ue_event_manager::ue_dl_buffer_occupancy_manager final : public scheduler_ auto& du_pcell = parent.du_cells[u.get_pcell().cell_index]; if (u.get_pcell().is_in_fallback_mode()) { // Signal SRB fallback scheduler with the new SRB0/SRB1 buffer state. - du_pcell.fallback_sched->handle_dl_buffer_state_indication( - dl_bo.ue_index, dl_bo.lcid == LCID_SRB0, sl, dl_bo.bs); + du_pcell.fallback_sched->handle_dl_buffer_state_indication(dl_bo.ue_index, dl_bo.lcid == LCID_SRB0); } // Log event. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 1133afa24d..01e302d269 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -92,10 +92,7 @@ void ue_fallback_scheduler::run_slot(cell_resource_allocator& res_alloc) schedule_dl_new_tx(res_alloc, dl_new_tx_alloc_type::srb1); } -void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_index, - bool is_srb0, - slot_point sl, - unsigned srb_buffer_bytes) +void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_index, bool is_srb0) { if (not ues.contains(ue_index)) { logger.error("ue={}: DL Buffer Occupancy update discarded. UE is not found in the scheduler", ue_index); @@ -114,24 +111,12 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i if (ue_it != pending_dl_ues_new_tx.end()) { // The UE has already data pending. - ue_it->is_srb0 = is_srb0; - ue_it->pending_srb1_buffer_bytes = get_pending_dl_srb_bytes(ue_index, sl, is_srb0, srb_buffer_bytes); - - if ((ue_it->pending_srb1_buffer_bytes > 0) != u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { - logger.error("ue={}: UE logical channel state is inconsistent with RLC buffer update", ue_index); - return; - } - - return; - } - - if ((srb_buffer_bytes > 0) != u.has_pending_dl_newtx_bytes(is_srb0 ? LCID_SRB0 : LCID_SRB1)) { - logger.error("ue={}: UE logical channel state is inconsistent with RLC buffer update", ue_index); + ue_it->is_srb0 = is_srb0; return; } // The UE doesn't exist in the internal fallback scheduler list, add it. - pending_dl_ues_new_tx.push_back({ue_index, is_srb0, u.is_conres_ce_pending(), srb_buffer_bytes}); + pending_dl_ues_new_tx.push_back({ue_index, is_srb0, u.is_conres_ce_pending()}); } void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) @@ -162,7 +147,7 @@ void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) return; } - pending_dl_ues_new_tx.push_back({ue_index, std::nullopt, true, 0}); + pending_dl_ues_new_tx.push_back({ue_index, std::nullopt, true}); } void ue_fallback_scheduler::handle_ul_bsr_indication(du_ue_index_t ue_index, const ul_bsr_indication_message& bsr_ind) @@ -873,15 +858,6 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u // Set MAC logical channels to schedule in this PDU. if (not is_retx) { u.build_dl_fallback_transport_block_info(msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes); - if (is_srb0.has_value() and not is_srb0.value()) { - auto* msg_lcid_it = - std::find_if(msg.tb_list.back().lc_chs_to_sched.begin(), - msg.tb_list.back().lc_chs_to_sched.end(), - [](const dl_msg_lc_info& lc_info) { return lc_info.lcid == lcid_t::LCID_SRB1; }); - srb1_bytes_allocated = msg_lcid_it != msg.tb_list.back().lc_chs_to_sched.end() ? msg_lcid_it->sched_bytes : 0; - // Update the internal state of the SRB1 buffer for LCID-1 bytes left to transmit (exclude overhead). - update_srb1_buffer_state_after_alloc(u.ue_index, srb1_bytes_allocated); - } } break; } @@ -901,15 +877,6 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u // Set MAC logical channels to schedule in this PDU. if (not is_retx) { u.build_dl_fallback_transport_block_info(msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes); - if (is_srb0.has_value() and not is_srb0.value()) { - auto* mcs_lcid_it = - std::find_if(msg.tb_list.back().lc_chs_to_sched.begin(), - msg.tb_list.back().lc_chs_to_sched.end(), - [](const dl_msg_lc_info& lc_info) { return lc_info.lcid == lcid_t::LCID_SRB1; }); - srb1_bytes_allocated = mcs_lcid_it != msg.tb_list.back().lc_chs_to_sched.end() ? mcs_lcid_it->sched_bytes : 0; - // Update the internal state of the SRB1 buffer for LCID-1 bytes left to transmit (exclude overhead). - update_srb1_buffer_state_after_alloc(u.ue_index, srb1_bytes_allocated); - } } break; } @@ -1330,15 +1297,8 @@ void ue_fallback_scheduler::store_harq_tx(du_ue_index_t unsigned ue_fallback_scheduler::get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) const { - auto it = std::find_if(pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_idx](const fallback_ue& ue) { - return ue.ue_index == ue_idx and ue.is_srb0.has_value() and not ue.is_srb0.value(); - }); - if (it == pending_dl_ues_new_tx.end()) { - return 0U; - } - // Note: this function assumes the ues[ue_idx] exists, which is guaranteed by the caller. - const unsigned mac_bytes = get_mac_sdu_required_bytes(it->pending_srb1_buffer_bytes); + const unsigned mac_bytes = ues[ue_idx].pending_dl_newtx_bytes(LCID_SRB1); const unsigned ce_bytes = ues[ue_idx].pending_ce_bytes(); // Each RLC buffer state update includes extra 4 bytes compared to the number of bytes left to transmit; this is to // account for the segmentation overhead. Suppose that (i) we need to compute the PDSCH TBS to allocate the last @@ -1350,24 +1310,6 @@ unsigned ue_fallback_scheduler::get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) return mac_bytes + ce_bytes + overallocation; } -void ue_fallback_scheduler::update_srb1_buffer_state_after_alloc(du_ue_index_t ue_idx, unsigned allocated_bytes) -{ - // Retrieve the UE from the list of UEs that need to be scheduled. - auto ue_it = - std::find_if(pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_idx](const fallback_ue& ue) { - return ue.ue_index == ue_idx and ue.is_srb0.has_value() and not ue.is_srb0.value(); - }); - if (ue_it == pending_dl_ues_new_tx.end() or not ues.contains(ue_idx)) { - return; - } - - if (ue_it->pending_srb1_buffer_bytes > allocated_bytes) { - ue_it->pending_srb1_buffer_bytes -= allocated_bytes; - } else { - ue_it->pending_srb1_buffer_bytes = 0U; - } -} - unsigned ue_fallback_scheduler::get_pending_dl_srb_bytes(du_ue_index_t ue_idx, slot_point sl, bool is_srb0, @@ -1447,7 +1389,7 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) if (ue_it->is_srb0.has_value() and not ue_it->is_srb0.value()) { // NOTE: the UEs that have pending RE-TXs are handled by the \ref ongoing_ues_ack_retxs and can be removed from // \ref pending_dl_ues_new_tx. - const bool remove_ue = ue_it->pending_srb1_buffer_bytes == 0 and + const bool remove_ue = not u.has_pending_dl_newtx_bytes(LCID_SRB1) and ongoing_ues_ack_retxs.end() == std::find_if(ongoing_ues_ack_retxs.begin(), ongoing_ues_ack_retxs.end(), diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index bd48e49708..9f0187413e 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -30,10 +30,7 @@ class ue_fallback_scheduler /// Handles DL buffer state reported by upper layers. /// \param[in] ue_index UE's DU Index for which SRB0 message needs to be scheduled. /// \param[in] is_srb0 Defines whether the DL Buffer State Indication is for SRB0/SRB1. - /// \param[in] sl Slot at which the DL Buffer State Indication was received. - /// \param[in] srb_buffer_bytes Number of SRB bytes reported by Buffer State Indication. - void - handle_dl_buffer_state_indication(du_ue_index_t ue_index, bool is_srb0, slot_point sl, unsigned srb_buffer_bytes); + void handle_dl_buffer_state_indication(du_ue_index_t ue_index, bool is_srb0); /// Handle Contention Resolution indication sent by the MAC. /// \param[in] ue_index UE's DU Index for which Contention Resolution CE needs to be scheduled. @@ -67,10 +64,6 @@ class ue_fallback_scheduler std::optional is_srb0; // This field indicated whether ConRes CE pending to be sent or not. bool is_conres_pending = false; - // Represents the number of LCID-1 bytes (excluding any overhead) that are pending for this UE. - // This is only meaningful for SRB1 and gets updated every time an RLC buffer state update is received or when we - // schedule a new PDSCH TX for this UE. - unsigned pending_srb1_buffer_bytes = 0; }; /// Helper that schedules DL SRB0 and SRB1 retx. Returns false if the DL fallback schedule should stop the DL @@ -216,12 +209,6 @@ class ue_fallback_scheduler // Checks if there are bytes pending for SRB1 for a given UE (including MAC CE and MAC subheaders). unsigned has_pending_bytes_for_srb1(du_ue_index_t ue_idx) const; - // \brief Updates the UE's SRB1 buffer state (only LCID 1 bytes, without any overhead) after the allocation of a HARQ - // process for a new transmission. - // \param[in] ue_idx UE's DU Index for which SRB1 buffer state needs to be updated. - // \param[in] allocated_bytes Number of bytes (only LCID 1 bytes, without any overhead) allocated on the PDSCH. - void update_srb1_buffer_state_after_alloc(du_ue_index_t ue_idx, unsigned allocated_bytes); - // \brief Updates the UE's SRB1 buffer state (only LCID 1 bytes, without any overhead) after receiving the RLC buffer // state update from upper layers. // diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 4af5c15bba..867a720e70 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -310,7 +310,7 @@ class base_fallback_tester } // Notify scheduler of DL buffer state. - bench->fallback_sched.handle_dl_buffer_state_indication(ue_idx, is_srb0, sl, buffer_size); + bench->fallback_sched.handle_dl_buffer_state_indication(ue_idx, is_srb0); } void push_buffer_state_to_ul_ue(du_ue_index_t ue_idx, slot_point sl, unsigned buffer_size) From 269c57c89ed3dba35332b05a184b130757e14cb1 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 10 Dec 2024 11:24:10 +0100 Subject: [PATCH 107/227] sched: remove unnecessary tracking of conres CE pendign in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 19 +++++-------------- .../ue_scheduling/ue_fallback_scheduler.h | 2 -- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 01e302d269..3aac4d0b15 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -116,7 +116,7 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i } // The UE doesn't exist in the internal fallback scheduler list, add it. - pending_dl_ues_new_tx.push_back({ue_index, is_srb0, u.is_conres_ce_pending()}); + pending_dl_ues_new_tx.push_back({ue_index, is_srb0}); } void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) @@ -143,11 +143,10 @@ void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) // Entry for this UE already exists. if (ue_it != pending_dl_ues_new_tx.end()) { - ue_it->is_conres_pending = true; return; } - pending_dl_ues_new_tx.push_back({ue_index, std::nullopt, true}); + pending_dl_ues_new_tx.push_back({ue_index, std::nullopt}); } void ue_fallback_scheduler::handle_ul_bsr_indication(du_ue_index_t ue_index, const ul_bsr_indication_message& bsr_ind) @@ -226,13 +225,13 @@ void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& ue_fallback_scheduler::dl_new_tx_alloc_type ue_fallback_scheduler::get_dl_new_tx_alloc_type(const fallback_ue& next_ue) const { + auto& u = ues[next_ue.ue_index]; if (not next_ue.is_srb0.has_value()) { // No SRB0 or SRB1. Verify if ConRes CE needs to be scheduled. - return next_ue.is_conres_pending ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; + return u.is_conres_ce_pending() ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; } if (next_ue.is_srb0.value()) { - auto& u = ues[next_ue.ue_index]; return u.has_pending_dl_newtx_bytes(LCID_SRB0) ? dl_new_tx_alloc_type::srb0 : dl_new_tx_alloc_type::error; } @@ -281,9 +280,6 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo // There was an allocation. This does not, however, mean that the pending data was completely flushed. - // We assume that there is always space for ConRes CE when an allocation takes place. - next_ue->is_conres_pending = false; - if (alloc_type == dl_new_tx_alloc_type::conres_only or alloc_type == dl_new_tx_alloc_type::srb0) { // ConRes-only, SRB0-ony and ConRes+SRB0 cases @@ -1372,12 +1368,7 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) continue; } - if (ue_it->is_conres_pending != u.is_conres_ce_pending()) { - logger.error("ue={}: Invalid ConRes state detected", ue_it->ue_index); - ue_it->is_conres_pending = u.is_conres_ce_pending(); - } - - if (not ue_it->is_conres_pending and not ue_it->is_srb0.has_value()) { + if (not u.is_conres_ce_pending() and not ue_it->is_srb0.has_value()) { // UE has no new txs pending. It can be removed. ue_it = pending_dl_ues_new_tx.erase(ue_it); continue; diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 9f0187413e..be5a6ea717 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -62,8 +62,6 @@ class ue_fallback_scheduler // This field is empty if only ConRes indication is received from MAC and buffer status from upper layers for // SRB0/SRB1 is not yet received. std::optional is_srb0; - // This field indicated whether ConRes CE pending to be sent or not. - bool is_conres_pending = false; }; /// Helper that schedules DL SRB0 and SRB1 retx. Returns false if the DL fallback schedule should stop the DL From 6a022ce3a7378c88af4d43e521f597a2ee40088a Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 10 Dec 2024 12:39:33 +0100 Subject: [PATCH 108/227] fix invalid access to to_lcid() in ue class --- .../srsran/ran/logical_channel/lcid_dl_sch.h | 2 +- lib/scheduler/ue_context/ue.cpp | 2 +- .../ue_scheduling/ue_fallback_scheduler.cpp | 31 ------------------- .../ue_scheduling/ue_fallback_scheduler.h | 13 -------- 4 files changed, 2 insertions(+), 46 deletions(-) diff --git a/include/srsran/ran/logical_channel/lcid_dl_sch.h b/include/srsran/ran/logical_channel/lcid_dl_sch.h index 65223d1d4d..2070e796cf 100644 --- a/include/srsran/ran/logical_channel/lcid_dl_sch.h +++ b/include/srsran/ran/logical_channel/lcid_dl_sch.h @@ -71,7 +71,7 @@ class lcid_dl_sch_t lcid_t to_lcid() const { - srsran_assert(is_sdu(), "Invalid to_lcid() access"); + srsran_assert(is_sdu(), "Invalid to_lcid() access to lcid={}", lcid_val); return (lcid_t)lcid_val; } diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index a1dc9199b3..d6749d5c37 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -140,7 +140,7 @@ void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_mess rem_harqs--; if (h_dl->pdsch_slot() >= last_sl_tx and h_dl->nof_retxs() == 0 and h_dl->is_waiting_ack()) { for (const auto& lc : h_dl->get_grant_params().lc_sched_info) { - if (lc.lcid.to_lcid() == msg.lcid) { + if (lc.lcid.is_sdu() and lc.lcid.to_lcid() == msg.lcid) { pending_bytes -= std::min(pending_bytes, lc.sched_bytes.value()); } } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 3aac4d0b15..32c1c19a1b 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1306,37 +1306,6 @@ unsigned ue_fallback_scheduler::get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) return mac_bytes + ce_bytes + overallocation; } -unsigned ue_fallback_scheduler::get_pending_dl_srb_bytes(du_ue_index_t ue_idx, - slot_point sl, - bool is_srb0, - unsigned dl_rlc_bo_update) const -{ - if (is_srb0) { - return dl_rlc_bo_update; - } - - unsigned srb1_buffer_bytes = dl_rlc_bo_update; - - // Subtract the LCID1 bytes that are scheduled but not yet transmitted. - auto& u = ues[ue_idx]; - auto& ue_pcell = u.get_pcell(); - for (unsigned i = 0, e = ue_pcell.harqs.nof_dl_harqs(); i < e; ++i) { - auto h_dl = ue_pcell.harqs.dl_harq(to_harq_id(i)); - if (h_dl.has_value() and h_dl->is_waiting_ack() and h_dl->pdsch_slot() >= sl and h_dl->nof_retxs() == 0) { - for (const auto& lc : h_dl->get_grant_params().lc_sched_info) { - if (lc.lcid.to_lcid() == LCID_SRB1) { - srb1_buffer_bytes -= std::min(srb1_buffer_bytes, lc.sched_bytes.value()); - if (srb1_buffer_bytes == 0) { - return 0; - } - } - } - } - } - - return srb1_buffer_bytes; -} - void ue_fallback_scheduler::slot_indication(slot_point sl) { // If there is any skipped slot, reset \ref slots_with_no_pdxch_space for all the skipped slots. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index be5a6ea717..c29a063da9 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -207,19 +207,6 @@ class ue_fallback_scheduler // Checks if there are bytes pending for SRB1 for a given UE (including MAC CE and MAC subheaders). unsigned has_pending_bytes_for_srb1(du_ue_index_t ue_idx) const; - // \brief Updates the UE's SRB1 buffer state (only LCID 1 bytes, without any overhead) after receiving the RLC buffer - // state update from upper layers. - // - // This function updates the fallback scheduler internal SRB1 buffer state for a given UE by subtracting the bytes for - // the new allocations (that have been already completed but not yet transmitted) from the RLC buffer state update - // that was received. - // - // \param[in] ue_idx UE's DU Index for which SRB1 buffer state needs to be updated. - // \param[in] sl Slot at which the Buffer State Update was received. - // \param[in] buffer_status_report Number of pending LCID 1 bytes reported by the RLC buffer state update (only LCID 1 - // bytes, without any overhead). - unsigned get_pending_dl_srb_bytes(du_ue_index_t ue_idx, slot_point sl, bool is_srb0, unsigned dl_rlc_bo_update) const; - const scheduler_ue_expert_config& expert_cfg; const cell_configuration& cell_cfg; // TODO: Find proper values for these 2 parameters. From 61df04a708b42f3d997edab638cf51550d4b5e71 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 10 Dec 2024 15:55:04 +0100 Subject: [PATCH 109/227] sched: simplify removal of UE from fallback scheduler --- .../ue_context/dl_logical_channel_manager.h | 5 ++-- .../ue_scheduling/ue_fallback_scheduler.cpp | 24 +------------------ 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index 31914d6f4d..af30314cd7 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -57,9 +57,8 @@ class dl_logical_channel_manager /// \remark Excludes data for SRB0. bool has_pending_bytes() const { - return has_pending_ces() or std::any_of(channels.begin() + 1, channels.end(), [](const auto& ch) { - return ch.active and ch.buf_st > 0; - }); + return has_pending_ces() or + std::any_of(channels.begin(), channels.end(), [](const auto& ch) { return ch.active and ch.buf_st > 0; }); } /// \brief Checks whether a logical channel has pending data. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 32c1c19a1b..bfaffb34bb 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1336,34 +1336,12 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) ue_it = pending_dl_ues_new_tx.erase(ue_it); continue; } - - if (not u.is_conres_ce_pending() and not ue_it->is_srb0.has_value()) { + if (not u.has_pending_dl_newtx_bytes()) { // UE has no new txs pending. It can be removed. ue_it = pending_dl_ues_new_tx.erase(ue_it); continue; } - // Remove UE when the SRB1 buffer status is empty and when there are no HARQ processes scheduled for future - // transmissions. - // TODO: Verify if this is still needed. - if (ue_it->is_srb0.has_value() and not ue_it->is_srb0.value()) { - // NOTE: the UEs that have pending RE-TXs are handled by the \ref ongoing_ues_ack_retxs and can be removed from - // \ref pending_dl_ues_new_tx. - const bool remove_ue = not u.has_pending_dl_newtx_bytes(LCID_SRB1) and - ongoing_ues_ack_retxs.end() == - std::find_if(ongoing_ues_ack_retxs.begin(), - ongoing_ues_ack_retxs.end(), - [ue_idx = ue_it->ue_index, sl](const ack_and_retx_tracker& tracker) { - return tracker.ue_index == ue_idx and tracker.h_dl->is_waiting_ack() and - tracker.h_dl->nof_retxs() == 0 and - tracker.h_dl->pdsch_slot() >= sl; - }); - if (remove_ue) { - ue_it = pending_dl_ues_new_tx.erase(ue_it); - continue; - } - } - ++ue_it; } From f6e848ee77a8759b6b5a550303251916721d5ca2 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 10 Dec 2024 17:16:50 +0100 Subject: [PATCH 110/227] sched: consider UE mode when computing pending bytes --- lib/scheduler/ue_context/ue.cpp | 18 +++++++++++++++++- lib/scheduler/ue_context/ue.h | 3 +-- .../ue_scheduling/ue_fallback_scheduler.cpp | 15 ++++++--------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index d6749d5c37..609615193b 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -153,9 +153,25 @@ void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_mess dl_lc_ch_mgr.handle_dl_buffer_status_indication(msg.lcid, pending_bytes); } +bool ue::has_pending_dl_newtx_bytes() const +{ + if (get_pcell().is_in_fallback_mode()) { + return dl_lc_ch_mgr.has_pending_ces() or dl_lc_ch_mgr.has_pending_bytes(LCID_SRB0) or + dl_lc_ch_mgr.has_pending_bytes(LCID_SRB1); + } + return dl_lc_ch_mgr.has_pending_bytes(); +} + unsigned ue::pending_dl_newtx_bytes(lcid_t lcid) const { - return lcid != INVALID_LCID ? dl_lc_ch_mgr.pending_bytes(lcid) : dl_lc_ch_mgr.pending_bytes(); + if (lcid != INVALID_LCID) { + return dl_lc_ch_mgr.pending_bytes(lcid); + } + if (get_pcell().is_in_fallback_mode()) { + return dl_lc_ch_mgr.pending_ce_bytes() + dl_lc_ch_mgr.pending_bytes(LCID_SRB0) + + dl_lc_ch_mgr.pending_bytes(LCID_SRB1); + } + return dl_lc_ch_mgr.pending_bytes(); } unsigned ue::pending_ul_newtx_bytes() const diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index ba2cd7529d..6da64d9e97 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -117,8 +117,7 @@ class ue /// \brief Checks if there are DL pending bytes that are yet to be allocated in a DL HARQ. /// This method is faster than computing \c pending_dl_newtx_bytes() > 0. - /// \remark Excludes SRB0 and UE Contention Resolution Identity CE. - bool has_pending_dl_newtx_bytes() const { return dl_lc_ch_mgr.has_pending_bytes(); } + bool has_pending_dl_newtx_bytes() const; /// \brief Checks if there are DL pending bytes for a specific LCID that are yet to be allocated in a DL HARQ. bool has_pending_dl_newtx_bytes(lcid_t lcid) const { return dl_lc_ch_mgr.has_pending_bytes(lcid); } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index bfaffb34bb..6b395a53bf 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -850,11 +850,6 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u pdcch.dci.tc_rnti_f1_0, ue_grant_crbs, not is_retx); - - // Set MAC logical channels to schedule in this PDU. - if (not is_retx) { - u.build_dl_fallback_transport_block_info(msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes); - } break; } case dci_dl_rnti_config_type::c_rnti_f1_0: { @@ -870,10 +865,6 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u pdcch.dci.c_rnti_f1_0, ue_grant_crbs, not is_retx); - // Set MAC logical channels to schedule in this PDU. - if (not is_retx) { - u.build_dl_fallback_transport_block_info(msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes); - } break; } default: { @@ -881,6 +872,12 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u } } + // Set MAC logical channels to schedule in this PDU. + if (not is_retx) { + u.build_dl_fallback_transport_block_info(msg.tb_list.emplace_back(), msg.pdsch_cfg.codewords[0].tb_size_bytes); + msg.context.buffer_occupancy = u.pending_dl_newtx_bytes(); + } + // Save in HARQ the parameters set for this PDCCH and PDSCH PDUs. dl_harq_alloc_context ctxt{pdcch.dci.type, std::nullopt, std::nullopt, std::nullopt, true}; h_dl->save_grant_params(ctxt, msg); From 53f4bf0ab0a49823505465730e2dfe934f781525 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 10:38:00 +0100 Subject: [PATCH 111/227] sched: fix bytes pending derivation for fallback --- .../ue_context/dl_logical_channel_manager.h | 29 ++++++++++++++++--- lib/scheduler/ue_context/ue.cpp | 16 ++-------- .../ue_scheduling/logical_channel_test.cpp | 3 +- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index af30314cd7..33755e847c 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -54,15 +54,25 @@ class dl_logical_channel_manager } /// \brief Checks whether the UE has pending data. - /// \remark Excludes data for SRB0. bool has_pending_bytes() const { return has_pending_ces() or std::any_of(channels.begin(), channels.end(), [](const auto& ch) { return ch.active and ch.buf_st > 0; }); } + /// \brief Check whether the UE has pending data, given its current state. + bool has_pending_bytes(bool fallback_enabled) const + { + if (fallback_enabled) { + return is_con_res_id_pending() or has_pending_bytes(LCID_SRB0) or has_pending_bytes(LCID_SRB1); + } + return has_pending_ces() or std::any_of(channels.begin() + 1, channels.end(), [](const auto& ch) { + return ch.active and ch.buf_st > 0; + }); + } + /// \brief Checks whether a logical channel has pending data. - bool has_pending_bytes(lcid_t lcid) const { return pending_bytes(lcid) > 0; } + bool has_pending_bytes(lcid_t lcid) const { return channels[lcid].active and channels[lcid].buf_st > 0; } /// \brief Checks whether a ConRes CE is pending for transmission. bool is_con_res_id_pending() const { return pending_con_res_id; } @@ -71,11 +81,22 @@ class dl_logical_channel_manager bool has_pending_ces() const { return pending_con_res_id or not pending_ces.empty(); } /// \brief Calculates total number of DL bytes, including MAC header overhead. - /// \remark Excludes data for SRB0 and UE Contention Resolution Identity CE. unsigned pending_bytes() const { unsigned bytes = pending_ce_bytes(); - // Skip index 0 ==> SRB0. + for (unsigned i = 0; i <= MAX_LCID; ++i) { + bytes += pending_bytes((lcid_t)i); + } + return bytes; + } + + /// \brief Calculates number of DL pending bytes, including MAC header overhead, and taking UE state into account. + unsigned pending_bytes(bool fallback_enabled) const + { + if (fallback_enabled) { + return pending_con_res_ce_bytes() + pending_bytes(LCID_SRB0) + pending_bytes(LCID_SRB1); + } + unsigned bytes = pending_ce_bytes(); for (unsigned i = 1; i <= MAX_LCID; ++i) { bytes += pending_bytes((lcid_t)i); } diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 609615193b..c666148214 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -155,23 +155,13 @@ void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_mess bool ue::has_pending_dl_newtx_bytes() const { - if (get_pcell().is_in_fallback_mode()) { - return dl_lc_ch_mgr.has_pending_ces() or dl_lc_ch_mgr.has_pending_bytes(LCID_SRB0) or - dl_lc_ch_mgr.has_pending_bytes(LCID_SRB1); - } - return dl_lc_ch_mgr.has_pending_bytes(); + return dl_lc_ch_mgr.has_pending_bytes(get_pcell().is_in_fallback_mode()); } unsigned ue::pending_dl_newtx_bytes(lcid_t lcid) const { - if (lcid != INVALID_LCID) { - return dl_lc_ch_mgr.pending_bytes(lcid); - } - if (get_pcell().is_in_fallback_mode()) { - return dl_lc_ch_mgr.pending_ce_bytes() + dl_lc_ch_mgr.pending_bytes(LCID_SRB0) + - dl_lc_ch_mgr.pending_bytes(LCID_SRB1); - } - return dl_lc_ch_mgr.pending_bytes(); + return lcid != INVALID_LCID ? dl_lc_ch_mgr.pending_bytes(lcid) + : dl_lc_ch_mgr.pending_bytes(get_pcell().is_in_fallback_mode()); } unsigned ue::pending_ul_newtx_bytes() const diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index 1218c62a15..42564365fa 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -115,8 +115,7 @@ TEST(dl_logical_channel_test, total_pending_bytes_equal_sum_of_logical_channel_p lch_mng.handle_dl_buffer_status_indication(lcid, dl_bs); } - ASSERT_EQ(lch_mng.pending_bytes() + lch_mng.pending_bytes(LCID_SRB0), - std::accumulate(buf_st_inds.begin(), buf_st_inds.end(), 0)); + ASSERT_EQ(lch_mng.pending_bytes(), std::accumulate(buf_st_inds.begin(), buf_st_inds.end(), 0)); ASSERT_FALSE(lch_mng.has_pending_ces()); for (unsigned i = 0; i != lcids.size(); ++i) { ASSERT_EQ(lch_mng.pending_bytes(lcids[i]), buf_st_inds[i]); From f3ae1abecf59740da7fbd9fccb42b92f0a99b27b Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 11:05:36 +0100 Subject: [PATCH 112/227] sched: remove unnecessary methods to compute pending bytes in fallback scheduler --- lib/scheduler/ue_context/ue.cpp | 12 ++++- .../ue_scheduling/ue_fallback_scheduler.cpp | 48 ++++--------------- .../ue_scheduling/ue_fallback_scheduler.h | 6 --- 3 files changed, 20 insertions(+), 46 deletions(-) diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index c666148214..c5e3a71e8f 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -127,8 +127,14 @@ void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_mess { unsigned pending_bytes = msg.bs; - // Subtract bytes pending for this LCID in scheduled HARQ allocations before forwarding to DL logical channel. + // Subtract bytes pending for this LCID in scheduled DL HARQ allocations (but not yet sent to the lower layers) + // before forwarding to DL logical channel manager. // Note: The RLC buffer occupancy updates never account for bytes associated with future HARQ transmissions. + // Note: The TB in the HARQ should also include RLC header segmentation overhead which is not accounted yet in the + // reported RLC DL buffer occupancy report (reminder: we haven't built the RLC PDU yet!). If we account for this + // overhead in the computation of pending bytes, the final value will be too low, which will lead to one extra + // tiny grant. To avoid this, we make the pessimization that every HARQ contains one RLC header due to segmentation. + constexpr static unsigned RLC_AM_HEADER_SIZE_ESTIM = 4; for (unsigned c = 0, ce = nof_cells(); c != ce; ++c) { auto& ue_cc = *ue_cells[c]; @@ -141,7 +147,9 @@ void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_mess if (h_dl->pdsch_slot() >= last_sl_tx and h_dl->nof_retxs() == 0 and h_dl->is_waiting_ack()) { for (const auto& lc : h_dl->get_grant_params().lc_sched_info) { if (lc.lcid.is_sdu() and lc.lcid.to_lcid() == msg.lcid) { - pending_bytes -= std::min(pending_bytes, lc.sched_bytes.value()); + unsigned bytes_sched = + lc.sched_bytes.value() - std::min(lc.sched_bytes.value(), RLC_AM_HEADER_SIZE_ESTIM); + pending_bytes -= std::min(pending_bytes, bytes_sched); } } } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 6b395a53bf..3a3fc8987e 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -230,19 +230,12 @@ ue_fallback_scheduler::get_dl_new_tx_alloc_type(const fallback_ue& next_ue) cons // No SRB0 or SRB1. Verify if ConRes CE needs to be scheduled. return u.is_conres_ce_pending() ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; } - if (next_ue.is_srb0.value()) { return u.has_pending_dl_newtx_bytes(LCID_SRB0) ? dl_new_tx_alloc_type::srb0 : dl_new_tx_alloc_type::error; } - - // NOTE: Since SRB1 data can be segmented, it could happen that not all the SRB1 bytes are scheduled at once. The - // scheduler will attempt to allocate those remaining bytes in the following slots. The policy we adopt in this - // scheduler is to schedule first all possible grants to a given UE (to speed up the re-establishment and - // re-configuration). Only after the SRB1 buffer of that UE is emptied, we move on to the next UE. - if (has_pending_bytes_for_srb1(next_ue.ue_index)) { + if (u.has_pending_dl_newtx_bytes(LCID_SRB1)) { return dl_new_tx_alloc_type::srb1; } - return dl_new_tx_alloc_type::skip; } @@ -296,7 +289,7 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo // Move to the next UE ONLY IF the UE has no more pending bytes for SRB1. This is to give priority to the same // UE, if there are still some SRB1 bytes left in the buffer. At the next iteration, the scheduler will try // again with the same scheduler, but starting from the next available slot. - if (not has_pending_bytes_for_srb1(u.ue_index)) { + if (not u.has_pending_dl_newtx_bytes()) { ++next_ue; } } @@ -543,21 +536,20 @@ ue_fallback_scheduler::alloc_grant(ue& u, ue_grant_crbs = {unused_crbs.start(), unused_crbs.start() + prbs_tbs.nof_prbs}; } else { - const unsigned only_conres_bytes = u.pending_conres_ce_bytes(); - const unsigned only_srb0_bytes = is_srb0.has_value() and is_srb0.value() ? u.pending_dl_newtx_bytes(LCID_SRB0) : 0; - unsigned pending_bytes = only_conres_bytes + only_srb0_bytes; - std::optional fixed_mcs; - if (is_srb0.has_value() and not is_srb0.value()) { - pending_bytes = std::max(pending_bytes, get_srb1_pending_tot_bytes(u.ue_index)); - fixed_mcs = map_cqi_to_mcs(expert_cfg.initial_cqi, pdsch_cfg.mcs_table); - srsran_assert(fixed_mcs.has_value(), "Invalid Initial CQI {}", expert_cfg.initial_cqi); - } + const unsigned pending_bytes = u.pending_dl_newtx_bytes(); srsran_assert(pending_bytes > 0, "Unexpected number of pending bytes"); + const unsigned only_conres_bytes = u.pending_conres_ce_bytes(); + const unsigned only_srb0_bytes = u.pending_dl_newtx_bytes(LCID_SRB0); // There must be space for ConRes CE, if it is pending. If only SRB0 is pending (no ConRes), there must be space // for it, as the SRB0 cannot be segmented. const unsigned min_pending_bytes = only_conres_bytes > 0 ? only_conres_bytes : (only_srb0_bytes > 0 ? only_srb0_bytes : 0); + std::optional fixed_mcs; + if (is_srb0.has_value() and not is_srb0.value()) { + fixed_mcs = map_cqi_to_mcs(expert_cfg.initial_cqi, pdsch_cfg.mcs_table); + srsran_assert(fixed_mcs.has_value(), "Invalid Initial CQI {}", expert_cfg.initial_cqi); + } std::tuple result = select_tbs(pdsch_cfg, pending_bytes, unused_crbs, fixed_mcs); unsigned chosen_tbs = std::get<2>(result).value(); @@ -1226,11 +1218,6 @@ void ue_fallback_scheduler::fill_ul_srb_grant(ue& u.reset_sr_indication(); } -unsigned ue_fallback_scheduler::has_pending_bytes_for_srb1(du_ue_index_t ue_idx) const -{ - return get_srb1_pending_tot_bytes(ue_idx) > 0U; -} - const pdsch_time_domain_resource_allocation& ue_fallback_scheduler::get_pdsch_td_cfg(unsigned pdsch_time_res_idx) const { return cell_cfg.dl_cfg_common.init_dl_bwp.pdsch_common.pdsch_td_alloc_list[pdsch_time_res_idx]; @@ -1288,21 +1275,6 @@ void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl, is_srb0); } -unsigned ue_fallback_scheduler::get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) const -{ - // Note: this function assumes the ues[ue_idx] exists, which is guaranteed by the caller. - const unsigned mac_bytes = ues[ue_idx].pending_dl_newtx_bytes(LCID_SRB1); - const unsigned ce_bytes = ues[ue_idx].pending_ce_bytes(); - // Each RLC buffer state update includes extra 4 bytes compared to the number of bytes left to transmit; this is to - // account for the segmentation overhead. Suppose that (i) we need to compute the PDSCH TBS to allocate the last - // remaining SRB1 bytes and (ii) we expect an RLC buffer state update before the PDSCH will be transmitted. By - // over-allocating 4 bytes to the MAC PDU, we ensure that the PDSCH will be able to fit all remaining bytes, including - // the 4 extra bytes added by the latest RLC buffer state update. - const unsigned overallocation_size = 4U; - const unsigned overallocation = mac_bytes != 0 ? overallocation_size : 0U; - return mac_bytes + ce_bytes + overallocation; -} - void ue_fallback_scheduler::slot_indication(slot_point sl) { // If there is any skipped slot, reset \ref slots_with_no_pdxch_space for all the skipped slots. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index c29a063da9..5e7a9f4f1b 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -201,12 +201,6 @@ class ue_fallback_scheduler std::optional h_dl, std::optional is_srb0 = std::nullopt); - // Returns the total number of bytes pending for SRB1 for a given UE, including MAC CE and MAC subheaders. - unsigned get_srb1_pending_tot_bytes(du_ue_index_t ue_idx) const; - - // Checks if there are bytes pending for SRB1 for a given UE (including MAC CE and MAC subheaders). - unsigned has_pending_bytes_for_srb1(du_ue_index_t ue_idx) const; - const scheduler_ue_expert_config& expert_cfg; const cell_configuration& cell_cfg; // TODO: Find proper values for these 2 parameters. From d40de889a9a7d5846ccb0461b8eaca6b6a25f2af Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 11:44:06 +0100 Subject: [PATCH 113/227] sched: remove unnecessary tracking of type of allocation in fallback scheduler --- .../ue_scheduling/ue_event_manager.cpp | 2 +- .../ue_scheduling/ue_fallback_scheduler.cpp | 198 +++++++----------- .../ue_scheduling/ue_fallback_scheduler.h | 81 +++---- .../ue_scheduling/fallback_scheduler_test.cpp | 2 +- 4 files changed, 107 insertions(+), 176 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index f13439decd..35f9f2c7a6 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -83,7 +83,7 @@ class ue_event_manager::ue_dl_buffer_occupancy_manager final : public scheduler_ auto& du_pcell = parent.du_cells[u.get_pcell().cell_index]; if (u.get_pcell().is_in_fallback_mode()) { // Signal SRB fallback scheduler with the new SRB0/SRB1 buffer state. - du_pcell.fallback_sched->handle_dl_buffer_state_indication(dl_bo.ue_index, dl_bo.lcid == LCID_SRB0); + du_pcell.fallback_sched->handle_dl_buffer_state_indication(dl_bo.ue_index); } // Log event. diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 3a3fc8987e..5e6c1e81da 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -92,7 +92,7 @@ void ue_fallback_scheduler::run_slot(cell_resource_allocator& res_alloc) schedule_dl_new_tx(res_alloc, dl_new_tx_alloc_type::srb1); } -void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_index, bool is_srb0) +void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_index) { if (not ues.contains(ue_index)) { logger.error("ue={}: DL Buffer Occupancy update discarded. UE is not found in the scheduler", ue_index); @@ -104,19 +104,16 @@ void ue_fallback_scheduler::handle_dl_buffer_state_indication(du_ue_index_t ue_i return; } - auto ue_it = std::find_if( - pending_dl_ues_new_tx.begin(), pending_dl_ues_new_tx.end(), [ue_index, is_srb0](const fallback_ue& ue) { - return ue.ue_index == ue_index and (not ue.is_srb0.has_value() or ue.is_srb0.value() == is_srb0); - }); + auto ue_it = std::find_if(pending_dl_ues_new_tx.begin(), + pending_dl_ues_new_tx.end(), + [ue_index](const fallback_ue& ue) { return ue.ue_index == ue_index; }); if (ue_it != pending_dl_ues_new_tx.end()) { - // The UE has already data pending. - ue_it->is_srb0 = is_srb0; return; } // The UE doesn't exist in the internal fallback scheduler list, add it. - pending_dl_ues_new_tx.push_back({ue_index, is_srb0}); + pending_dl_ues_new_tx.push_back({ue_index}); } void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) @@ -146,7 +143,7 @@ void ue_fallback_scheduler::handle_conres_indication(du_ue_index_t ue_index) return; } - pending_dl_ues_new_tx.push_back({ue_index, std::nullopt}); + pending_dl_ues_new_tx.push_back({ue_index}); } void ue_fallback_scheduler::handle_ul_bsr_indication(du_ue_index_t ue_index, const ul_bsr_indication_message& bsr_ind) @@ -194,11 +191,11 @@ void ue_fallback_scheduler::handle_sr_indication(du_ue_index_t ue_index) bool ue_fallback_scheduler::schedule_dl_retx(cell_resource_allocator& res_alloc) { for (auto& next_ue_harq_retx : ongoing_ues_ack_retxs) { - auto& u = ues[next_ue_harq_retx.ue_index]; - std::optional& h_dl = next_ue_harq_retx.h_dl; + auto& u = ues[next_ue_harq_retx.ue_index]; + dl_harq_process_handle& h_dl = next_ue_harq_retx.h_dl; - if (h_dl->has_pending_retx()) { - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, h_dl, next_ue_harq_retx.is_srb0); + if (h_dl.has_pending_retx()) { + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, h_dl); // This is the case of the scheduler reaching the maximum number of sched attempts. if (outcome == dl_sched_outcome::stop_dl_scheduling) { return false; @@ -222,21 +219,15 @@ void ue_fallback_scheduler::schedule_ul_new_tx_and_retx(cell_resource_allocator& } } -ue_fallback_scheduler::dl_new_tx_alloc_type -ue_fallback_scheduler::get_dl_new_tx_alloc_type(const fallback_ue& next_ue) const +ue_fallback_scheduler::dl_new_tx_alloc_type ue_fallback_scheduler::get_dl_new_tx_alloc_type(const ue& u) { - auto& u = ues[next_ue.ue_index]; - if (not next_ue.is_srb0.has_value()) { - // No SRB0 or SRB1. Verify if ConRes CE needs to be scheduled. - return u.is_conres_ce_pending() ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; - } - if (next_ue.is_srb0.value()) { - return u.has_pending_dl_newtx_bytes(LCID_SRB0) ? dl_new_tx_alloc_type::srb0 : dl_new_tx_alloc_type::error; + if (u.has_pending_dl_newtx_bytes(LCID_SRB0)) { + return dl_new_tx_alloc_type::srb0; } if (u.has_pending_dl_newtx_bytes(LCID_SRB1)) { return dl_new_tx_alloc_type::srb1; } - return dl_new_tx_alloc_type::skip; + return u.is_conres_ce_pending() ? dl_new_tx_alloc_type::conres_only : dl_new_tx_alloc_type::error; } bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_alloc, @@ -244,7 +235,8 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo { for (auto next_ue = pending_dl_ues_new_tx.begin(); next_ue != pending_dl_ues_new_tx.end();) { // Determine if we should schedule ConRes, SRB0, SRB1 for the given UE. - const auto alloc_type = get_dl_new_tx_alloc_type(*next_ue); + auto& u = ues[next_ue->ue_index]; + const auto alloc_type = get_dl_new_tx_alloc_type(u); if (alloc_type == dl_new_tx_alloc_type::error) { // The UE is not in a state for scheduling logger.error("ue={}: UE is an inconsistent state in the fallback scheduler", next_ue->ue_index); @@ -258,8 +250,7 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo } // Make the scheduling attempt. - auto& u = ues[next_ue->ue_index]; - dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt, next_ue->is_srb0); + dl_sched_outcome outcome = schedule_dl_srb(res_alloc, u, std::nullopt); if (outcome == dl_sched_outcome::next_ue) { // Allocation failed but we can attempt with another UE. ++next_ue; @@ -271,28 +262,12 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo return false; } - // There was an allocation. This does not, however, mean that the pending data was completely flushed. - - if (alloc_type == dl_new_tx_alloc_type::conres_only or alloc_type == dl_new_tx_alloc_type::srb0) { - // ConRes-only, SRB0-ony and ConRes+SRB0 cases - - if (outcome == dl_sched_outcome::success) { - next_ue = pending_dl_ues_new_tx.erase(next_ue); - } else { - // ConRes CE was scheduled but SRB0 wasn't. - ++next_ue; - } - } else { - // SRB1-ony and ConRes+SRB1 cases - - if (outcome == dl_sched_outcome::success) { - // Move to the next UE ONLY IF the UE has no more pending bytes for SRB1. This is to give priority to the same - // UE, if there are still some SRB1 bytes left in the buffer. At the next iteration, the scheduler will try - // again with the same scheduler, but starting from the next available slot. - if (not u.has_pending_dl_newtx_bytes()) { - ++next_ue; - } - } + // There was a successful allocation. This does not, however, mean that the pending data was completely flushed. + // Move to the next UE ONLY IF the UE has no more pending bytes. This is to give priority to the same UE, if + // there are still some bytes left in the buffer. At the next iteration, the scheduler will try + // again with the same scheduler, but starting from the next available slot. + if (not u.has_pending_dl_newtx_bytes()) { + ++next_ue; } } @@ -318,8 +293,7 @@ static slot_point get_next_srb_slot(const cell_configuration& cell_cfg, slot_poi ue_fallback_scheduler::dl_sched_outcome ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res_alloc, ue& u, - std::optional h_dl_retx, - std::optional is_srb0) + std::optional h_dl_retx) { const auto& bwp_cfg_common = cell_cfg.dl_cfg_common.init_dl_bwp; // Search valid PDSCH time domain resource. @@ -380,9 +354,8 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res // Verify there is space in PDSCH and PDCCH result lists for new allocations. if (pdcch_alloc.result.dl.dl_pdcchs.full() or pdsch_alloc.result.dl.ue_grants.full()) { - logger.debug("rnti={}: Failed to allocate PDSCH for {}. Cause: No space available in scheduler output list", - u.crnti, - not is_srb0.has_value() ? "ConRes CE" : (*is_srb0 ? "SRB0 PDU" : "SRB1 PDU")); + logger.debug("rnti={}: Failed to allocate fallback PDSCH. Cause: No space available in scheduler output list", + u.crnti); slots_with_no_pdxch_space[next_slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; continue; } @@ -398,16 +371,13 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res most_recent_ack_slot = last_slot_ack; } - sched_srb_results sched_res = alloc_grant( - u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx, is_srb0); + auto h_dl = + alloc_grant(u, res_alloc, time_res_idx.value(), offset_to_sched_ref_slot, most_recent_ack_slot, h_dl_retx); - const bool alloc_successful = sched_res.h_dl.has_value(); + const bool alloc_successful = h_dl.has_value(); if (alloc_successful) { if (not is_retx) { - store_harq_tx(u.ue_index, sched_res.h_dl, is_srb0); - } - if (sched_res.is_srb_data_pending) { - return dl_sched_outcome::srb_pending; + store_harq_tx(u.ue_index, h_dl.value()); } return dl_sched_outcome::success; } @@ -416,11 +386,11 @@ ue_fallback_scheduler::schedule_dl_srb(cell_resource_allocator& res } // No resource found in UE's carriers and Search spaces. - logger.debug("rnti={}: Skipped {} allocation in slots:[{},{}). Cause: no PDCCH/PDSCH/PUCCH resources available", - u.crnti, - not is_srb0.has_value() ? "ConRes CE" : (*is_srb0 ? "SRB0 PDU" : "SRB1 PDU"), - starting_slot, - sched_ref_slot + max_dl_slots_ahead_sched + 1); + logger.debug( + "rnti={}: Skipped fallback PDSCH allocation in slots:[{},{}). Cause: no PDCCH/PDSCH/PUCCH resources available", + u.crnti, + starting_slot, + sched_ref_slot + max_dl_slots_ahead_sched + 1); return dl_sched_outcome::next_ue; } @@ -474,14 +444,13 @@ allocate_ue_fallback_pucch(ue& u, return std::make_pair(std::nullopt, last_valid_k1); } -ue_fallback_scheduler::sched_srb_results +std::optional ue_fallback_scheduler::alloc_grant(ue& u, cell_resource_allocator& res_alloc, unsigned pdsch_time_res, unsigned slot_offset, slot_point most_recent_ack_slot, - std::optional h_dl_retx, - std::optional is_srb0) + std::optional h_dl_retx) { ue_cell& ue_pcell = u.get_pcell(); const subcarrier_spacing scs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.scs; @@ -520,8 +489,7 @@ ue_fallback_scheduler::alloc_grant(ue& u, crb_interval ue_grant_crbs; sch_prbs_tbs prbs_tbs{}; - sch_mcs_index mcs_idx = 0; - bool pending_bytes_segmented = false; + sch_mcs_index mcs_idx = 0; if (is_retx) { // Use the same MCS, nof PRBs and TBS as the last allocation. mcs_idx = h_dl_retx->get_grant_params().mcs; @@ -536,17 +504,18 @@ ue_fallback_scheduler::alloc_grant(ue& u, ue_grant_crbs = {unused_crbs.start(), unused_crbs.start() + prbs_tbs.nof_prbs}; } else { - const unsigned pending_bytes = u.pending_dl_newtx_bytes(); - srsran_assert(pending_bytes > 0, "Unexpected number of pending bytes"); const unsigned only_conres_bytes = u.pending_conres_ce_bytes(); const unsigned only_srb0_bytes = u.pending_dl_newtx_bytes(LCID_SRB0); + const unsigned only_srb1_bytes = u.pending_dl_newtx_bytes(LCID_SRB1); + const unsigned pending_bytes = only_conres_bytes + only_srb0_bytes + only_srb1_bytes; + srsran_assert(pending_bytes > 0, "Unexpected number of pending bytes"); // There must be space for ConRes CE, if it is pending. If only SRB0 is pending (no ConRes), there must be space // for it, as the SRB0 cannot be segmented. const unsigned min_pending_bytes = only_conres_bytes > 0 ? only_conres_bytes : (only_srb0_bytes > 0 ? only_srb0_bytes : 0); std::optional fixed_mcs; - if (is_srb0.has_value() and not is_srb0.value()) { + if (only_srb1_bytes > 0) { fixed_mcs = map_cqi_to_mcs(expert_cfg.initial_cqi, pdsch_cfg.mcs_table); srsran_assert(fixed_mcs.has_value(), "Invalid Initial CQI {}", expert_cfg.initial_cqi); } @@ -585,7 +554,6 @@ ue_fallback_scheduler::alloc_grant(ue& u, return {}; } } - pending_bytes_segmented = true; } // Selection of Nof RBs, TBS and MCS complete. @@ -615,10 +583,7 @@ ue_fallback_scheduler::alloc_grant(ue& u, // configuration, the UE is provided by higher layers with one or more PUCCH resources [...]"). // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), // don't use the PUCCH ded. resources. - const bool use_common_and_ded_res = - u.ue_cfg_dedicated()->is_ue_cfg_complete() and - (is_retx or (is_srb0.has_value() and not is_srb0.value() and dci_type != dci_dl_rnti_config_type::tc_rnti_f1_0)); - // TODO: Fix use_common_and_ded_res check + const bool use_common_and_ded_res = u.ue_cfg_dedicated()->is_ue_cfg_complete() and is_retx; auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, res_alloc, pucch_alloc, @@ -649,25 +614,20 @@ ue_fallback_scheduler::alloc_grant(ue& u, u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); // Fill ConRes and/or SRB grant. - auto [nof_srb1_scheduled_bytes, h_dl] = fill_dl_srb_grant(u, - pdsch_alloc.slot, - h_dl_retx, - *pdcch, - dci_type, - pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), - pdsch_time_res, - chosen_k1.value(), - mcs_idx, - ue_grant_crbs, - pdsch_cfg, - prbs_tbs.tbs_bytes, - is_retx, - is_srb0); - - return sched_srb_results{.h_dl = h_dl, - .is_srb_data_pending = pending_bytes_segmented, - .nof_srb1_scheduled_bytes = nof_srb1_scheduled_bytes}; + return fill_dl_srb_grant(u, + pdsch_alloc.slot, + h_dl_retx, + *pdcch, + dci_type, + pdsch_alloc.result.dl.ue_grants.emplace_back(), + pucch_res_indicator.value(), + pdsch_time_res, + chosen_k1.value(), + mcs_idx, + ue_grant_crbs, + pdsch_cfg, + prbs_tbs.tbs_bytes, + is_retx); } std::tuple @@ -762,22 +722,20 @@ ue_fallback_scheduler::select_tbs(const pdsch_config_params& pdsch_cfg, return std::make_tuple(prbs_tbs.nof_prbs, chosen_mcs_idx, units::bytes{prbs_tbs.tbs_bytes}); } -std::pair -ue_fallback_scheduler::fill_dl_srb_grant(ue& u, - slot_point pdsch_slot, - std::optional h_dl, - pdcch_dl_information& pdcch, - dci_dl_rnti_config_type dci_type, - dl_msg_alloc& msg, - unsigned pucch_res_indicator, - unsigned pdsch_time_res, - unsigned k1, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pdsch_config_params& pdsch_params, - unsigned tbs_bytes, - bool is_retx, - std::optional is_srb0) +dl_harq_process_handle ue_fallback_scheduler::fill_dl_srb_grant(ue& u, + slot_point pdsch_slot, + std::optional h_dl, + pdcch_dl_information& pdcch, + dci_dl_rnti_config_type dci_type, + dl_msg_alloc& msg, + unsigned pucch_res_indicator, + unsigned pdsch_time_res, + unsigned k1, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pdsch_config_params& pdsch_params, + unsigned tbs_bytes, + bool is_retx) { // Allocate DL HARQ. // NOTE: We do not multiplex the SRB1 PUCCH with existing PUCCH HARQs, thus both DAI and HARQ-ACK bit index are 0. @@ -831,7 +789,6 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u msg.context.nof_retxs = h_dl->nof_retxs(); msg.context.olla_offset = 0; - unsigned srb1_bytes_allocated = 0; switch (dci_type) { case dci_dl_rnti_config_type::tc_rnti_f1_0: { build_pdsch_f1_0_tc_rnti(msg.pdsch_cfg, @@ -845,9 +802,6 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u break; } case dci_dl_rnti_config_type::c_rnti_f1_0: { - srsran_assert(is_srb0.has_value(), - "Invalid DCI type={} used for scheduling ConRes CE only", - dci_dl_rnti_config_rnti_type(dci_type)); build_pdsch_f1_0_c_rnti(msg.pdsch_cfg, pdsch_params, tbs_bytes, @@ -874,7 +828,7 @@ ue_fallback_scheduler::fill_dl_srb_grant(ue& u dl_harq_alloc_context ctxt{pdcch.dci.type, std::nullopt, std::nullopt, std::nullopt, true}; h_dl->save_grant_params(ctxt, msg); - return std::make_pair(srb1_bytes_allocated, *h_dl); + return *h_dl; } ue_fallback_scheduler::ul_srb_sched_outcome ue_fallback_scheduler::schedule_ul_ue(cell_resource_allocator& res_alloc, @@ -1260,9 +1214,7 @@ ue_fallback_scheduler::get_pdsch_time_res_idx(const pdsch_config_common& return candidate_pdsch_time_res_idx; } -void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ue_index, - std::optional h_dl, - std::optional is_srb0) +void ue_fallback_scheduler::store_harq_tx(du_ue_index_t ue_index, const dl_harq_process_handle& h_dl) { srsran_sanity_check(ongoing_ues_ack_retxs.end() == std::find_if(ongoing_ues_ack_retxs.begin(), @@ -1272,7 +1224,7 @@ void ue_fallback_scheduler::store_harq_tx(du_ue_index_t }), "This UE and HARQ process were already in the list"); - ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl, is_srb0); + ongoing_ues_ack_retxs.emplace_back(ue_index, h_dl); } void ue_fallback_scheduler::slot_indication(slot_point sl) @@ -1343,7 +1295,7 @@ void ue_fallback_scheduler::slot_indication(slot_point sl) it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); continue; } - if (not it_ue_harq->h_dl.has_value() or it_ue_harq->h_dl->empty()) { + if (it_ue_harq->h_dl.empty()) { it_ue_harq = ongoing_ues_ack_retxs.erase(it_ue_harq); continue; } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 5e7a9f4f1b..f6c268d1ab 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -30,7 +30,7 @@ class ue_fallback_scheduler /// Handles DL buffer state reported by upper layers. /// \param[in] ue_index UE's DU Index for which SRB0 message needs to be scheduled. /// \param[in] is_srb0 Defines whether the DL Buffer State Indication is for SRB0/SRB1. - void handle_dl_buffer_state_indication(du_ue_index_t ue_index, bool is_srb0); + void handle_dl_buffer_state_indication(du_ue_index_t ue_index); /// Handle Contention Resolution indication sent by the MAC. /// \param[in] ue_index UE's DU Index for which Contention Resolution CE needs to be scheduled. @@ -59,9 +59,6 @@ class ue_fallback_scheduler /// Defines the information that is needed to track the DL UEs that are pending for new SRB0/SRB1/ConRes CE TX. struct fallback_ue { du_ue_index_t ue_index; - // This field is empty if only ConRes indication is received from MAC and buffer status from upper layers for - // SRB0/SRB1 is not yet received. - std::optional is_srb0; }; /// Helper that schedules DL SRB0 and SRB1 retx. Returns false if the DL fallback schedule should stop the DL @@ -72,7 +69,7 @@ class ue_fallback_scheduler void schedule_ul_new_tx_and_retx(cell_resource_allocator& res_alloc); /// Determine which type of DL allocation is required for a given UE candidate. - dl_new_tx_alloc_type get_dl_new_tx_alloc_type(const fallback_ue& next_ue) const; + static dl_new_tx_alloc_type get_dl_new_tx_alloc_type(const ue& u); /// Helper that schedules pending DL new txs for ConRes CE, SRB0 or SRB1. /// \param[in] selected_alloc_type Type of allocation to make. Options: ConRes CE only, SRB0 and SRB1. @@ -83,15 +80,13 @@ class ue_fallback_scheduler void slot_indication(slot_point sl); /// \remark srb_pending => Only ConRes was scheduled and Msg4 is yet to be scheduled. - enum class dl_sched_outcome { success, next_ue, stop_dl_scheduling, srb_pending }; + enum class dl_sched_outcome { success, next_ue, stop_dl_scheduling }; /// \brief Tries to schedule DL SRB0/SRB1 message and/or ConRes CE only for a UE, iterating over several PDSCH slots /// ahead of the current reference slot. /// \remark If \c is_srb0 is empty, then only ConRes CE is scheduled. - dl_sched_outcome schedule_dl_srb(cell_resource_allocator& res_alloc, - ue& u, - std::optional h_dl_retx, - std::optional is_srb0 = std::nullopt); + dl_sched_outcome + schedule_dl_srb(cell_resource_allocator& res_alloc, ue& u, std::optional h_dl_retx); enum class ul_srb_sched_outcome { next_ue, next_slot, stop_ul_scheduling }; @@ -99,15 +94,6 @@ class ue_fallback_scheduler /// scheduler should keep allocating the next UL UE, false if it should stop the UL allocation. ul_srb_sched_outcome schedule_ul_ue(cell_resource_allocator& res_alloc, ue& u); - struct sched_srb_results { - std::optional h_dl; - // This field represents whether SRB data was scheduled along with ConRes CE or only ConRes CE was scheduled. - bool is_srb_data_pending = false; - // This is only meaningful for SRB1, and represents the number of LCID-1 bytes (excluding any overhead) that have - // been scheduled for transmission. - unsigned nof_srb1_scheduled_bytes = 0; - }; - /// \brief For a number of pending bytes, select the appropriate MCS. std::tuple select_tbs(const pdsch_config_params& pdsch_cfg, unsigned pending_bytes, @@ -115,13 +101,12 @@ class ue_fallback_scheduler const std::optional& fixed_mcs) const; /// \brief Allocate DL grant for a UE and for a specific PDSCH slot. - sched_srb_results alloc_grant(ue& u, - cell_resource_allocator& res_alloc, - unsigned pdsch_time_res, - unsigned slot_offset, - slot_point most_recent_ack_slot, - std::optional h_dl_retx, - std::optional is_srb0); + std::optional alloc_grant(ue& u, + cell_resource_allocator& res_alloc, + unsigned pdsch_time_res, + unsigned slot_offset, + slot_point most_recent_ack_slot, + std::optional h_dl_retx); /// \brief Tries to schedule SRB1 message for a specific PUSCH time domain resource. ul_srb_sched_outcome schedule_ul_srb(ue& u, @@ -131,21 +116,20 @@ class ue_fallback_scheduler std::optional h_ul_retx); /// \return A pair with the number of SRB bytes allocated and which DL HARQ process was used. - std::pair fill_dl_srb_grant(ue& u, - slot_point pdsch_slot, - std::optional h_dl, - pdcch_dl_information& pdcch, - dci_dl_rnti_config_type dci_type, - dl_msg_alloc& msg, - unsigned pucch_res_indicator, - unsigned pdsch_time_res, - unsigned k1, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pdsch_config_params& pdsch_params, - unsigned tbs_bytes, - bool is_retx, - std::optional is_srb0 = std::nullopt); + dl_harq_process_handle fill_dl_srb_grant(ue& u, + slot_point pdsch_slot, + std::optional h_dl, + pdcch_dl_information& pdcch, + dci_dl_rnti_config_type dci_type, + dl_msg_alloc& msg, + unsigned pucch_res_indicator, + unsigned pdsch_time_res, + unsigned k1, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pdsch_config_params& pdsch_params, + unsigned tbs_bytes, + bool is_retx); void fill_ul_srb_grant(ue& u, slot_point pdcch_slot, @@ -178,28 +162,23 @@ class ue_fallback_scheduler class ack_and_retx_tracker { public: - explicit ack_and_retx_tracker(du_ue_index_t ue_idx, - const std::optional& h_dl_, - std::optional is_srb0_ = std::nullopt) : - ue_index(ue_idx), is_srb0(is_srb0_), h_dl(h_dl_) + explicit ack_and_retx_tracker(du_ue_index_t ue_idx, const dl_harq_process_handle& h_dl_) : + ue_index(ue_idx), h_dl(h_dl_) { } explicit ack_and_retx_tracker(const ack_and_retx_tracker& other) = default; - bool match_ue_harq(du_ue_index_t ue_idx_, const std::optional& h_dl_) const + bool match_ue_harq(du_ue_index_t ue_idx_, const dl_harq_process_handle& h_dl_) const { return ue_index == ue_idx_ and h_dl == h_dl_; } du_ue_index_t ue_index; // This field is empty if HARQ is used to schedule ConRes CE only. - std::optional is_srb0; - std::optional h_dl; + dl_harq_process_handle h_dl; }; - void store_harq_tx(du_ue_index_t ue_index, - std::optional h_dl, - std::optional is_srb0 = std::nullopt); + void store_harq_tx(du_ue_index_t ue_index, const dl_harq_process_handle& h_dl); const scheduler_ue_expert_config& expert_cfg; const cell_configuration& cell_cfg; diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 867a720e70..579d624f65 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -310,7 +310,7 @@ class base_fallback_tester } // Notify scheduler of DL buffer state. - bench->fallback_sched.handle_dl_buffer_state_indication(ue_idx, is_srb0); + bench->fallback_sched.handle_dl_buffer_state_indication(ue_idx); } void push_buffer_state_to_ul_ue(du_ue_index_t ue_idx, slot_point sl, unsigned buffer_size) From 9c3a458b1ffb524b037881ef4196af682936a85b Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 12:39:33 +0100 Subject: [PATCH 114/227] sched: fix accounting of segmentation overhead in the fallback scheduler --- .../ue_context/dl_logical_channel_manager.cpp | 13 +++++++++++-- lib/scheduler/ue_context/ue.cpp | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp index 6c53887a02..b3a291b719 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp @@ -50,8 +50,8 @@ unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, un subpdu.lcid = lcid_dl_sch_t::MIN_RESERVED; subpdu.sched_bytes = 0; - lcid_t lcid_with_prio = lcid == lcid_t::INVALID_LCID ? get_max_prio_lcid() : lcid; - if (lcid_with_prio == lcid_t::INVALID_LCID) { + lcid_t lcid_with_prio = lcid == INVALID_LCID ? get_max_prio_lcid() : lcid; + if (lcid_with_prio == INVALID_LCID) { return 0; } @@ -98,6 +98,15 @@ unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, lc // Update DL Buffer Status to avoid reallocating the same LCID bytes. channels[lcid].buf_st -= std::min(sdu_size, channels[lcid].buf_st); + if (lcid != LCID_SRB0 and channels[lcid].buf_st > 0) { + constexpr static unsigned RLC_SEGMENTATION_OVERHEAD = 4; + // Allocation was not enough to empty the logical channel. In this specific case, we add some bytes to account + // for the RLC segmentation overhead. + // Note: This update is only relevant for PDSCH allocations for slots > slot_tx. For the case of PDSCH + // slot==slot_tx, there will be an RLC Buffer Occupancy update right away, which will set a new buffer value. + channels[lcid].buf_st += RLC_SEGMENTATION_OVERHEAD; + } + subpdu.lcid = (lcid_dl_sch_t::options)lcid; subpdu.sched_bytes = sdu_size; diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index c5e3a71e8f..08904e7cba 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -144,7 +144,7 @@ void ue::handle_dl_buffer_state_indication(const dl_buffer_state_indication_mess auto h_dl = ue_cc.harqs.dl_harq(to_harq_id(i)); if (h_dl.has_value()) { rem_harqs--; - if (h_dl->pdsch_slot() >= last_sl_tx and h_dl->nof_retxs() == 0 and h_dl->is_waiting_ack()) { + if (h_dl->pdsch_slot() > last_sl_tx and h_dl->nof_retxs() == 0 and h_dl->is_waiting_ack()) { for (const auto& lc : h_dl->get_grant_params().lc_sched_info) { if (lc.lcid.is_sdu() and lc.lcid.to_lcid() == msg.lcid) { unsigned bytes_sched = From 4bab909736faee4b40b939f28ba23f9424547382 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 12:46:19 +0100 Subject: [PATCH 115/227] sched: avoid log error when fallback scheduling is successful --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 5e6c1e81da..567fb7cc38 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -239,7 +239,9 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo const auto alloc_type = get_dl_new_tx_alloc_type(u); if (alloc_type == dl_new_tx_alloc_type::error) { // The UE is not in a state for scheduling - logger.error("ue={}: UE is an inconsistent state in the fallback scheduler", next_ue->ue_index); + logger.error("ue={}: UE is an inconsistent state in the fallback scheduler. Pending bytes={}", + next_ue->ue_index, + u.pending_dl_newtx_bytes()); next_ue = pending_dl_ues_new_tx.erase(next_ue); continue; } @@ -267,7 +269,7 @@ bool ue_fallback_scheduler::schedule_dl_new_tx(cell_resource_allocator& res_allo // there are still some bytes left in the buffer. At the next iteration, the scheduler will try // again with the same scheduler, but starting from the next available slot. if (not u.has_pending_dl_newtx_bytes()) { - ++next_ue; + next_ue = pending_dl_ues_new_tx.erase(next_ue); } } From 07838e274e4acc9a83ab90d3de25fb59ef72395c Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 14:20:50 +0100 Subject: [PATCH 116/227] sched: fix failing scheduler con res msg4 test --- .../scheduler_ue_fallback_mode_test.cpp | 81 +++++++++---------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp index 6d74a7b9c1..665abda82d 100644 --- a/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp +++ b/tests/unittests/scheduler/scheduler_ue_fallback_mode_test.cpp @@ -144,6 +144,12 @@ TEST_P(scheduler_con_res_msg4_test, ASSERT_TRUE(this->last_sched_res_list[to_du_cell_index(0)]->dl.csi_rs.empty()); } +static bool is_f1_pucch(const pucch_info& pucch, bool is_common, bool has_sr) +{ + return pucch.format == pucch_format::FORMAT_1 and ((pucch.format_1.sr_bits != sr_nof_bits::no_sr) == has_sr) and + pucch.format_1.harq_ack_nof_bits > 0 and (pucch.resources.second_hop_prbs.empty() != is_common); +}; + TEST_P(scheduler_con_res_msg4_test, while_ue_is_in_fallback_then_common_pucch_is_used) { static const unsigned msg4_size = 128; @@ -188,66 +194,55 @@ TEST_P(scheduler_con_res_msg4_test, while_ue_is_in_fallback_then_common_pucch_is ASSERT_TRUE(this->run_slot_until([this, &pucch_res_ptrs]() { // Depending on the SR and CSI slots, we can have different combinations of PUCCH grants. There must be at least one - // PUCCH F1 grant using common resources, plus: + // PUCCH F1 grant using common resources, and: + // - No PUCCH F1 ded. // - 1 PUCCH F1 ded. with 1 HARQ-ACK bit and NO SR. // - 1 PUCCH F1 ded. with 1 HARQ-ACK bit and NO SR and 1 PUCCH F1 ded. with 1 HARQ-ACK bit and SR. // - 1 PUCCH F2 ded. with 1 HARQ-ACK bit and CSI, with optional SR. - // Case of 2 PUCCH grants. - if (this->last_sched_res_list[to_du_cell_index(0)]->ul.pucchs.size() == 2) { - for (const auto& pucch : this->last_sched_res_list[to_du_cell_index(0)]->ul.pucchs) { - if (pucch.crnti == rnti and pucch.format == pucch_format::FORMAT_1 and - pucch.format_1.sr_bits == sr_nof_bits::no_sr and pucch.format_1.harq_ack_nof_bits > 0) { - pucch.resources.second_hop_prbs.empty() ? pucch_res_ptrs.f1_ded_ptr = &pucch - : pucch_res_ptrs.f1_common_ptr = &pucch; - } else if (pucch.crnti == rnti and pucch.format == pucch_format::FORMAT_2 and - pucch.format_2.harq_ack_nof_bits > 0) { - pucch_res_ptrs.f2_ptr = &pucch; + const auto& pucchs = this->last_sched_res_list[to_du_cell_index(0)]->ul.pucchs; + unsigned nof_pucchs = pucchs.size(); + + if (nof_pucchs == 1) { + if (pucchs[0].crnti == rnti and is_f1_pucch(pucchs[0], true, false)) { + pucch_res_ptrs.f1_common_ptr = &pucchs[0]; + } + } else if (nof_pucchs == 2) { + for (const auto& pucch : pucchs) { + if (pucch.crnti != rnti) { + continue; } - if (pucch_res_ptrs.f1_common_ptr != nullptr and - (pucch_res_ptrs.f1_ded_ptr != nullptr or pucch_res_ptrs.f2_ptr != nullptr)) { - return true; + if (is_f1_pucch(pucch, true, false)) { + pucch_res_ptrs.f1_common_ptr = &pucch; + } else if (is_f1_pucch(pucch, false, false)) { + pucch_res_ptrs.f1_ded_ptr = &pucch; + } else if (pucch.format == pucch_format::FORMAT_2 and pucch.format_2.harq_ack_nof_bits > 0) { + pucch_res_ptrs.f2_ptr = &pucch; } } - return false; - } - // Case of 3 PUCCH grants. - else if (this->last_sched_res_list[to_du_cell_index(0)]->ul.pucchs.size() == 3) { - for (const auto& pucch : this->last_sched_res_list[to_du_cell_index(0)]->ul.pucchs) { + } else if (nof_pucchs == 3) { + for (const auto& pucch : pucchs) { if (pucch.crnti == rnti and pucch.format == pucch_format::FORMAT_1) { - if (pucch.format_1.sr_bits == sr_nof_bits::no_sr and pucch.format_1.harq_ack_nof_bits > 0 and - not pucch.resources.second_hop_prbs.empty()) { + if (is_f1_pucch(pucch, true, false)) { pucch_res_ptrs.f1_common_ptr = &pucch; - } else if (pucch.format_1.sr_bits == sr_nof_bits::one and pucch.format_1.harq_ack_nof_bits > 0 and - pucch.resources.second_hop_prbs.empty()) { + } else if (is_f1_pucch(pucch, false, true)) { pucch_res_ptrs.f1_ded_sr_ptr = &pucch; - } else if (pucch.format_1.sr_bits == sr_nof_bits::no_sr and pucch.format_1.harq_ack_nof_bits > 0 and - pucch.resources.second_hop_prbs.empty()) { + } else if (is_f1_pucch(pucch, false, false)) { pucch_res_ptrs.f1_ded_ptr = &pucch; } } - if (pucch_res_ptrs.f1_common_ptr != nullptr and pucch_res_ptrs.f1_ded_ptr != nullptr and - pucch_res_ptrs.f1_ded_sr_ptr != nullptr) { - return true; - } } - return false; } - return false; + return pucch_res_ptrs.f1_common_ptr != nullptr; })); - // TODO: Once PUCCH scheduler avoids multiplexing SR and HARQ-ACK for common PUCCH resources, uncomment the following. - // ASSERT_EQ(std::count_if(this->last_sched_res->ul.pucchs.begin(), - // this->last_sched_res->ul.pucchs.end(), - // [this](const pucch_info& pucch) { return pucch.crnti == rnti; }), - // 1) - // << "In case of common PUCCH scheduling, multiplexing with SR or CSI should be avoided"; - - const bool two_pucch_grants = pucch_res_ptrs.f1_common_ptr != nullptr and - (pucch_res_ptrs.f1_ded_ptr != nullptr or pucch_res_ptrs.f2_ptr != nullptr); - const bool three_pucch_grants = pucch_res_ptrs.f1_common_ptr != nullptr and pucch_res_ptrs.f1_ded_ptr != nullptr and - pucch_res_ptrs.f1_ded_sr_ptr != nullptr; - ASSERT_TRUE(two_pucch_grants or three_pucch_grants) << "Invalid PUCCH grants combination"; + + ASSERT_TRUE(pucch_res_ptrs.f1_common_ptr != nullptr); + if (pucch_res_ptrs.f1_ded_sr_ptr != nullptr) { + ASSERT_TRUE(pucch_res_ptrs.f1_ded_ptr != nullptr); + } else { + ASSERT_FALSE((pucch_res_ptrs.f1_ded_ptr != nullptr) and (pucch_res_ptrs.f2_ptr != nullptr)); + } } TEST_P(scheduler_con_res_msg4_test, while_ue_is_in_fallback_then_common_ss_is_used) From 92b032d1bffd1856aa85a9d7d4790e19182d7d20 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 17:51:03 +0100 Subject: [PATCH 117/227] sched: rename dl logical channel method name --- .../ue_context/dl_logical_channel_manager.cpp | 2 +- .../ue_context/dl_logical_channel_manager.h | 11 ++++++----- .../ue_scheduling/logical_channel_test.cpp | 14 +++++++------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp index b3a291b719..758622b955 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp @@ -86,7 +86,7 @@ unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, lc // - If it is last PDU of the TBS. // - [Implementation-defined] If \c leftover_bytes is < 5 bytes, as it results in small SDU size. unsigned leftover_bytes = rem_bytes - alloc_bytes; - if (leftover_bytes > 0 and ((leftover_bytes <= MAX_MAC_SDU_SUBHEADER_SIZE + 1) or pending_bytes() == 0)) { + if (leftover_bytes > 0 and ((leftover_bytes <= MAX_MAC_SDU_SUBHEADER_SIZE + 1) or total_pending_bytes() == 0)) { alloc_bytes += leftover_bytes; } if (alloc_bytes == MAC_SDU_SUBHEADER_LENGTH_THRES + MIN_MAC_SDU_SUBHEADER_SIZE) { diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index 33755e847c..6d1b82b3e6 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -53,7 +53,7 @@ class dl_logical_channel_manager return channels[lcid].active; } - /// \brief Checks whether the UE has pending data. + /// \brief Checks whether the UE has pending data, regardless of the state it is in. bool has_pending_bytes() const { return has_pending_ces() or @@ -80,12 +80,13 @@ class dl_logical_channel_manager /// \brief Checks whether UE has pending CEs to be scheduled (ConRes excluded). bool has_pending_ces() const { return pending_con_res_id or not pending_ces.empty(); } - /// \brief Calculates total number of DL bytes, including MAC header overhead. - unsigned pending_bytes() const + /// \brief Calculates total number of DL bytes, including MAC header overhead, and without taking into account + /// the UE state. + unsigned total_pending_bytes() const { unsigned bytes = pending_ce_bytes(); for (unsigned i = 0; i <= MAX_LCID; ++i) { - bytes += pending_bytes((lcid_t)i); + bytes += pending_bytes(static_cast(i)); } return bytes; } @@ -98,7 +99,7 @@ class dl_logical_channel_manager } unsigned bytes = pending_ce_bytes(); for (unsigned i = 1; i <= MAX_LCID; ++i) { - bytes += pending_bytes((lcid_t)i); + bytes += pending_bytes(static_cast(i)); } return bytes; } diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index 42564365fa..bdc61c9da4 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -54,7 +54,7 @@ TEST(dl_logical_channel_test, when_buffer_state_is_zero_no_tx_data_is_pending) lch_mng.handle_dl_buffer_status_indication(lcid, 0); ASSERT_EQ(lch_mng.pending_bytes(lcid), 0); - ASSERT_EQ(lch_mng.pending_bytes(), 0); + ASSERT_EQ(lch_mng.total_pending_bytes(), 0); ASSERT_FALSE(lch_mng.has_pending_bytes()); ASSERT_FALSE(lch_mng.has_pending_ces()); } @@ -70,7 +70,7 @@ TEST(dl_logical_channel_test, buffer_state_indication_has_no_effect_in_inactive_ if (lcid == LCID_SRB0) { ASSERT_EQ(lch_mng.pending_bytes(lcid), get_mac_sdu_required_bytes(buf_st)); } else { - ASSERT_EQ(lch_mng.pending_bytes(), 0); + ASSERT_EQ(lch_mng.total_pending_bytes(), 0); ASSERT_EQ(lch_mng.pending_bytes(lcid), 0); } @@ -96,7 +96,7 @@ TEST(dl_logical_channel_test, buffer_status_indication_updates_tx_pending_bytes) ASSERT_EQ(lch_mng.pending_bytes(lcid), get_mac_sdu_required_bytes(buf_st)); ASSERT_EQ(lch_mng.has_pending_bytes(lcid), buf_st > 0); } else { - ASSERT_EQ(lch_mng.pending_bytes(), get_mac_sdu_required_bytes(buf_st)); + ASSERT_EQ(lch_mng.total_pending_bytes(), get_mac_sdu_required_bytes(buf_st)); ASSERT_EQ(lch_mng.has_pending_bytes(), buf_st > 0); } ASSERT_EQ(lch_mng.pending_bytes(lcid), get_mac_sdu_required_bytes(buf_st)); @@ -115,7 +115,7 @@ TEST(dl_logical_channel_test, total_pending_bytes_equal_sum_of_logical_channel_p lch_mng.handle_dl_buffer_status_indication(lcid, dl_bs); } - ASSERT_EQ(lch_mng.pending_bytes(), std::accumulate(buf_st_inds.begin(), buf_st_inds.end(), 0)); + ASSERT_EQ(lch_mng.total_pending_bytes(), std::accumulate(buf_st_inds.begin(), buf_st_inds.end(), 0)); ASSERT_FALSE(lch_mng.has_pending_ces()); for (unsigned i = 0; i != lcids.size(); ++i) { ASSERT_EQ(lch_mng.pending_bytes(lcids[i]), buf_st_inds[i]); @@ -130,7 +130,7 @@ TEST(dl_logical_channel_test, mac_ce_indication_updates_tx_pending_bytes) ASSERT_TRUE(lch_mng.has_pending_bytes()); ASSERT_TRUE(lch_mng.has_pending_ces()); - ASSERT_EQ(lch_mng.pending_bytes(), + ASSERT_EQ(lch_mng.total_pending_bytes(), lcid_dl_sch_t{lcid_dl_sch_t::TA_CMD}.sizeof_ce() + FIXED_SIZED_MAC_CE_SUBHEADER_SIZE); } @@ -197,7 +197,7 @@ TEST(dl_logical_channel_test, mac_sdu_is_scheduled_if_tb_has_space) unsigned rem_bytes = tb_size, rem_sdu_size = sdu_size; do { - unsigned pending_bytes = lch_mng.pending_bytes(); + unsigned pending_bytes = lch_mng.total_pending_bytes(); dl_msg_lc_info subpdu; unsigned allocated_bytes = lch_mng.allocate_mac_sdu(subpdu, rem_bytes); if (not subpdu.lcid.is_valid()) { @@ -214,7 +214,7 @@ TEST(dl_logical_channel_test, mac_sdu_is_scheduled_if_tb_has_space) ASSERT_FALSE(lch_mng.has_pending_bytes()) << "subPDU is large enough to deplete all the pending tx bytes"; } else { rem_sdu_size -= subpdu.sched_bytes; - ASSERT_EQ(get_mac_sdu_required_bytes(rem_sdu_size), lch_mng.pending_bytes()) + ASSERT_EQ(get_mac_sdu_required_bytes(rem_sdu_size), lch_mng.total_pending_bytes()) << "incorrect calculation of remaining pending tx bytes"; } From 44073c41bc5ff18c4cc83e1a476d118cb52d6cc1 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 19:44:01 +0100 Subject: [PATCH 118/227] sched: fix failing unit test for the DL logical channel manager --- .../scheduler/ue_scheduling/logical_channel_test.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index bdc61c9da4..6a7bad7d7c 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -214,7 +214,10 @@ TEST(dl_logical_channel_test, mac_sdu_is_scheduled_if_tb_has_space) ASSERT_FALSE(lch_mng.has_pending_bytes()) << "subPDU is large enough to deplete all the pending tx bytes"; } else { rem_sdu_size -= subpdu.sched_bytes; - ASSERT_EQ(get_mac_sdu_required_bytes(rem_sdu_size), lch_mng.total_pending_bytes()) + // Note: In the case the logical channel was totally flushed, the manager adds some extra bytes to account for + // RLC overhead. + const unsigned RLC_SEGMENTATION_OVERHEAD = 4; + ASSERT_EQ(get_mac_sdu_required_bytes(rem_sdu_size), lch_mng.total_pending_bytes() - RLC_SEGMENTATION_OVERHEAD) << "incorrect calculation of remaining pending tx bytes"; } From 54eeba58cba0a15468ca59e86474bdc467fcdc33 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Wed, 4 Dec 2024 12:48:02 +0100 Subject: [PATCH 119/227] cu_cp,nrppa: store ue measurements in ue measurement context --- include/srsran/nrppa/nrppa.h | 39 ++++++++----------- .../adapters/cell_meas_manager_adapters.h | 18 --------- lib/cu_cp/adapters/nrppa_adapters.h | 6 +++ .../cell_meas_manager_impl.cpp | 26 ++++++------- .../cell_meas_manager_impl.h | 16 ++------ .../cell_meas_manager/measurement_context.h | 6 ++- lib/cu_cp/cu_cp_impl.cpp | 15 ++++--- lib/cu_cp/cu_cp_impl.h | 13 ++----- lib/cu_cp/cu_cp_impl_interface.h | 37 +++++++----------- lib/nrppa/nrppa_dummy_impl.cpp | 5 --- lib/nrppa/nrppa_dummy_impl.h | 9 +---- .../cell_meas_manager_test_helpers.cpp | 8 ++-- .../cell_meas_manager_test_helpers.h | 20 +++------- 13 files changed, 78 insertions(+), 140 deletions(-) diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h index 1d823cb257..ba85b2676e 100644 --- a/include/srsran/nrppa/nrppa.h +++ b/include/srsran/nrppa/nrppa.h @@ -30,6 +30,17 @@ class nrppa_cu_cp_ue_notifier virtual bool schedule_async_task(async_task task) = 0; }; +struct cell_measurement_positioning_info { + struct cell_measurement_item_t { + nr_cell_global_id_t nr_cgi; + uint32_t nr_arfcn; + rrc_meas_result_nr meas_result; + }; + + nr_cell_global_id_t serving_cell_id; + std::map cell_measurements; +}; + /// Methods used by NRPPa to signal events to the CU-CP. class nrppa_cu_cp_notifier { @@ -41,6 +52,12 @@ class nrppa_cu_cp_notifier /// \returns Pointer to the NRPPA UE notifier. virtual nrppa_cu_cp_ue_notifier* on_new_nrppa_ue(ue_index_t ue_index) = 0; + /// \brief Notifies the CU-CP about a required UE measurement. + /// \param[in] ue_index The index of the UE. + /// \returns The measurement results if successful, an error string otherwise. + virtual expected + on_measurement_results_required(ue_index_t ue_index) = 0; + /// \brief Notifies about a NRPPa PDU. /// \param[in] nrppa_pdu The NRPPa PDU. /// \param[in] ue_index For UE associated messages the index of the UE. @@ -57,27 +74,6 @@ class nrppa_message_handler virtual void handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) = 0; }; -struct cell_measurement_positioning_info { - struct cell_measurement_item_t { - nr_cell_global_id_t nr_cgi; - uint32_t nr_arfcn; - rrc_meas_result_nr meas_result; - }; - - nr_cell_global_id_t serving_cell_id; - std::map cell_measurements; -}; - -/// This interface is used to push UE measurements to the NRPPA interface. -class nrppa_measurement_handler -{ -public: - virtual ~nrppa_measurement_handler() = default; - - /// Handle the incoming UE measurement. - virtual void handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; -}; - /// Handle ue context removal. class nrppa_ue_context_removal_handler { @@ -96,7 +92,6 @@ class nrppa_interface virtual ~nrppa_interface() = default; virtual nrppa_message_handler& get_nrppa_message_handler() = 0; - virtual nrppa_measurement_handler& get_nrppa_measurement_handler() = 0; virtual nrppa_ue_context_removal_handler& get_nrppa_ue_context_removal_handler() = 0; }; diff --git a/lib/cu_cp/adapters/cell_meas_manager_adapters.h b/lib/cu_cp/adapters/cell_meas_manager_adapters.h index ec9d46d48f..2902524cf1 100644 --- a/lib/cu_cp/adapters/cell_meas_manager_adapters.h +++ b/lib/cu_cp/adapters/cell_meas_manager_adapters.h @@ -37,23 +37,5 @@ class cell_meas_mobility_manager_adapter : public cell_meas_mobility_manager_not mobility_manager_measurement_handler* handler = nullptr; }; -/// Adapter between cell measurement manager and CU-CP. -class cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier -{ -public: - cell_meas_manager_cu_cp_adapter() = default; - - void connect_cu_cp(cu_cp_positioning_measurement_handler& handler_) { handler = &handler_; } - - void on_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override - { - srsran_assert(handler != nullptr, "Positioning measurement handler must not be nullptr"); - handler->handle_ue_measurement(ue_index, meas_result); - } - -private: - cu_cp_positioning_measurement_handler* handler = nullptr; -}; - } // namespace srs_cu_cp } // namespace srsran diff --git a/lib/cu_cp/adapters/nrppa_adapters.h b/lib/cu_cp/adapters/nrppa_adapters.h index 97bc7ddf25..f7f4010ebb 100644 --- a/lib/cu_cp/adapters/nrppa_adapters.h +++ b/lib/cu_cp/adapters/nrppa_adapters.h @@ -32,6 +32,12 @@ class nrppa_cu_cp_adapter : public nrppa_cu_cp_notifier return cu_cp_handler->handle_new_nrppa_ue(ue_index); } + expected on_measurement_results_required(ue_index_t ue_index) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NRPPA handler must not be nullptr"); + return cu_cp_handler->handle_measurement_results_required(ue_index); + } + void on_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override { srsran_assert(cu_cp_handler != nullptr, "CU-CP NRPPA handler must not be nullptr"); 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 0635ca2bc0..c07b253799 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 @@ -12,6 +12,7 @@ #include "cell_meas_manager_helpers.h" #include "srsran/cu_cp/cell_meas_manager_config.h" #include "srsran/rrc/meas_types.h" +#include "srsran/support/compiler.h" #include "srsran/support/srsran_assert.h" #include @@ -20,13 +21,8 @@ using namespace srs_cu_cp; cell_meas_manager::cell_meas_manager(const cell_meas_manager_cfg& cfg_, cell_meas_mobility_manager_notifier& mobility_mng_notifier_, - cell_meas_manager_cu_cp_notifier& cu_cp_notifier_, ue_manager& ue_mng_) : - cfg(cfg_), - mobility_mng_notifier(mobility_mng_notifier_), - cu_cp_notifier(cu_cp_notifier_), - ue_mng(ue_mng_), - logger(srslog::fetch_basic_logger("CU-CP")) + cfg(cfg_), mobility_mng_notifier(mobility_mng_notifier_), ue_mng(ue_mng_), logger(srslog::fetch_basic_logger("CU-CP")) { srsran_assert(is_valid_configuration(cfg, ssb_freq_to_meas_object), "Invalid cell measurement configuration"); generate_measurement_objects_for_serving_cells(); @@ -201,10 +197,10 @@ void cell_meas_manager::report_measurement(ue_index_t ue_index, const rrc_meas_r return; } - auto& meas_ctxt = ue_meas_context.meas_id_to_meas_context.at(meas_results.meas_id); + // Store measurement results. + store_measurement_results(ue_index, meas_results); - // Forward measurement to CU-CP. - send_positioning_measurement(ue_index, meas_results); + auto& meas_ctxt = ue_meas_context.meas_id_to_meas_context.at(meas_results.meas_id); // Ignore id with periodic measurements. @@ -298,9 +294,13 @@ void cell_meas_manager::update_measurement_object(nr_cell_identity ssb_freq_to_meas_object.emplace(ssb_freq, generate_measurement_object(serving_cell_cfg)); } -SRSRAN_WEAK_SYMB void cell_meas_manager::send_positioning_measurement(ue_index_t ue_index, - const rrc_meas_results& meas_results) +SRSRAN_WEAK_SYMB expected + cell_meas_manager::get_meas_results(ue_index_t ue_index) +{ + return make_unexpected("Positioning measurements are not supported"); +} + +SRSRAN_WEAK_SYMB void cell_meas_manager::store_measurement_results(ue_index_t ue_index, + const rrc_meas_results& meas_results) { - (void)&cu_cp_notifier; - logger.info("Positioning measurements are not supported"); } diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index cc8fad4520..b3eb96af4b 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -33,23 +33,12 @@ class cell_meas_mobility_manager_notifier pci_t neighbor_pci) = 0; }; -/// Methods used by cell measurement manager to signal measurement events to the positioning manager. -class cell_meas_manager_cu_cp_notifier -{ -public: - virtual ~cell_meas_manager_cu_cp_notifier() = default; - - /// \brief Notifies about a UE measurement. - virtual void on_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) = 0; -}; - /// Basic cell manager implementation class cell_meas_manager { public: cell_meas_manager(const cell_meas_manager_cfg& cfg_, cell_meas_mobility_manager_notifier& mobility_mng_notifier_, - cell_meas_manager_cu_cp_notifier& cu_cp_notifier_, ue_manager& ue_mng_); ~cell_meas_manager() = default; @@ -60,17 +49,18 @@ class cell_meas_manager bool update_cell_config(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg); void report_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); + expected get_meas_results(ue_index_t ue_index); + private: /// \brief Generate measurement objects for the given cell configuration. void generate_measurement_objects_for_serving_cells(); void update_measurement_object(nr_cell_identity nci, const serving_cell_meas_config& serving_cell_cfg); - void send_positioning_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); + void store_measurement_results(ue_index_t ue_index, const rrc_meas_results& meas_results); cell_meas_manager_cfg cfg; cell_meas_mobility_manager_notifier& mobility_mng_notifier; - cell_meas_manager_cu_cp_notifier& cu_cp_notifier; ue_manager& ue_mng; std::unordered_map diff --git a/lib/cu_cp/cell_meas_manager/measurement_context.h b/lib/cu_cp/cell_meas_manager/measurement_context.h index 65a0ab9073..85fdefd8b9 100644 --- a/lib/cu_cp/cell_meas_manager/measurement_context.h +++ b/lib/cu_cp/cell_meas_manager/measurement_context.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/nrppa/nrppa.h" #include "srsran/ran/gnb_id.h" #include "srsran/ran/nr_cgi.h" #include "srsran/ran/pci.h" @@ -87,8 +88,9 @@ class cell_meas_manager_ue_context slotted_array meas_ids; // 0 is reserved for invalid meas_id slotted_array meas_obj_ids; // 0 is reserved for invalid meas_obj_id - std::map meas_id_to_meas_context; - std::map nci_to_meas_obj_id; + std::map meas_id_to_meas_context; + std::map nci_to_meas_obj_id; + std::optional meas_results; cell_meas_manager_ue_context() { diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 8f46ea8428..f9fe5ec7f3 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -53,7 +53,7 @@ static void assert_cu_cp_configuration_valid(const cu_cp_configuration& cfg) cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : cfg(config_), ue_mng(cfg), - cell_meas_mng(cfg.mobility.meas_manager_config, cell_meas_mobility_notifier, cell_meas_ev_notifier, ue_mng), + cell_meas_mng(cfg.mobility.meas_manager_config, cell_meas_mobility_notifier, ue_mng), du_db(du_repository_config{cfg, *this, get_cu_cp_ue_removal_handler(), @@ -78,7 +78,6 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : mobility_manager_ev_notifier.connect_cu_cp(get_cu_cp_mobility_manager_handler()); e1ap_ev_notifier.connect_cu_cp(get_cu_cp_e1ap_handler()); rrc_du_cu_cp_notifier.connect_cu_cp(get_cu_cp_measurement_config_handler()); - cell_meas_ev_notifier.connect_cu_cp(get_cu_cp_positioning_measurement_handler()); ngap_db = std::make_unique( ngap_repository_config{cfg, get_cu_cp_ngap_handler(), paging_handler, srslog::fetch_basic_logger("CU-CP")}); @@ -623,6 +622,12 @@ SRSRAN_WEAK_SYMB nrppa_cu_cp_ue_notifier* cu_cp_impl::handle_new_nrppa_ue(ue_ind return nullptr; } +SRSRAN_WEAK_SYMB expected + cu_cp_impl::handle_measurement_results_required(ue_index_t ue_index) +{ + return make_unexpected("UL NRPPa messages are not supported"); +} + SRSRAN_WEAK_SYMB void cu_cp_impl::handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) { logger.info("UL NRPPa messages are not supported"); @@ -646,12 +651,6 @@ bool cu_cp_impl::handle_cell_config_update_request(nr_cell_identity nci, const s return cell_meas_mng.update_cell_config(nci, serv_cell_cfg); } -SRSRAN_WEAK_SYMB void cu_cp_impl::handle_ue_measurement(const ue_index_t ue_index, - const cell_measurement_positioning_info& meas_result) -{ - logger.info("NRPPa messages are not supported"); -} - async_task cu_cp_impl::handle_intra_cu_handover_request(const cu_cp_intra_cu_handover_request& request, du_index_t& source_du_index, diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index de389cfa1b..153a160577 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -109,6 +109,9 @@ class cu_cp_impl final : public cu_cp, void handle_n2_disconnection() override; // cu_cp_nrppa_handler. + nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) override; + expected + handle_measurement_results_required(ue_index_t ue_index) override; void handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override; // cu_cp_measurement_handler. @@ -121,9 +124,6 @@ class cu_cp_impl final : public cu_cp, // cu_cp_measurement_config_handler. bool handle_cell_config_update_request(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg) override; - // cu_cp_positioning_measurement_handler - void handle_ue_measurement(const ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override; - // cu_cp_mobility_manager_handler. async_task handle_intra_cu_handover_request(const cu_cp_intra_cu_handover_request& request, @@ -148,7 +148,6 @@ class cu_cp_impl final : public cu_cp, cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() override { return *this; } cu_cp_measurement_handler& get_cu_cp_measurement_handler() override { return *this; } cu_cp_measurement_config_handler& get_cu_cp_measurement_config_handler() override { return *this; } - cu_cp_positioning_measurement_handler& get_cu_cp_positioning_measurement_handler() override { return *this; } cu_cp_mobility_manager_handler& get_cu_cp_mobility_manager_handler() override { return *this; } cu_cp_ue_removal_handler& get_cu_cp_ue_removal_handler() override { return *this; } cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() override { return *this; } @@ -164,9 +163,6 @@ class cu_cp_impl final : public cu_cp, // NGAP UE creation handler. ngap_cu_cp_ue_notifier* handle_new_ngap_ue(ue_index_t ue_index) override; - // NRPPA UE creation handler. - nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) override; - // cu_cp_task_scheduler_handler. bool schedule_ue_task(ue_index_t ue_index, async_task task) override; @@ -195,9 +191,6 @@ class cu_cp_impl final : public cu_cp, // Cell Measurement Manager to mobility manager adapters. cell_meas_mobility_manager_adapter cell_meas_mobility_notifier; - // Cell Measurement Manager to positioning manager adapters. - cell_meas_manager_cu_cp_adapter cell_meas_ev_notifier; - // E1AP to CU-CP adapter. e1ap_cu_cp_adapter e1ap_ev_notifier; diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index f3c302784f..549eba9c93 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -124,6 +124,12 @@ class cu_cp_nrppa_handler /// \returns Pointer to the NRPPA UE notifier. virtual nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) = 0; + /// \brief Handle a UE measurement request. + /// \param[in] ue_index The index of the UE. + /// \returns The measurement results if successful, an error string otherwise. + virtual expected + handle_measurement_results_required(ue_index_t ue_index) = 0; + /// \brief Handle a UL NRPPa PDU. /// \param[in] msg The NRPPa PDU. /// \param[in] ue_index For UE associated messages the index of the UE. @@ -267,17 +273,6 @@ class cu_cp_measurement_config_handler const serving_cell_meas_config& serv_cell_cfg) = 0; }; -/// Interface to handle measurements for positioning. -class cu_cp_positioning_measurement_handler -{ -public: - virtual ~cu_cp_positioning_measurement_handler() = default; - - /// \brief Handle a UE measurement report. - virtual void handle_ue_measurement(const ue_index_t ue_index, - const cell_measurement_positioning_info& meas_result) = 0; -}; - /// Interface to request handover. class cu_cp_mobility_manager_handler { @@ -310,7 +305,6 @@ class cu_cp_impl_interface : public cu_cp_e1ap_event_handler, public cu_cp_rrc_ue_interface, public cu_cp_measurement_handler, public cu_cp_measurement_config_handler, - public cu_cp_positioning_measurement_handler, public cu_cp_ngap_handler, public cu_cp_nrppa_handler, public cu_cp_ue_context_manipulation_handler, @@ -320,16 +314,15 @@ class cu_cp_impl_interface : public cu_cp_e1ap_event_handler, public: virtual ~cu_cp_impl_interface() = default; - virtual cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() = 0; - virtual cu_cp_ngap_handler& get_cu_cp_ngap_handler() = 0; - virtual cu_cp_nrppa_handler& get_cu_cp_nrppa_handler() = 0; - virtual cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() = 0; - virtual cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() = 0; - virtual cu_cp_measurement_handler& get_cu_cp_measurement_handler() = 0; - virtual cu_cp_measurement_config_handler& get_cu_cp_measurement_config_handler() = 0; - virtual cu_cp_positioning_measurement_handler& get_cu_cp_positioning_measurement_handler() = 0; - virtual cu_cp_mobility_manager_handler& get_cu_cp_mobility_manager_handler() = 0; - virtual cu_cp_ue_removal_handler& get_cu_cp_ue_removal_handler() = 0; + virtual cu_cp_e1ap_event_handler& get_cu_cp_e1ap_handler() = 0; + virtual cu_cp_ngap_handler& get_cu_cp_ngap_handler() = 0; + virtual cu_cp_nrppa_handler& get_cu_cp_nrppa_handler() = 0; + virtual cu_cp_rrc_ue_interface& get_cu_cp_rrc_ue_interface() = 0; + virtual cu_cp_ue_context_manipulation_handler& get_cu_cp_ue_context_handler() = 0; + virtual cu_cp_measurement_handler& get_cu_cp_measurement_handler() = 0; + virtual cu_cp_measurement_config_handler& get_cu_cp_measurement_config_handler() = 0; + virtual cu_cp_mobility_manager_handler& get_cu_cp_mobility_manager_handler() = 0; + virtual cu_cp_ue_removal_handler& get_cu_cp_ue_removal_handler() = 0; }; } // namespace srs_cu_cp diff --git a/lib/nrppa/nrppa_dummy_impl.cpp b/lib/nrppa/nrppa_dummy_impl.cpp index 67dc7e661d..049d5cb1fd 100644 --- a/lib/nrppa/nrppa_dummy_impl.cpp +++ b/lib/nrppa/nrppa_dummy_impl.cpp @@ -19,11 +19,6 @@ nrppa_dummy_impl::nrppa_dummy_impl() : logger(srslog::fetch_basic_logger("NRPPA" // Note: For fwd declaration of member types, dtor cannot be trivial. nrppa_dummy_impl::~nrppa_dummy_impl() {} -void nrppa_dummy_impl::handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) -{ - logger.info("NRPPa messages are not supported"); -} - void nrppa_dummy_impl::remove_ue_context(ue_index_t ue_index) { logger.info("NRPPa messages are not supported"); diff --git a/lib/nrppa/nrppa_dummy_impl.h b/lib/nrppa/nrppa_dummy_impl.h index 2b541b7193..954256b45d 100644 --- a/lib/nrppa/nrppa_dummy_impl.h +++ b/lib/nrppa/nrppa_dummy_impl.h @@ -16,10 +16,7 @@ namespace srsran { namespace srs_cu_cp { -class nrppa_dummy_impl : public nrppa_interface, - public nrppa_message_handler, - public nrppa_measurement_handler, - public nrppa_ue_context_removal_handler +class nrppa_dummy_impl : public nrppa_interface, public nrppa_message_handler, public nrppa_ue_context_removal_handler { public: nrppa_dummy_impl(); @@ -28,14 +25,10 @@ class nrppa_dummy_impl : public nrppa_interface, // See nrppa_message_handler for documentation. void handle_new_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override; - // See nrppa_measurement_handler for documentation. - void handle_ue_measurement(ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override; - // See nrppa_ue_context_removal_handle for documentation. void remove_ue_context(ue_index_t ue_index) override; nrppa_message_handler& get_nrppa_message_handler() override { return *this; } - nrppa_measurement_handler& get_nrppa_measurement_handler() override { return *this; } nrppa_ue_context_removal_handler& get_nrppa_ue_context_removal_handler() override { return *this; } private: diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp index 05749c3390..d156cac51b 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.cpp @@ -38,7 +38,7 @@ cell_meas_manager_test::~cell_meas_manager_test() void cell_meas_manager_test::create_empty_manager() { cell_meas_manager_cfg cfg = {}; - manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); + manager = std::make_unique(cfg, mobility_manager, ue_mng); ASSERT_NE(manager, nullptr); } @@ -141,7 +141,7 @@ void cell_meas_manager_test::create_default_manager() a3_report_cfg = event_trigger_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); - manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); + manager = std::make_unique(cfg, mobility_manager, ue_mng); ASSERT_NE(manager, nullptr); } @@ -222,7 +222,7 @@ void cell_meas_manager_test::create_manager_with_incomplete_cells_and_periodic_r a3_report_cfg = event_trigger_cfg; cfg.report_config_ids.emplace(uint_to_report_cfg_id(2), a3_report_cfg); - manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); + manager = std::make_unique(cfg, mobility_manager, ue_mng); ASSERT_NE(manager, nullptr); } @@ -279,7 +279,7 @@ void cell_meas_manager_test::create_manager_without_ncells_and_periodic_report() a3_report_cfg = event_trigger_cfg = {}; cfg.report_config_ids.emplace(uint_to_report_cfg_id(1), a3_report_cfg); - manager = std::make_unique(cfg, mobility_manager, cu_cp_notifier, ue_mng); + manager = std::make_unique(cfg, mobility_manager, ue_mng); ASSERT_NE(manager, nullptr); } diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h index 9afc8bbe5e..9ab641bf75 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h @@ -29,15 +29,6 @@ class dummy_mobility_manager : public cell_meas_mobility_manager_notifier } }; -class dummy_cell_meas_manager_cu_cp_adapter : public cell_meas_manager_cu_cp_notifier -{ -public: - void on_ue_measurement(const ue_index_t ue_index, const cell_measurement_positioning_info& meas_result) override - { - fmt::print("on_ue_measurement() called.\n"); - } -}; - /// Fixture class to create cell meas manager object. class cell_meas_manager_test : public ::testing::Test { @@ -57,12 +48,11 @@ class cell_meas_manager_test : public ::testing::Test srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP", false); - std::unique_ptr manager; - dummy_mobility_manager mobility_manager; - dummy_cell_meas_manager_cu_cp_adapter cu_cp_notifier; - manual_task_worker ctrl_worker{128}; - timer_manager timers; - cu_cp_configuration cu_cp_cfg; + std::unique_ptr manager; + dummy_mobility_manager mobility_manager; + manual_task_worker ctrl_worker{128}; + timer_manager timers; + cu_cp_configuration cu_cp_cfg; ue_manager ue_mng{cu_cp_cfg}; }; From 76030451fbd417ba00eae44b3e097e17509a758b Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Thu, 5 Dec 2024 12:00:29 +0100 Subject: [PATCH 120/227] cu_cp,nrppa: get ue measurements directly from cu-cp ue --- include/srsran/nrppa/nrppa.h | 31 +++++++++---------- lib/cu_cp/adapters/nrppa_adapters.h | 12 +++---- .../cell_meas_manager_impl.cpp | 6 ---- .../cell_meas_manager_impl.h | 2 -- lib/cu_cp/cu_cp_impl.cpp | 6 ---- lib/cu_cp/cu_cp_impl.h | 2 -- lib/cu_cp/cu_cp_impl_interface.h | 6 ---- lib/cu_cp/ue_manager/cu_cp_ue_impl.h | 6 ++++ .../ue_manager/cu_cp_ue_impl_interface.h | 4 +++ 9 files changed, 30 insertions(+), 45 deletions(-) diff --git a/include/srsran/nrppa/nrppa.h b/include/srsran/nrppa/nrppa.h index ba85b2676e..356a9fab2e 100644 --- a/include/srsran/nrppa/nrppa.h +++ b/include/srsran/nrppa/nrppa.h @@ -17,6 +17,17 @@ namespace srsran { namespace srs_cu_cp { +struct cell_measurement_positioning_info { + struct cell_measurement_item_t { + nr_cell_global_id_t nr_cgi; + uint32_t nr_arfcn; + rrc_meas_result_nr meas_result; + }; + + nr_cell_global_id_t serving_cell_id; + std::map cell_measurements; +}; + /// NRPPA notifier to the CU-CP UE class nrppa_cu_cp_ue_notifier { @@ -26,21 +37,13 @@ class nrppa_cu_cp_ue_notifier /// \brief Get the UE index of the UE. virtual ue_index_t get_ue_index() = 0; + /// \brief Get the measurement results of the UE. + virtual std::optional& on_measurement_results_required() = 0; + /// \brief Schedule an async task for the UE. virtual bool schedule_async_task(async_task task) = 0; }; -struct cell_measurement_positioning_info { - struct cell_measurement_item_t { - nr_cell_global_id_t nr_cgi; - uint32_t nr_arfcn; - rrc_meas_result_nr meas_result; - }; - - nr_cell_global_id_t serving_cell_id; - std::map cell_measurements; -}; - /// Methods used by NRPPa to signal events to the CU-CP. class nrppa_cu_cp_notifier { @@ -52,12 +55,6 @@ class nrppa_cu_cp_notifier /// \returns Pointer to the NRPPA UE notifier. virtual nrppa_cu_cp_ue_notifier* on_new_nrppa_ue(ue_index_t ue_index) = 0; - /// \brief Notifies the CU-CP about a required UE measurement. - /// \param[in] ue_index The index of the UE. - /// \returns The measurement results if successful, an error string otherwise. - virtual expected - on_measurement_results_required(ue_index_t ue_index) = 0; - /// \brief Notifies about a NRPPa PDU. /// \param[in] nrppa_pdu The NRPPa PDU. /// \param[in] ue_index For UE associated messages the index of the UE. diff --git a/lib/cu_cp/adapters/nrppa_adapters.h b/lib/cu_cp/adapters/nrppa_adapters.h index f7f4010ebb..3d53b741b5 100644 --- a/lib/cu_cp/adapters/nrppa_adapters.h +++ b/lib/cu_cp/adapters/nrppa_adapters.h @@ -32,12 +32,6 @@ class nrppa_cu_cp_adapter : public nrppa_cu_cp_notifier return cu_cp_handler->handle_new_nrppa_ue(ue_index); } - expected on_measurement_results_required(ue_index_t ue_index) override - { - srsran_assert(cu_cp_handler != nullptr, "CU-CP NRPPA handler must not be nullptr"); - return cu_cp_handler->handle_measurement_results_required(ue_index); - } - void on_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override { srsran_assert(cu_cp_handler != nullptr, "CU-CP NRPPA handler must not be nullptr"); @@ -63,6 +57,12 @@ class nrppa_cu_cp_ue_adapter : public nrppa_cu_cp_ue_notifier return ue->get_ue_index(); } + std::optional& on_measurement_results_required() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_measurement_results(); + } + /// \brief Schedule an async task for the UE. bool schedule_async_task(async_task task) override { 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 c07b253799..7a6c5d3ba7 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 @@ -294,12 +294,6 @@ void cell_meas_manager::update_measurement_object(nr_cell_identity ssb_freq_to_meas_object.emplace(ssb_freq, generate_measurement_object(serving_cell_cfg)); } -SRSRAN_WEAK_SYMB expected - cell_meas_manager::get_meas_results(ue_index_t ue_index) -{ - return make_unexpected("Positioning measurements are not supported"); -} - SRSRAN_WEAK_SYMB void cell_meas_manager::store_measurement_results(ue_index_t ue_index, const rrc_meas_results& meas_results) { diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index b3eb96af4b..0f5f6c2f7b 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -49,8 +49,6 @@ class cell_meas_manager bool update_cell_config(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg); void report_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); - expected get_meas_results(ue_index_t ue_index); - private: /// \brief Generate measurement objects for the given cell configuration. void generate_measurement_objects_for_serving_cells(); diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index f9fe5ec7f3..e8a721de1a 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -622,12 +622,6 @@ SRSRAN_WEAK_SYMB nrppa_cu_cp_ue_notifier* cu_cp_impl::handle_new_nrppa_ue(ue_ind return nullptr; } -SRSRAN_WEAK_SYMB expected - cu_cp_impl::handle_measurement_results_required(ue_index_t ue_index) -{ - return make_unexpected("UL NRPPa messages are not supported"); -} - SRSRAN_WEAK_SYMB void cu_cp_impl::handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) { logger.info("UL NRPPa messages are not supported"); diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 153a160577..d16d805e58 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -110,8 +110,6 @@ class cu_cp_impl final : public cu_cp, // cu_cp_nrppa_handler. nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) override; - expected - handle_measurement_results_required(ue_index_t ue_index) override; void handle_ul_nrppa_pdu(const byte_buffer& nrppa_pdu, std::optional ue_index) override; // cu_cp_measurement_handler. diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 549eba9c93..3d8cbcf5df 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -124,12 +124,6 @@ class cu_cp_nrppa_handler /// \returns Pointer to the NRPPA UE notifier. virtual nrppa_cu_cp_ue_notifier* handle_new_nrppa_ue(ue_index_t ue_index) = 0; - /// \brief Handle a UE measurement request. - /// \param[in] ue_index The index of the UE. - /// \returns The measurement results if successful, an error string otherwise. - virtual expected - handle_measurement_results_required(ue_index_t ue_index) = 0; - /// \brief Handle a UL NRPPa PDU. /// \param[in] msg The NRPPa PDU. /// \param[in] ue_index For UE associated messages the index of the UE. diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h index 27e41a648a..23963094f3 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -132,6 +132,12 @@ class cu_cp_ue : public cu_cp_ue_impl_interface /// \brief Get the RRC UE of the UE. rrc_ue_interface* get_rrc_ue() const { return rrc_ue; } + /// \brief Get the measurement results of the UE. + std::optional& get_measurement_results() override + { + return meas_context.meas_results; + } + private: // common context ue_index_t ue_index = ue_index_t::invalid; diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h index caa452b67f..a2b39dbb89 100644 --- a/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h @@ -12,6 +12,7 @@ #include "../ue_security_manager/ue_security_manager_impl.h" #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/nrppa/nrppa.h" namespace srsran { @@ -43,6 +44,9 @@ class cu_cp_ue_impl_interface /// \brief Get the RRC UE notifier of the UE. virtual ngap_rrc_ue_notifier& get_ngap_rrc_ue_notifier() = 0; + + /// \brief Get the measurement results of the UE. + virtual std::optional& get_measurement_results() = 0; }; } // namespace srs_cu_cp From d91f05ada8ce6aecc61dc548a065c7e3872e07b2 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Mon, 9 Dec 2024 12:13:51 +0100 Subject: [PATCH 121/227] ran: add ran type for tac --- .../o_du_high/du_high/du_high_config.h | 3 +- .../du_high/du_high_config_validator.cpp | 2 +- apps/units/o_cu_cp/cu_cp/cu_cp_unit_config.h | 3 +- include/srsran/cu_cp/cu_cp_configuration.h | 3 +- include/srsran/cu_cp/cu_cp_types.h | 7 +++-- include/srsran/cu_cp/du_processor_context.h | 3 +- include/srsran/du/du_cell_config.h | 3 +- .../f1ap/du/f1ap_du_connection_manager.h | 3 +- include/srsran/ngap/ngap.h | 5 ++-- include/srsran/ngap/ngap_setup.h | 2 +- include/srsran/ran/tac.h | 28 +++++++++++++++++++ include/srsran/rrc/rrc_cell_context.h | 3 +- include/srsran/rrc/rrc_ue.h | 2 +- lib/cu_cp/adapters/rrc_ue_adapters.h | 2 +- lib/cu_cp/paging/paging_message_handler.cpp | 3 +- lib/ngap/ngap_asn1_helpers.h | 3 +- lib/ngap/ngap_impl.cpp | 2 +- tests/test_doubles/f1ap/f1ap_test_messages.h | 3 +- tests/unittests/cu_cp/test_helpers.h | 2 +- tests/unittests/rrc/test_helpers.h | 2 +- 20 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 include/srsran/ran/tac.h diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index f1151940bb..85ace11aa8 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -31,6 +31,7 @@ #include "srsran/ran/sib/system_info_config.h" #include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/subcarrier_spacing.h" +#include "srsran/ran/tac.h" #include "srsran/scheduler/config/scheduler_expert_config.h" #include "srsran/srslog/srslog.h" #include @@ -661,7 +662,7 @@ struct du_high_unit_base_cell_config { /// Human readable full PLMN (without possible filler digit). std::string plmn = "00101"; /// TAC. - unsigned tac = 7; + tac_t tac = 7; /// \c q-RxLevMin, part of \c cellSelectionInfo, \c SIB1, TS 38.311, in dBm. int q_rx_lev_min = -70; /// \c q-QualMin, part of \c cellSelectionInfo, \c SIB1, TS 38.311, in dB. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index d9546bf957..661c292368 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -1031,7 +1031,7 @@ static bool validate_cell_unit_config(const du_high_unit_cell_config& config, bo /// Validates the given list of cell application configuration. Returns true on success, otherwise false. static bool validate_cells_unit_config(span config, const gnb_id_t& gnb_id, bool ntn) { - unsigned tac = config[0].cell.tac; + tac_t tac = config[0].cell.tac; for (const auto& cell : config) { if (!validate_cell_unit_config(cell, ntn)) { return false; diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config.h b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config.h index 27b468f9b2..f3dc95c2e9 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config.h +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config.h @@ -17,6 +17,7 @@ #include "srsran/ran/pci.h" #include "srsran/ran/qos/five_qi.h" #include "srsran/ran/s_nssai.h" +#include "srsran/ran/tac.h" #include namespace srsran { @@ -33,7 +34,7 @@ struct cu_cp_unit_plmn_item { }; struct cu_cp_unit_supported_ta_item { - unsigned tac; + tac_t tac; std::vector plmn_list; }; diff --git a/include/srsran/cu_cp/cu_cp_configuration.h b/include/srsran/cu_cp/cu_cp_configuration.h index 1e819a53c8..d9a9f8eca6 100644 --- a/include/srsran/cu_cp/cu_cp_configuration.h +++ b/include/srsran/cu_cp/cu_cp_configuration.h @@ -17,6 +17,7 @@ #include "srsran/e2/e2ap_configuration.h" #include "srsran/e2/gateways/e2_connection_client.h" #include "srsran/f1ap/cu_cp/f1ap_configuration.h" +#include "srsran/ran/tac.h" #include "srsran/rrc/rrc_ue_config.h" #include "srsran/support/async/async_task.h" #include "srsran/support/executors/task_executor.h" @@ -36,7 +37,7 @@ struct plmn_item { }; struct supported_tracking_area { - unsigned tac; + tac_t tac; std::vector plmn_list; }; diff --git a/include/srsran/cu_cp/cu_cp_types.h b/include/srsran/cu_cp/cu_cp_types.h index ca9b0def25..0fe6400d3c 100644 --- a/include/srsran/cu_cp/cu_cp_types.h +++ b/include/srsran/cu_cp/cu_cp_types.h @@ -23,6 +23,7 @@ #include "srsran/ran/rb_id.h" #include "srsran/ran/s_nssai.h" #include "srsran/ran/subcarrier_spacing.h" +#include "srsran/ran/tac.h" #include "srsran/ran/up_transport_layer_info.h" #include #include @@ -130,7 +131,7 @@ struct cu_cp_qos_config { struct cu_cp_tai { plmn_identity plmn_id = plmn_identity::test_value(); - uint32_t tac; + tac_t tac; }; struct cu_cp_user_location_info_nr { @@ -247,8 +248,8 @@ struct cu_cp_nr_mode_info { struct cu_cp_served_cell_info { nr_cell_global_id_t nr_cgi; pci_t nr_pci; - std::optional five_gs_tac; - std::optional cfg_eps_tac; + std::optional five_gs_tac; + std::optional cfg_eps_tac; std::vector served_plmns; cu_cp_nr_mode_info nr_mode_info; byte_buffer meas_timing_cfg; diff --git a/include/srsran/cu_cp/du_processor_context.h b/include/srsran/cu_cp/du_processor_context.h index e253198433..9b1d405dd8 100644 --- a/include/srsran/cu_cp/du_processor_context.h +++ b/include/srsran/cu_cp/du_processor_context.h @@ -14,6 +14,7 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/ran/band_helper.h" #include "srsran/ran/nr_cgi.h" +#include "srsran/ran/tac.h" #include namespace srsran { @@ -31,7 +32,7 @@ struct du_cell_configuration { /// Global cell ID. nr_cell_global_id_t cgi; /// Tracking Area Code - uint32_t tac; + tac_t tac; /// Physical cell ID pci_t pci; /// NR bands provided/supported by the cell. diff --git a/include/srsran/du/du_cell_config.h b/include/srsran/du/du_cell_config.h index 36ca38830c..ce44b7685a 100644 --- a/include/srsran/du/du_cell_config.h +++ b/include/srsran/du/du_cell_config.h @@ -18,6 +18,7 @@ #include "srsran/ran/sib/system_info_config.h" #include "srsran/ran/srs/srs_configuration.h" #include "srsran/ran/ssb_configuration.h" +#include "srsran/ran/tac.h" #include "srsran/ran/tdd/tdd_ul_dl_config.h" #include "srsran/scheduler/config/bwp_configuration.h" #include "srsran/scheduler/config/serving_cell_config.h" @@ -179,7 +180,7 @@ struct mac_cell_group_params { /// other layers (e.g. scheduler). struct du_cell_config { pci_t pci; - uint32_t tac; + tac_t tac; nr_cell_global_id_t nr_cgi; carrier_configuration dl_carrier; diff --git a/include/srsran/f1ap/du/f1ap_du_connection_manager.h b/include/srsran/f1ap/du/f1ap_du_connection_manager.h index 6d0a16aa39..0d3c7516e2 100644 --- a/include/srsran/f1ap/du/f1ap_du_connection_manager.h +++ b/include/srsran/f1ap/du/f1ap_du_connection_manager.h @@ -18,6 +18,7 @@ #include "srsran/ran/pci.h" #include "srsran/ran/s_nssai.h" #include "srsran/ran/subcarrier_spacing.h" +#include "srsran/ran/tac.h" #include "srsran/support/async/async_task.h" #include @@ -28,7 +29,7 @@ namespace srs_du { struct f1_cell_setup_params { nr_cell_global_id_t nr_cgi; pci_t pci; - uint32_t tac; + tac_t tac; duplex_mode duplx_mode; subcarrier_spacing scs_common; carrier_configuration dl_carrier; diff --git a/include/srsran/ngap/ngap.h b/include/srsran/ngap/ngap.h index 13e501e3e3..d133ff02e8 100644 --- a/include/srsran/ngap/ngap.h +++ b/include/srsran/ngap/ngap.h @@ -251,9 +251,8 @@ class ngap_control_message_handler handle_handover_preparation_request(const ngap_handover_preparation_request& msg) = 0; /// \brief Handle the reception of an inter CU handove related RRC Reconfiguration Complete. - virtual void handle_inter_cu_ho_rrc_recfg_complete(const ue_index_t ue_index, - const nr_cell_global_id_t& cgi, - const unsigned tac) = 0; + virtual void + handle_inter_cu_ho_rrc_recfg_complete(const ue_index_t ue_index, const nr_cell_global_id_t& cgi, const tac_t tac) = 0; /// \brief Get the supported PLMNs. virtual const ngap_context_t& get_ngap_context() const = 0; diff --git a/include/srsran/ngap/ngap_setup.h b/include/srsran/ngap/ngap_setup.h index 9989c47f89..a2321e8768 100644 --- a/include/srsran/ngap/ngap_setup.h +++ b/include/srsran/ngap/ngap_setup.h @@ -26,7 +26,7 @@ struct ngap_broadcast_plmn_item { }; struct ngap_supported_ta_item { - uint32_t tac; + tac_t tac; std::vector broadcast_plmn_list; }; diff --git a/include/srsran/ran/tac.h b/include/srsran/ran/tac.h new file mode 100644 index 0000000000..68c01c8b1e --- /dev/null +++ b/include/srsran/ran/tac.h @@ -0,0 +1,28 @@ +/* + * + * 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 { + +/// 3GPP TS 38.331, TrackingAreaCode ::= BIT STRING (SIZE (24)). +using tac_t = uint32_t; +constexpr tac_t INVALID_TAC = 16777216; + +/// Returns true if the given struct is valid, otherwise false. +constexpr bool is_valid(tac_t tac) +{ + // TAC must be in [0..16777215]. + return tac < INVALID_TAC; +} + +} // namespace srsran diff --git a/include/srsran/rrc/rrc_cell_context.h b/include/srsran/rrc/rrc_cell_context.h index bdf2841afd..9d3088ce25 100644 --- a/include/srsran/rrc/rrc_cell_context.h +++ b/include/srsran/rrc/rrc_cell_context.h @@ -14,6 +14,7 @@ #include "srsran/ran/band_helper.h" #include "srsran/ran/nr_cgi.h" #include "srsran/ran/pci.h" +#include "srsran/ran/tac.h" #include namespace srsran { @@ -23,7 +24,7 @@ namespace srs_cu_cp { // Cell-related configuration used by the RRC. struct rrc_cell_context { nr_cell_global_id_t cgi; - uint32_t tac; + tac_t tac; pci_t pci; unsigned ssb_arfcn; ///< Absolute SSB position. std::vector bands; ///< Required for capability band filter. diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index e995bf83dd..e33d090033 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -186,7 +186,7 @@ class rrc_ue_ngap_notifier /// \brief Notify about the reception of an inter CU handove related RRC Reconfiguration Complete. virtual void on_inter_cu_ho_rrc_recfg_complete_received(const ue_index_t ue_index, const nr_cell_global_id_t& cgi, - const unsigned tac) = 0; + const tac_t tac) = 0; }; struct rrc_reconfiguration_response_message { diff --git a/lib/cu_cp/adapters/rrc_ue_adapters.h b/lib/cu_cp/adapters/rrc_ue_adapters.h index e7e61ee1df..ce108b6f49 100644 --- a/lib/cu_cp/adapters/rrc_ue_adapters.h +++ b/lib/cu_cp/adapters/rrc_ue_adapters.h @@ -68,7 +68,7 @@ class rrc_ue_ngap_adapter : public rrc_ue_ngap_notifier void on_inter_cu_ho_rrc_recfg_complete_received(const ue_index_t ue_index, const nr_cell_global_id_t& cgi, - const unsigned tac) override + const tac_t tac) override { srsran_assert(ngap != nullptr, "ue={}: NGAP for not found", ue_index); ngap->get_ngap_control_message_handler().handle_inter_cu_ho_rrc_recfg_complete(ue_index, cgi, tac); diff --git a/lib/cu_cp/paging/paging_message_handler.cpp b/lib/cu_cp/paging/paging_message_handler.cpp index fe9d7fe7a2..9323c17e5b 100644 --- a/lib/cu_cp/paging/paging_message_handler.cpp +++ b/lib/cu_cp/paging/paging_message_handler.cpp @@ -11,6 +11,7 @@ #include "paging_message_handler.h" #include "../du_processor/du_processor_repository.h" #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/ran/tac.h" using namespace srsran; using namespace srs_cu_cp; @@ -33,7 +34,7 @@ void paging_message_handler::handle_paging_message(const cu_cp_paging_message& m } } -static bool is_tac_in_list(span tai_list, unsigned tac) +static bool is_tac_in_list(span tai_list, tac_t tac) { return std::any_of(tai_list.begin(), tai_list.end(), [&tac](const auto& tai) { return tai.tai.tac == tac; }); } diff --git a/lib/ngap/ngap_asn1_helpers.h b/lib/ngap/ngap_asn1_helpers.h index 6989339913..0d27e6b0c2 100644 --- a/lib/ngap/ngap_asn1_helpers.h +++ b/lib/ngap/ngap_asn1_helpers.h @@ -24,6 +24,7 @@ #include "srsran/ngap/ngap_setup.h" #include "srsran/ngap/ngap_types.h" #include "srsran/ran/cu_types.h" +#include "srsran/ran/tac.h" #include "srsran/security/security.h" #include #include @@ -1108,7 +1109,7 @@ fill_asn1_handover_resource_allocation_response(asn1::ngap::ho_fail_s& /// \param[in] cgi The nr_cell_global_id common type struct of the UE. /// \param[in] tac The tac of the UE. inline void -fill_asn1_handover_notify(asn1::ngap::ho_notify_s& asn1_msg, const nr_cell_global_id_t& cgi, const unsigned tac) +fill_asn1_handover_notify(asn1::ngap::ho_notify_s& asn1_msg, const nr_cell_global_id_t& cgi, const tac_t tac) { auto& user_loc_info_nr = asn1_msg->user_location_info.set_user_location_info_nr(); user_loc_info_nr.nr_cgi = nr_cgi_to_ngap_asn1(cgi); diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 3008a43350..ad3182e4fe 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -964,7 +964,7 @@ ngap_impl::handle_handover_preparation_request(const ngap_handover_preparation_r void ngap_impl::handle_inter_cu_ho_rrc_recfg_complete(const ue_index_t ue_index, const nr_cell_global_id_t& cgi, - const unsigned tac) + const tac_t tac) { if (!ue_ctxt_list.contains(ue_index)) { logger.warning("ue={}: Dropping RrcReconfigurationComplete. UE context does not exist", ue_index); diff --git a/tests/test_doubles/f1ap/f1ap_test_messages.h b/tests/test_doubles/f1ap/f1ap_test_messages.h index cebb7ae34c..ff5381638f 100644 --- a/tests/test_doubles/f1ap/f1ap_test_messages.h +++ b/tests/test_doubles/f1ap/f1ap_test_messages.h @@ -23,6 +23,7 @@ #include "srsran/ran/rb_id.h" #include "srsran/ran/rnti.h" #include "srsran/ran/subcarrier_spacing.h" +#include "srsran/ran/tac.h" namespace srsran { @@ -38,7 +39,7 @@ struct served_cell_item_info { nr_cell_identity nci = nr_cell_identity::create(gnb_id_t{411, 22}, 0U).value(); pci_t pci = 0; - unsigned tac = 7; + tac_t tac = 7; nr_band band = nr_band::n78; uint32_t nr_arfcn = 626748; meas_timing_config meas_timing_cfg; diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index a2e5122589..c421f7bd31 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -408,7 +408,7 @@ struct dummy_ngap_control_message_handler : public ngap_control_message_handler void handle_inter_cu_ho_rrc_recfg_complete(const ue_index_t ue_index, const nr_cell_global_id_t& cgi, - const unsigned tac) override + const tac_t tac) override { logger.info("Received a RRC Reconfiguration Complete for Inter-CU Handover"); } diff --git a/tests/unittests/rrc/test_helpers.h b/tests/unittests/rrc/test_helpers.h index a753121dcb..f449ea8144 100644 --- a/tests/unittests/rrc/test_helpers.h +++ b/tests/unittests/rrc/test_helpers.h @@ -50,7 +50,7 @@ class dummy_rrc_ue_ngap_adapter : public rrc_ue_ngap_notifier void on_inter_cu_ho_rrc_recfg_complete_received(const ue_index_t ue_index, const nr_cell_global_id_t& cgi, - const unsigned tac) override + const tac_t tac) override { logger.info("ue={}: Received inter CU handover related RRC Reconfiguration Complete", ue_index); } From 7749ca45c9a872dc2edef9d47d83474935e595be Mon Sep 17 00:00:00 2001 From: Joaquim Broquetas Date: Thu, 5 Dec 2024 17:03:32 +0100 Subject: [PATCH 122/227] ran: fix dci f0_1 precoding info and nof. layers field size for maxRank=1 and 2 SRS ports --- lib/ran/pdcch/dci_packing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ran/pdcch/dci_packing.cpp b/lib/ran/pdcch/dci_packing.cpp index dc7ed8f2bc..61b557dc7a 100644 --- a/lib/ran/pdcch/dci_packing.cpp +++ b/lib/ran/pdcch/dci_packing.cpp @@ -212,7 +212,7 @@ static units::bits ul_precoding_info_size_2port_maxrank1(tx_scheme_codebook_subs return 3_bits; } - return 2_bits; + return 1_bits; } // Computes the UL precoding information field size for DCI format 0_1. From 852f93bb43f7d31f4cb92af01cc9f79903b53486 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Wed, 11 Dec 2024 15:46:14 +0100 Subject: [PATCH 123/227] ci: add drx test --- .gitlab/ci/e2e.yml | 16 ++++++++ .gitlab/ci/e2e/.env | 2 +- tests/e2e/pyproject.toml | 1 + tests/e2e/tests/ping.py | 53 ++++++++++++++++++++++++++ tests/e2e/tests/steps/configuration.py | 2 + 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index e428d1f28d..4930e6af4c 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -460,6 +460,22 @@ android x300: artifacts: true - *retina-needs +android x300 drx: + stage: rf + extends: .e2e-run + allow_failure: true + variables: + GROUP: "rf" + TESTBED: "android_x300" + MARKERS: "android_hp_drx" + E2E_LOG_LEVEL: "info" + KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" + KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" + needs: + - job: "basic relwithdeb" + artifacts: true + - *retina-needs + ################################################################################ # VIAVI ############################################################################### diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 762ed1dde4..cd7e609146 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.58.1 +RETINA_VERSION=0.58.2 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index ba65f86c33..5db84f008e 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -23,6 +23,7 @@ markers = [ "rf", "android", "android_hp", + "android_hp_drx", "udp", "tcp", "downlink", diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index 0afc5f81fb..85919a07a1 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -186,6 +186,57 @@ def test_android_hp( ) +@mark.parametrize( + "reattach_count", + (param(0, id="reattach:%s"),), +) +@mark.parametrize( + "band, common_scs, bandwidth", + ( + param(7, 15, 20, id="band:%s-scs:%s-bandwidth:%s"), + param(78, 30, 90, id="band:%s-scs:%s-bandwidth:%s"), + ), +) +@mark.android_hp_drx +@mark.flaky( + reruns=2, + only_rerun=["failed to start", "Exception calling application", "Attach timeout reached", "Some packages got lost"], +) +# pylint: disable=too-many-arguments,too-many-positional-arguments +def test_android_hp_drx( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue: UEStub, # pylint: disable=invalid-name + fivegc: FiveGCStub, + gnb: GNBStub, + band: int, + common_scs: int, + bandwidth: int, + reattach_count: int, +): + """ + Android high performance Pings + """ + + _ping( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=(ue,), + gnb=gnb, + fivegc=fivegc, + band=band, + common_scs=common_scs, + bandwidth=bandwidth, + sample_rate=None, + global_timing_advance=-1, + time_alignment_calibration="auto", + warning_as_errors=False, + always_download_artifacts=True, + reattach_count=reattach_count, + enable_drx=True, + ) + + @mark.parametrize( "band, common_scs, bandwidth, ciphering", ( @@ -493,6 +544,7 @@ def _ping( plmn: Optional[PLMN] = None, enable_security_mode: bool = False, ims_mode: str = "", + enable_drx: bool = False, ): logging.info("Ping Test") @@ -509,6 +561,7 @@ def _ping( log_ip_level="debug", enable_security_mode=enable_security_mode, ims_mode=ims_mode, + enable_drx=enable_drx, ) configure_artifacts( retina_data=retina_data, diff --git a/tests/e2e/tests/steps/configuration.py b/tests/e2e/tests/steps/configuration.py index 24854f992c..dea4a93c3f 100644 --- a/tests/e2e/tests/steps/configuration.py +++ b/tests/e2e/tests/steps/configuration.py @@ -45,6 +45,7 @@ def configure_test_parameters( nof_antennas_dl: int = 1, nof_antennas_ul: int = 1, ims_mode: str = "", + enable_drx: bool = False, ): """ Configure test parameters @@ -84,6 +85,7 @@ def configure_test_parameters( "enable_dddsu": enable_dddsu, "nof_antennas_dl": nof_antennas_dl, "nof_antennas_ul": nof_antennas_ul, + "enable_drx": enable_drx, }, }, "5gc": {"parameters": {"ims_mode": ims_mode}}, From b2071a69d8b40c628dbaa59db33967278eb91779 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 12 Dec 2024 14:21:01 +0100 Subject: [PATCH 124/227] pcaps,e2: fix release of cu_up e2ap pcap, without the fix the gnb cannot exit --- apps/units/o_cu_up/pcap_factory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/units/o_cu_up/pcap_factory.h b/apps/units/o_cu_up/pcap_factory.h index cbc0e043e6..76fe561a08 100644 --- a/apps/units/o_cu_up/pcap_factory.h +++ b/apps/units/o_cu_up/pcap_factory.h @@ -26,6 +26,7 @@ struct o_cu_up_dlt_pcaps { n3.reset(); f1u.reset(); e1ap.reset(); + e2ap.reset(); } }; From 236fef2e8cf7d3c5217556a427a2cd2ac8f34707 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 12 Dec 2024 14:25:12 +0100 Subject: [PATCH 125/227] cli,pcap: add autoderive of cu_up e2ap pcap enabled config parameter --- apps/cu/cu.cpp | 2 +- apps/gnb/gnb.cpp | 1 + apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.cpp | 6 ++++++ apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.h | 3 +++ apps/units/o_cu_up/o_cu_up_application_unit_impl.cpp | 5 +++++ apps/units/o_cu_up/o_cu_up_application_unit_impl.h | 2 +- 6 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 17bf0040b5..18b543fea0 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -150,7 +150,6 @@ static void autoderive_cu_up_parameters_after_parsing(o_cu_up_unit_config& o sock_cfg.bind_addr = cu_cp_cfg.amf_config.amf.bind_addr; o_cu_up_cfg.cu_up_cfg.ngu_cfg.ngu_socket_cfg.push_back(sock_cfg); } - o_cu_up_cfg.e2_cfg.pcaps.enabled = o_cu_up_cfg.e2_cfg.base_config.enable_unit_e2 && o_cu_up_cfg.e2_cfg.pcaps.enabled; } int main(int argc, char** argv) @@ -188,6 +187,7 @@ int main(int argc, char** argv) // Set the callback for the app calling all the autoderivation functions. app.callback([&app, &o_cu_cp_app_unit, &o_cu_up_app_unit]() { o_cu_cp_app_unit->on_configuration_parameters_autoderivation(app); + o_cu_up_app_unit->on_configuration_parameters_autoderivation(app); autoderive_cu_up_parameters_after_parsing(o_cu_up_app_unit->get_o_cu_up_unit_config(), o_cu_cp_app_unit->get_o_cu_cp_unit_config().cucp_cfg); diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 96499a0819..6e87138256 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -225,6 +225,7 @@ int main(int argc, char** argv) } o_cu_cp_app_unit->on_configuration_parameters_autoderivation(app); + o_cu_up_app_unit->on_configuration_parameters_autoderivation(app); autoderive_cu_up_parameters_after_parsing(o_cu_up_app_unit->get_o_cu_up_unit_config().cu_up_cfg, o_cu_cp_app_unit->get_o_cu_cp_unit_config().cucp_cfg); }); diff --git a/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.cpp b/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.cpp index d409dc2a1a..3488d4281d 100644 --- a/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.cpp +++ b/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.cpp @@ -30,3 +30,9 @@ void srsran::configure_cli11_with_o_cu_up_e2_config_schema(CLI::App& app, o_cu_u CLI::App* pcap_subcmd = add_subcommand(app, "pcap", "Logging configuration")->configurable(); configure_cli11_pcap_args(*pcap_subcmd, unit_cfg.pcaps); } + +void srsran::autoderive_o_cu_up_e2_parameters_after_parsing(o_cu_up_e2_config& unit_cfg) +{ + // If CU UP E2 agent is disabled do not enable e2ap pcap for it. + unit_cfg.pcaps.enabled = unit_cfg.base_config.enable_unit_e2 && unit_cfg.pcaps.enabled; +} \ No newline at end of file diff --git a/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.h b/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.h index 91e3bc45c5..c1f87363f2 100644 --- a/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.h +++ b/apps/units/o_cu_up/e2/o_cu_up_e2_config_cli11_schema.h @@ -19,4 +19,7 @@ struct o_cu_up_e2_config; /// Configures the given CLI11 application with the O-RAN CU-UP application unit E2 configuration schema. void configure_cli11_with_o_cu_up_e2_config_schema(CLI::App& app, o_cu_up_e2_config& unit_cfg); +/// Auto derive O-RAN CU-UP E2 parameters after the parsing. +void autoderive_o_cu_up_e2_parameters_after_parsing(o_cu_up_e2_config& unit_cfg); + } // namespace srsran diff --git a/apps/units/o_cu_up/o_cu_up_application_unit_impl.cpp b/apps/units/o_cu_up/o_cu_up_application_unit_impl.cpp index 20baf21670..2ff2493f4c 100644 --- a/apps/units/o_cu_up/o_cu_up_application_unit_impl.cpp +++ b/apps/units/o_cu_up/o_cu_up_application_unit_impl.cpp @@ -34,6 +34,11 @@ void o_cu_up_application_unit_impl::on_parsing_configuration_registration(CLI::A configure_cli11_with_o_cu_up_e2_config_schema(app, unit_cfg.e2_cfg); } +void o_cu_up_application_unit_impl::on_configuration_parameters_autoderivation(CLI::App& app) +{ + autoderive_o_cu_up_e2_parameters_after_parsing(unit_cfg.e2_cfg); +} + bool o_cu_up_application_unit_impl::on_configuration_validation(const os_sched_affinity_bitmask& available_cpus) const { return validate_cu_up_unit_config(unit_cfg.cu_up_cfg); diff --git a/apps/units/o_cu_up/o_cu_up_application_unit_impl.h b/apps/units/o_cu_up/o_cu_up_application_unit_impl.h index 500239efae..708870a0f5 100644 --- a/apps/units/o_cu_up/o_cu_up_application_unit_impl.h +++ b/apps/units/o_cu_up/o_cu_up_application_unit_impl.h @@ -25,7 +25,7 @@ class o_cu_up_application_unit_impl : public o_cu_up_application_unit void on_parsing_configuration_registration(CLI::App& app) override; // See interface for documentation. - void on_configuration_parameters_autoderivation(CLI::App& app) override {} + void on_configuration_parameters_autoderivation(CLI::App& app) override; // See interface for documentation. bool on_configuration_validation(const os_sched_affinity_bitmask& available_cpus) const override; From 2cbaa6e3acfba7cb8392b74bbaf7eb526b456363 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Thu, 12 Dec 2024 15:52:38 +0100 Subject: [PATCH 126/227] ci: increase acc100 test log level --- tests/e2e/tests/test_mode.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/test_mode.py b/tests/e2e/tests/test_mode.py index a3fa3c0fed..426dba1054 100644 --- a/tests/e2e/tests/test_mode.py +++ b/tests/e2e/tests/test_mode.py @@ -155,7 +155,9 @@ def test_ru_acc100( """ Run gnb in test mode ru dummy. """ - _test_ru(retina_manager, retina_data, gnb, ru_config="config_ru_acc100.yml") + _test_ru( + retina_manager, retina_data, gnb, ru_config="config_ru_acc100.yml", extra_cli_config="log --hal_level=debug" + ) @mark.test_mode @@ -221,6 +223,7 @@ def _test_ru( log_search: bool = True, warning_as_errors: bool = True, fail_if_kos: bool = True, + extra_cli_config: str = "", ): # pylint: disable=too-many-locals # Configuration with tempfile.NamedTemporaryFile(mode="w+") as tmp_file: @@ -260,7 +263,7 @@ def _test_ru( fivegc_definition=FiveGCDefinition(amf_ip=gnb_def.zmq_ip, amf_port=38412), start_info=StartInfo( timeout=gnb_startup_timeout, - post_commands=("cu_cp amf --no_core 1",), + post_commands=(f"cu_cp amf --no_core 1 {extra_cli_config}",), ), ) ) From 2444c4837259db7e311f4fcca23c198701eab81c Mon Sep 17 00:00:00 2001 From: sauka Date: Thu, 12 Dec 2024 16:37:37 +0100 Subject: [PATCH 127/227] ofh: reserve space in the mbufs for headroom and ethernet packets corresponding to max allowed mtu size --- lib/ofh/ethernet/dpdk/dpdk_ethernet_port_context.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ofh/ethernet/dpdk/dpdk_ethernet_port_context.cpp b/lib/ofh/ethernet/dpdk/dpdk_ethernet_port_context.cpp index 4ca00b13be..962af37840 100644 --- a/lib/ofh/ethernet/dpdk/dpdk_ethernet_port_context.cpp +++ b/lib/ofh/ethernet/dpdk/dpdk_ethernet_port_context.cpp @@ -169,8 +169,8 @@ std::shared_ptr dpdk_port_context::create(const dpdk_port_con { // Create the mbuf pool only once as it is common for all ports. static ::rte_mempool* mem_pool = []() { - ::rte_mempool* pool = - ::rte_pktmbuf_pool_create("OFH_MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, MAX_BUFFER_SIZE, ::rte_socket_id()); + ::rte_mempool* pool = ::rte_pktmbuf_pool_create( + "OFH_MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, (MAX_BUFFER_SIZE + RTE_PKTMBUF_HEADROOM), ::rte_socket_id()); if (pool == nullptr) { ::rte_exit(EXIT_FAILURE, "DPDK - Unable to create the DPDK mbuf pool\n"); } From 4ecc39e0614baa240353259752e06462eb76534c Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Thu, 12 Dec 2024 15:14:39 +0100 Subject: [PATCH 128/227] mac: fix failing e2e tests caused by pucch formats 3/4 --- .../du_high/du_high_config_cli11_schema.cpp | 8 +++---- .../du_high/du_high_config_translators.cpp | 7 +++--- .../du_high/du_high_config_validator.cpp | 5 +++++ .../du_high/du_high_config_yaml_writer.cpp | 4 ++-- .../du_pucch_resource_manager.cpp | 22 +++++++++---------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 7360006bd9..68c3a8380c 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -888,7 +888,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option(app, "--f0_or_f1_nof_cell_res_sr", pucch_params.nof_cell_sr_resources, - "Number of PUCCH F1 resources available per cell for SR") + "Number of PUCCH F0/F1 resources available per cell for SR") ->capture_default_str() ->check(CLI::Range(1, 100)); add_option(app, @@ -916,9 +916,9 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& ->capture_default_str() ->check(CLI::Range(1, 10)); add_option(app, - "--f2_nof_cell_res_csi", + "--f2_or_f3_or_f4_nof_cell_res_csi", pucch_params.nof_cell_csi_resources, - "Number of PUCCH F2 resources available per cell for CSI") + "Number of PUCCH F2/F3/F4 resources available per cell for CSI") ->capture_default_str() ->check(CLI::Range(0, 100)); add_option(app, "--f2_max_nof_rbs", pucch_params.f2_max_nof_rbs, "Max number of RBs for PUCCH F2 resources") @@ -962,7 +962,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option_function( app, "--f4_max_code_rate", - map_max_code_rate(pucch_params.f3_max_code_rate), + map_max_code_rate(pucch_params.f4_max_code_rate), "PUCCH F4 max code rate {dot08, dot15, dot25, dot35, dot45, dot60, dot80}. Default: dot35") ->check(CLI::IsMember({"dot08", "dot15", "dot25", "dot35", "dot45", "dot60", "dot80"}, CLI::ignore_case)); add_option(app, diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index 8df5ed177f..aa0068ab54 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -536,12 +536,13 @@ std::vector srsran::generate_du_cell_config(const du_hig du_pucch_cfg.nof_sr_resources = user_pucch_cfg.nof_cell_sr_resources; du_pucch_cfg.nof_csi_resources = param.csi_rs_enabled ? user_pucch_cfg.nof_cell_csi_resources : 0U; - if (user_pucch_cfg.use_format_0 and user_pucch_cfg.set1_format == 2) { + if (user_pucch_cfg.use_format_0) { auto& f0_params = du_pucch_cfg.f0_or_f1_params.emplace(); // Subtract 2 PUCCH resources from value: with Format 0, 2 extra resources will be added by the DU resource // allocator when the DU create the UE configuration. - du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; - du_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - 2U; + const unsigned extra_res_harq = user_pucch_cfg.set1_format == 2U ? 2U : 0U; + du_pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - extra_res_harq; + du_pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq = user_pucch_cfg.nof_ue_pucch_res_harq_per_set - extra_res_harq; f0_params.intraslot_freq_hopping = user_pucch_cfg.f0_intraslot_freq_hopping; } else { auto& f1_params = du_pucch_cfg.f0_or_f1_params.emplace(); diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index 661c292368..8839fc67ca 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -411,6 +411,11 @@ static bool validate_pucch_cell_unit_config(const du_high_unit_base_cell_config& return false; } + if (pucch_cfg.use_format_0 and pucch_cfg.set1_format != 2) { + fmt::print("Using PUCCH Formats 3 and 4 is not supported when Format 0 is used.\n"); + return false; + } + // See \c periodicityAndOffset in \c SchedulingRequestResourceConfig of TS 38.331. static const std::map> mu_to_valid_sr_period_slots_lookup{ {0, {1, 2, 4, 5, 8, 10, 16, 20, 40, 80}}, diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp index e4702cd239..022d6a63a1 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp @@ -410,7 +410,7 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c node["p0_nominal"] = config.p0_nominal; node["pucch_resource_common"] = config.pucch_resource_common; node["use_format_0"] = config.use_format_0; - node["set1_format"] = config.set1_format; + node["pucch_set1_format"] = config.set1_format; node["sr_period_ms"] = config.sr_period_msec; node["nof_ue_pucch_res_harq_per_set"] = config.nof_ue_pucch_res_harq_per_set; node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; @@ -429,10 +429,10 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c node["f3_additional_dmrs"] = config.f3_additional_dmrs; node["f3_pi2_bpsk"] = config.f3_pi2_bpsk; node["f4_intraslot_freq_hop"] = config.f4_intraslot_freq_hopping; + node["f4_max_code_rate"] = to_string(config.f4_max_code_rate); node["f4_additional_dmrs"] = config.f4_additional_dmrs; node["f4_pi2_bpsk"] = config.f4_pi2_bpsk; node["f4_occ_length"] = config.f4_occ_length; - node["f4_occ_length"] = config.f4_occ_length; node["min_k1"] = config.min_k1; node["max_consecutive_kos"] = config.max_consecutive_kos; if (config.f2_max_payload_bits.has_value()) { diff --git a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index b01fd29d6f..d8a7155c5b 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -40,17 +40,17 @@ static pucch_config build_default_pucch_cfg(const pucch_config& pucch_cfg, const if (not std::holds_alternative(user_params.f0_or_f1_params)) { target_pucch_cfg.format_1_common_param.reset(); } - std::visit( - [&target_pucch_cfg](const auto& params) { - if constexpr (std::is_same_v) { - target_pucch_cfg.format_2_common_param.value().max_c_rate = params.max_code_rate; - } else if constexpr (std::is_same_v) { - target_pucch_cfg.format_3_common_param.value().max_c_rate = params.max_code_rate; - } else if constexpr (std::is_same_v) { - target_pucch_cfg.format_4_common_param.value().max_c_rate = params.max_code_rate; - } - }, - user_params.f2_or_f3_or_f4_params); + + if (std::holds_alternative(user_params.f2_or_f3_or_f4_params)) { + const auto& f2_params = std::get(user_params.f2_or_f3_or_f4_params); + target_pucch_cfg.format_2_common_param.value().max_c_rate = f2_params.max_code_rate; + } else if (std::holds_alternative(user_params.f2_or_f3_or_f4_params)) { + const auto& f3_params = std::get(user_params.f2_or_f3_or_f4_params); + target_pucch_cfg.format_3_common_param.value().max_c_rate = f3_params.max_code_rate; + } else { + const auto& f4_params = std::get(user_params.f2_or_f3_or_f4_params); + target_pucch_cfg.format_4_common_param.value().max_c_rate = f4_params.max_code_rate; + } return target_pucch_cfg; } From 538486e02e0fb9133ddcfe306b1d10416093c50c Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 12 Dec 2024 16:26:29 +0100 Subject: [PATCH 129/227] sched: increase phr ring buffer size Signed-off-by: Carlo Galiotto --- lib/scheduler/support/ul_power_controller.cpp | 2 ++ lib/scheduler/support/ul_power_controller.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/scheduler/support/ul_power_controller.cpp b/lib/scheduler/support/ul_power_controller.cpp index ea49d8d881..039d1bd256 100644 --- a/lib/scheduler/support/ul_power_controller.cpp +++ b/lib/scheduler/support/ul_power_controller.cpp @@ -16,6 +16,7 @@ using namespace srsran; ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell_cfg, const ue_channel_state_manager& ch_state_manager) : + rnti(ue_cell_cfg.crnti), cl_pw_control_enabled(ue_cell_cfg.cell_cfg_common.expert_cfg.ue.ul_power_ctrl.enable_pusch_cl_pw_control), p0_nominal_pusch( ue_cell_cfg.cell_cfg_common.ul_cfg_common.init_ul_bwp.pusch_cfg_common.value().p0_nominal_with_grant.to_int()), @@ -40,6 +41,7 @@ ul_power_controller::ul_power_controller(const ue_cell_configuration& ue_cell pusch_pw_ctrl_data{slot_point{}, init_nof_prbs, init_f_pw_control}); // Dummy casts only needed to prevent Clang from complaining about unused variables. + static_cast(rnti); static_cast(cl_pw_control_enabled); static_cast(channel_state_manager); static_cast(ref_path_loss_for_target_sinr); diff --git a/lib/scheduler/support/ul_power_controller.h b/lib/scheduler/support/ul_power_controller.h index fa79987038..ab3bbb7529 100644 --- a/lib/scheduler/support/ul_power_controller.h +++ b/lib/scheduler/support/ul_power_controller.h @@ -43,7 +43,7 @@ class ul_power_controller /// maximum expected delay (in slots) between the for which slot the PUSCH is scheduled and the slot at which the PHR /// is received; this delay depends on the PHY processing capabilities. For simplicity, we take round the number to a /// multiple of 10. - static constexpr size_t MAX_PHR_IND_DELAY_SLOTS = 40; + static constexpr size_t MAX_PHR_IND_DELAY_SLOTS = 80; /// This variable defines a time window after a PUSCH transmission, in slots, in which TPC adjustments are forbidden. /// This is to prevent the PUSCH TPC to be adjusted too quickly, leading to oscillations in the SINR. // [Implementation-defined] This value should be enough to guarantee that the CRC indication (reporting the PUSCH @@ -53,8 +53,9 @@ class ul_power_controller /// low. static constexpr int min_f_cl_pw_control = -30; - const bool cl_pw_control_enabled; - const int p0_nominal_pusch; + const rnti_t rnti; + const bool cl_pw_control_enabled; + const int p0_nominal_pusch; // Configuration for the PUSCH power control. std::optional pusch_pwr_ctrl; const ue_channel_state_manager& channel_state_manager; From 533c3cc05b7c73fe595efabb901d12f8d1af2213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Wed, 4 Dec 2024 17:14:37 +0100 Subject: [PATCH 130/227] ci: use splits in e2e build jobs --- .gitlab/ci/build.yml | 88 ++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 1cbe76cd82..1e9e858bad 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -71,13 +71,15 @@ variables: echo "DPDK_VERSION=${DPDK_VERSION}" build_srsgnb() { + target="$1" + start_time=$(date +%s) if [ -e "/usr/local/bin/ram_reporter.py" ]; then /usr/local/builder_tools/bin/python3 /usr/local/bin/ram_reporter.py ${CI_PROJECT_DIR}/ram_usage.txt & ram_reporter_pid=$! fi - build_srsran "" ${CMAKE_FLAGS_CMD} + build_srsran "${target}" ${CMAKE_FLAGS_CMD} if [[ -n "$OUTPUT_FINGERPRINT" ]]; then echo "Storing fingerprints of all executables to $OUTPUT_FINGERPRINT" cd build @@ -185,7 +187,7 @@ variables: exit $ret } - - build_srsgnb + - build_srsgnb ${SRS_TARGET} - launch_tests timeout: 6h @@ -193,9 +195,9 @@ variables: after_script: &build_after_script - mv ${CI_PROJECT_DIR}/build/coverage.xml ${CI_PROJECT_DIR}/${CI_JOB_ID}_coverage.xml || true - | - mv ${CI_PROJECT_DIR}/build/apps/gnb/gnb /tmp/gnb - mv ${CI_PROJECT_DIR}/build/apps/cu/srscu /tmp/srscu - mv ${CI_PROJECT_DIR}/build/apps/du/srsdu /tmp/srsdu + find ${CI_PROJECT_DIR}/build -name "gnb" -type f -executable -exec mv {} /tmp/gnb \; + find ${CI_PROJECT_DIR}/build -name "srscu" -type f -executable -exec mv {} /tmp/srscu \; + find ${CI_PROJECT_DIR}/build -name "srsdu" -type f -executable -exec mv {} /tmp/srsdu \; cd build make clean mv /tmp/gnb ${CI_PROJECT_DIR}/build/apps/gnb/gnb @@ -236,6 +238,9 @@ variables: fi - *srs_functions - build_srsgnb + - | + rm ${CI_PROJECT_DIR}/build/apps/gnb_split_7_2/gnb + rm ${CI_PROJECT_DIR}/build/apps/gnb_split_8/gnb - launch_tests variables: OS: ubuntu-24.04 @@ -1574,20 +1579,6 @@ check-affinity-manager-nocpu: ############### # E2E Nightly # ############### -basic relwithdeb: - extends: .smoke relwithdeb - rules: - - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ - retry: 2 - interruptible: false - variables: - TEST_MODE: none - after_script: - - *build_after_script - artifacts: - <<: *build_artifacts - expire_in: 3 day - basic package: extends: .deb-package stage: build and unit tests @@ -1601,50 +1592,92 @@ basic package: INFRASTRUCTURE_TAG: amd64-avx2 needs: [] +basic relwithdeb: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ + retry: 2 + interruptible: false + variables: + SRS_TARGET: srscu srsdu gnb + OS: ubuntu-24.04 + COMPILER: gcc + CMAKE_BUILD_TYPE: RelWithDebInfo + ASSERT_LEVEL: PARANOID + TEST_MODE: none + MARCH: x86-64-v3 + INFRASTRUCTURE_TAG: amd64-avx2 + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts + expire_in: 3 days + basic tsan: - extends: .smoke tsan + extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ retry: 2 interruptible: false variables: + SRS_TARGET: gnb + OS: ubuntu-24.04 + COMPILER: clang + CMAKE_BUILD_TYPE: Debug + ASSERT_LEVEL: PARANOID + ENABLE_TSAN: "True" TEST_MODE: none + MARCH: x86-64-v3 + INFRASTRUCTURE_TAG: amd64-avx2 after_script: - *build_after_script artifacts: <<: *build_artifacts - expire_in: 3 day + expire_in: 3 days basic asan: - extends: smoke asan + extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ retry: 2 interruptible: false variables: + SRS_TARGET: gnb + OS: ubuntu-24.04 + COMPILER: clang + CMAKE_BUILD_TYPE: Debug + ASSERT_LEVEL: PARANOID + ENABLE_ASAN: "True" TEST_MODE: none MARCH: x86-64-v3 - BUILD_ARGS: -DEXIT_TIMEOUT=60 INFRASTRUCTURE_TAG: amd64-avx2 + BUILD_ARGS: -DEXIT_TIMEOUT=60 after_script: - *build_after_script artifacts: <<: *build_artifacts - expire_in: 3 day + expire_in: 3 days basic memcheck: - extends: .smoke valgrind + extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ retry: 2 interruptible: false variables: + SRS_TARGET: gnb + OS: ubuntu-24.04 + COMPILER: gcc + CMAKE_BUILD_TYPE: Debug + ASSERT_LEVEL: PARANOID TEST_MODE: none + MARCH: x86-64-v3 + INFRASTRUCTURE_TAG: amd64-avx2 after_script: - *build_after_script artifacts: <<: *build_artifacts - expire_in: 3 day + expire_in: 3 days basic avx512 dpdk: extends: .build_and_unit @@ -1654,6 +1687,7 @@ basic avx512 dpdk: retry: 2 interruptible: false variables: + SRS_TARGET: gnb_split_7_2 OS: ubuntu-24.04 COMPILER: gcc CMAKE_BUILD_TYPE: Release @@ -1670,7 +1704,7 @@ basic avx512 dpdk: - *build_after_script artifacts: <<: *build_artifacts - expire_in: 3 day + expire_in: 3 days basic avx512 dpdk withassert: extends: basic avx512 dpdk From 47026f4bbc5f80766bfcafdd8bbf3a6816aa3f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Tue, 10 Dec 2024 18:29:57 +0100 Subject: [PATCH 131/227] ci: add depends on plugin --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 42ec87abd0..60976408b6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -140,6 +140,7 @@ plugin nightly: trigger: project: ${PLUGIN_REPO} branch: main + strategy: depend matlab weekly: stage: ci From f4a4d2bb6202b26f98e2df794ee2db7c5801679c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Tue, 10 Dec 2024 18:30:10 +0100 Subject: [PATCH 132/227] ci: add support for plugin in all build jobs --- .gitlab-ci.yml | 7 +++++ .gitlab/ci/build.yml | 30 ++++++++++------------ .gitlab/ci/builders/codechecker/Dockerfile | 1 + 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 60976408b6..b1e28e450d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,6 +55,7 @@ variables: SLACK_CHANNEL_FAIL: "#ci_gnb" SLACK_CHANNEL_INFO_MSG: "#ci_gnb_verbose" AUTOREBASER_PRS_IN_QUEUE: 1 + MR_PLUGIN_REF: main ################################################################################ ## CI @@ -226,6 +227,11 @@ full-code-format: -*lib/asn1 -*lib/phy/generic_functions/fftx/lib_fftx_dftbat_srcs -*lib/phy/generic_functions/fftx/lib_fftx_idftbat_srcs" >/tmp/codechecker_skip + - | + if [[ $CI_MERGE_REQUEST_LABELS != *"ci-no-plugin"* && -n $PLUGIN_BRANCH ]]; then + git submodule add https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_SHELL_SSH_HOST}/${PLUGIN_REPO}.git ${PLUGIN_PATH} + git submodule set-branch --branch ${PLUGIN_BRANCH} ${PLUGIN_PATH} + fi - | export CC=/usr/bin/clang export CXX=/usr/bin/clang++ @@ -268,6 +274,7 @@ clang-tidy: when: manual allow_failure: false variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF ANALYZER: clang-tidy ANALYZER_ARGS: --analyzer-config clang-tidy:take-config-from-directory=true --tidy-config .clang-tidy ARTIFACT_EXTRA_PATH: "/index.html" diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 1e9e858bad..62d671dd5e 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -187,6 +187,10 @@ variables: exit $ret } + if [[ $CI_MERGE_REQUEST_LABELS != *"ci-no-plugin"* && -n $PLUGIN_BRANCH ]]; then + git submodule add https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_SHELL_SSH_HOST}/${PLUGIN_REPO}.git ${PLUGIN_PATH} >/dev/null + git submodule set-branch --branch ${PLUGIN_BRANCH} ${PLUGIN_PATH} + fi - build_srsgnb ${SRS_TARGET} - launch_tests timeout: 6h @@ -231,11 +235,7 @@ variables: .smoke relwithdeb: extends: .build_and_unit - script: &smoke_script - - | - if [[ $CI_MERGE_REQUEST_LABELS != *"ci-no-plugin"* ]]; then - git submodule add https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_SHELL_SSH_HOST}/${PLUGIN_REPO}.git ${PLUGIN_PATH} - fi + script: - *srs_functions - build_srsgnb - | @@ -243,6 +243,7 @@ variables: rm ${CI_PROJECT_DIR}/build/apps/gnb_split_8/gnb - launch_tests variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-24.04 COMPILER: clang CMAKE_BUILD_TYPE: RelWithDebInfo @@ -253,9 +254,8 @@ variables: .smoke tsan: extends: .build_and_unit - script: - - *smoke_script variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-24.04 COMPILER: clang CMAKE_BUILD_TYPE: Debug @@ -279,6 +279,7 @@ variables: .smoke archlinux: extends: .build_and_unit variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: archlinux-latest ENABLE_WERROR: "False" COMPILER: gcc @@ -290,9 +291,8 @@ variables: .smoke dpdk: extends: .build_and_unit - script: - - *smoke_script variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-22.04 COMPILER: gcc CMAKE_BUILD_TYPE: Release @@ -307,6 +307,7 @@ variables: .smoke valgrind: extends: .build_and_unit variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-24.04 COMPILER: gcc CMAKE_BUILD_TYPE: Debug @@ -317,9 +318,8 @@ variables: .smoke avx512: extends: .build_and_unit - script: - - *smoke_script variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-24.04 COMPILER: gcc CMAKE_BUILD_TYPE: Release @@ -330,9 +330,8 @@ variables: .smoke arm: extends: .build_and_unit - script: - - *smoke_script variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-24.04 COMPILER: gcc CMAKE_BUILD_TYPE: Release @@ -343,9 +342,8 @@ variables: .smoke arm neon: extends: .build_and_unit - script: - - *smoke_script variables: + PLUGIN_BRANCH: $MR_PLUGIN_REF OS: ubuntu-24.04 COMPILER: gcc CMAKE_BUILD_TYPE: Release @@ -1672,7 +1670,7 @@ basic memcheck: ASSERT_LEVEL: PARANOID TEST_MODE: none MARCH: x86-64-v3 - INFRASTRUCTURE_TAG: amd64-avx2 + INFRASTRUCTURE_TAG: amd64-avx2 after_script: - *build_after_script artifacts: diff --git a/.gitlab/ci/builders/codechecker/Dockerfile b/.gitlab/ci/builders/codechecker/Dockerfile index c30c3d1636..d830881d1b 100644 --- a/.gitlab/ci/builders/codechecker/Dockerfile +++ b/.gitlab/ci/builders/codechecker/Dockerfile @@ -16,4 +16,5 @@ ADD install_dependencies.sh /usr/local/bin RUN chmod +x /usr/local/bin/install_dependencies.sh RUN DEBIAN_FRONTEND=noninteractive apt-get update && install_dependencies.sh \ + && apt-get install -y --no-install-recommends git \ && apt-get autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* From 82f3502515f87b8a23cb3b3161c5cb4a8cae0cf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 17:32:48 +0100 Subject: [PATCH 133/227] ci: plugin nightlies --- .gitlab-ci.yml | 34 +++------ .gitlab/ci/build.yml | 129 ++++++++++++++------------------- .gitlab/ci/e2e.yml | 14 +++- .gitlab/ci/schedules.yml | 64 ++++++++++++++-- .gitlab/run_custom_pipeline.py | 16 +++- 5 files changed, 148 insertions(+), 109 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b1e28e450d..7b195518fb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -64,14 +64,14 @@ job cleaner: extends: .job cleaner timeout: 4h rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ pr reminder: extends: .pr reminder rules: - if: $NOTIFY_SLACK != "true" when: never - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ trigger builder: stage: ci @@ -100,7 +100,7 @@ trigger docker: - docker/**/*.{yml,env,json,toml,py,sh,csv,py,toml} - docker/**/Dockerfile - .gdbinit - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ variables: CI_DESCRIPTION: $CI_DESCRIPTION - if: $CI_DESCRIPTION =~ /Weekly/ @@ -115,7 +115,7 @@ trigger docker: matlab nightly: stage: ci rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ variables: ON_SCHEDULE: "true" CI_DESCRIPTION: Nightly @@ -127,22 +127,6 @@ matlab nightly: project: softwareradiosystems/srsgnb_matlab branch: master -plugin nightly: - stage: ci - rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ - variables: - ON_SCHEDULE: "true" - CI_DESCRIPTION: Nightly - SRSRAN_COMMIT: $CI_COMMIT_SHA - NOTIFY_SLACK: "true" - inherit: - variables: false - trigger: - project: ${PLUGIN_REPO} - branch: main - strategy: depend - matlab weekly: stage: ci rules: @@ -191,7 +175,7 @@ full-code-format: - if: $ON_MR changes: - .clang-format - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ .codechecker: image: ${CR_REGISTRY_URI}/srsgnb/codechecker:${DOCKER_BUILDER_VERSION} @@ -443,7 +427,7 @@ unit coverage: unit coverage dev: extends: unit coverage rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ variables: coverage_report: full when: always # Even if previous stages/required jobs fail @@ -454,7 +438,7 @@ unit coverage dev: pages: stage: documentation rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: always # Even if previous stages/required jobs fail allow_failure: true image: ${GITLAB_REGISTRY_URI}/${CI_TOOLS_REPO}/doxygen:1.9.8-1.2023.7 @@ -507,7 +491,7 @@ update agpl main dryrun: extends: update private branch stage: .post rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: always variables: PRIVATE_BRANCH: agpl_main @@ -519,7 +503,7 @@ create-tags: extends: .create-tag stage: .post rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 3 hours script: diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 62d671dd5e..bb7d66df22 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -69,6 +69,7 @@ variables: echo "MAKE_ARGS=${MAKE_ARGS}" echo "UHD_VERSION=${UHD_VERSION}" echo "DPDK_VERSION=${DPDK_VERSION}" + echo "PLUGIN_BRANCH=${PLUGIN_BRANCH}" build_srsgnb() { target="$1" @@ -188,8 +189,8 @@ variables: exit $ret } if [[ $CI_MERGE_REQUEST_LABELS != *"ci-no-plugin"* && -n $PLUGIN_BRANCH ]]; then - git submodule add https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_SHELL_SSH_HOST}/${PLUGIN_REPO}.git ${PLUGIN_PATH} >/dev/null - git submodule set-branch --branch ${PLUGIN_BRANCH} ${PLUGIN_PATH} + git submodule add https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_SHELL_SSH_HOST}/${PLUGIN_REPO}.git ${PLUGIN_PATH} >/dev/null 2>&1 + git submodule set-branch --branch ${PLUGIN_BRANCH} ${PLUGIN_PATH} >/dev/null 2>&1 fi - build_srsgnb ${SRS_TARGET} - launch_tests @@ -629,7 +630,7 @@ check builders ubuntu versions: extends: .check image exists for all supported ubuntu versions stage: static rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed start_in: 15 minutes variables: @@ -642,7 +643,7 @@ check builders ubuntu versions: smoke release update cache: extends: .smoke release rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -658,7 +659,7 @@ smoke release update cache: smoke relwithdeb update cache: extends: .smoke relwithdeb rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -669,7 +670,7 @@ smoke relwithdeb update cache: smoke tsan update cache: extends: .smoke tsan rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes interruptible: false @@ -680,7 +681,7 @@ smoke tsan update cache: smoke rhel update cache: extends: .smoke rhel rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -691,7 +692,7 @@ smoke rhel update cache: smoke archlinux update cache: extends: .smoke archlinux rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -702,7 +703,7 @@ smoke archlinux update cache: smoke dpdk update cache: extends: .smoke dpdk rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -713,7 +714,7 @@ smoke dpdk update cache: smoke valgrind update cache: extends: .smoke valgrind rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes interruptible: false @@ -729,7 +730,7 @@ smoke valgrind update cache: smoke avx512 update cache: extends: .smoke avx512 rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes interruptible: false @@ -740,7 +741,7 @@ smoke avx512 update cache: smoke arm update cache: extends: .smoke arm rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -751,7 +752,7 @@ smoke arm update cache: smoke arm neon update cache: extends: .smoke arm neon rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ when: delayed start_in: 45 minutes retry: 2 @@ -783,7 +784,7 @@ package: extends: .deb-package stage: build and unit tests rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests OpenSource/ when: delayed start_in: 45 minutes variables: &package_variables @@ -808,7 +809,7 @@ install-package: extends: .deb-install stage: build and unit tests rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests OpenSource/ variables: PROJECT_NAME: srsran-project RELEASE_VERSION: "99.9" @@ -827,7 +828,7 @@ check package ubuntu versions: extends: .check packaging ubuntu images stage: static rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed start_in: 15 minutes @@ -891,13 +892,16 @@ ubuntu-24.04 amd64 avx2: parallel: matrix: - <<: *basic_combinations + - <<: *basic_combinations + ENABLE_FFTW: "False" + ENABLE_MKL: "True" ubuntu-24.04 amd64 avx512: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 135 minutes + start_in: 165 minutes interruptible: false variables: OS: ubuntu-24.04 @@ -906,13 +910,16 @@ ubuntu-24.04 amd64 avx512: parallel: matrix: - <<: *basic_combinations + - <<: *basic_combinations + ENABLE_FFTW: "False" + ENABLE_MKL: "True" ubuntu-22.04 amd64 avx2: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 165 minutes + start_in: 195 minutes interruptible: false variables: OS: ubuntu-22.04 @@ -927,7 +934,7 @@ rhel-8 amd64 avx2: rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 195 minutes + start_in: 225 minutes interruptible: false variables: OS: rhel-8 @@ -953,6 +960,9 @@ ubuntu-24.04 arm neon: parallel: matrix: - <<: *basic_combinations + - <<: *basic_combinations + ENABLE_FFTW: "False" + ENABLE_ARMPL: "True" # Basic DPDK @@ -961,7 +971,7 @@ ubuntu dpdk: rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ when: delayed - start_in: 225 minutes + start_in: 260 minutes interruptible: false variables: ENABLE_UHD: "False" @@ -1297,6 +1307,9 @@ ubuntu-24.04 amd64 native: parallel: matrix: - <<: *basic_combinations + - <<: *basic_combinations + ENABLE_FFTW: "False" + ENABLE_MKL: "True" ubuntu-24.04 arm native: extends: .build_and_unit @@ -1311,13 +1324,16 @@ ubuntu-24.04 arm native: parallel: matrix: - <<: *basic_combinations + - <<: *basic_combinations + ENABLE_FFTW: "False" + ENABLE_ARMPL: "True" ubuntu-22.04 amd64 native: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 90 minutes + start_in: 120 minutes interruptible: false variables: OS: ubuntu-22.04 @@ -1331,7 +1347,7 @@ ubuntu-22.04 amd64 avx512: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 90 minutes + start_in: 120 minutes interruptible: false variables: OS: ubuntu-22.04 @@ -1346,7 +1362,7 @@ ubuntu-22.04 arm native: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 90 minutes + start_in: 120 minutes interruptible: false variables: OS: ubuntu-22.04 @@ -1360,7 +1376,7 @@ ubuntu-22.04 arm neon: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 90 minutes + start_in: 120 minutes interruptible: false variables: OS: ubuntu-22.04 @@ -1375,7 +1391,7 @@ rhel-8 amd64 native: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 120 minutes + start_in: 150 minutes interruptible: false variables: OS: rhel-8 @@ -1389,7 +1405,7 @@ rhel-8 amd64 avx512: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 120 minutes + start_in: 150 minutes interruptible: false variables: OS: rhel-8 @@ -1404,7 +1420,7 @@ rhel-8 arm native: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 120 minutes + start_in: 150 minutes interruptible: false variables: OS: rhel-8 @@ -1418,7 +1434,7 @@ rhel-8 arm neon: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 120 minutes + start_in: 150 minutes interruptible: false variables: OS: rhel-8 @@ -1484,13 +1500,17 @@ ubuntu-24.04 amd64 avx2 dpdk: matrix: - <<: *basic_combinations_dpdk DPDK_VERSION: "23.11.1_avx2" + - <<: *basic_combinations + DPDK_VERSION: "23.11.1_avx2" + ENABLE_FFTW: "False" + ENABLE_MKL: "True" ubuntu-24.04 amd64 avx512 dpdk: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 270 minutes + start_in: 320 minutes interruptible: false variables: OS: ubuntu-24.04 @@ -1500,13 +1520,17 @@ ubuntu-24.04 amd64 avx512 dpdk: matrix: - <<: *basic_combinations_dpdk DPDK_VERSION: "23.11.1_avx512" + - <<: *basic_combinations + DPDK_VERSION: "23.11.1_avx512" + ENABLE_FFTW: "False" + ENABLE_MKL: "True" ubuntu-24.10 amd64 avx2 dpdk: extends: .build_and_unit rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 300 minutes + start_in: 360 minutes interruptible: false variables: OS: ubuntu-24.10 @@ -1522,7 +1546,7 @@ ubuntu-24.10 amd64 avx512 dpdk: rules: - if: $CI_DESCRIPTION =~ /Weekly/ when: delayed - start_in: 300 minutes + start_in: 360 minutes interruptible: false variables: OS: ubuntu-24.10 @@ -1533,47 +1557,6 @@ ubuntu-24.10 amd64 avx512 dpdk: - <<: *basic_combinations_dpdk DPDK_VERSION: "23.11.1_avx512" -############# -# Run check # -############# - -check-affinity-manager-nocpu: - image: ${CR_REGISTRY_URI}/srsgnb/builder-ubuntu-24.04:${DOCKER_BUILDER_VERSION} - stage: build and unit tests - needs: - - job: "smoke release update cache" - artifacts: true - - job: builder version - optional: false - artifacts: true - rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ - timeout: 15 minutes - tags: [amd64] - script: - - cd build/apps/gnb - - | - error_found=false - for (( i=3; i<=10; i++ )) - do - echo "Checking for number of CPU = $((i-2))" - output=$(taskset -c 2-$i bash -c "./gnb log --filename=stdout" 2>&1 || true) - echo "$output" - - if [[ "$output" == *"nof_cores_for_non_prio_threads"* ]]; then - error_found=true - echo "**********************************************************************************" - echo $output - echo "**********************************************************************************" - echo "Error for number of CPU = $((i-2))" - echo -e "\n\n\n\n\n" - fi - done - - if [ "$error_found" = true ]; then - exit 1 - fi - ############### # E2E Nightly # ############### @@ -1581,7 +1564,7 @@ basic package: extends: .deb-package stage: build and unit tests rules: - - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests OpenSource/ retry: 2 interruptible: false variables: diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 4930e6af4c..4be3ac9107 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -163,6 +163,8 @@ amari 1UE 4x4 mimo: amari 4UE deb: extends: .zmq + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests OpenSource/ variables: TESTBED: "zmq_deb" MARKERS: "smoke" @@ -377,6 +379,16 @@ test mode ru memcheck: - *txrx-lib - *retina-needs +test mode ru acc100: + extends: test mode ru + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests Plugin/ + variables: + TESTBED: "test_mode_acc100" + MARKERS: "test_mode_acc100" + KEYWORDS: "" + allow_failure: true + ################################################################################ # RF ################################################################################ @@ -591,4 +603,4 @@ retina runners: branch: main needs: - job: "retina setup" - artifacts: false \ No newline at end of file + artifacts: false diff --git a/.gitlab/ci/schedules.yml b/.gitlab/ci/schedules.yml index 9575b2e105..996f50b1ac 100644 --- a/.gitlab/ci/schedules.yml +++ b/.gitlab/ci/schedules.yml @@ -20,14 +20,14 @@ Rebaser: value: "false" raw: false -Nightly Build Unit Tests: - cron: "45 23 * * 0-5" +Nightly Build Unit Tests Plugin: + cron: "45 23 * * 1-5" cron_timezone: "Europe/Madrid" ref: refs/heads/dev variables: - variable_type: env_var key: CI_DESCRIPTION - value: "Nightly Build Unit Tests" + value: "Nightly Build Unit Tests Plugin" raw: false - variable_type: env_var key: NOTIFY_SLACK @@ -37,15 +37,19 @@ Nightly Build Unit Tests: key: SLACK_CHANNEL_OK value: "#ci_gnb" raw: false + - variable_type: env_var + key: PLUGIN_BRANCH + value: "main" + raw: false -Nightly E2E Tests: - cron: "30 22 * * 0-5" +Nightly E2E Tests Plugin: + cron: "30 22 * * 1-5" cron_timezone: "Europe/Madrid" ref: refs/heads/dev variables: - variable_type: env_var key: CI_DESCRIPTION - value: "Nightly E2E Tests" + value: "Nightly E2E Tests Plugin" raw: false - variable_type: env_var key: NOTIFY_SLACK @@ -55,6 +59,10 @@ Nightly E2E Tests: key: SLACK_CHANNEL_OK value: "#ci_gnb" raw: false + - variable_type: env_var + key: PLUGIN_BRANCH + value: "main" + raw: false Weekly: cron: "00 13 * * 6" @@ -73,6 +81,10 @@ Weekly: key: SLACK_CHANNEL_OK value: "#ci_gnb" raw: false + - variable_type: env_var + key: PLUGIN_BRANCH + value: "main" + raw: false Alternative OSs: cron: "00 10 * * 6" @@ -91,3 +103,43 @@ Alternative OSs: key: SLACK_CHANNEL_OK value: "#ci_gnb" raw: false + - variable_type: env_var + key: PLUGIN_BRANCH + value: "main" + raw: false + +Nightly Build Unit Tests OpenSource: + cron: "45 23 * * 1-5" + cron_timezone: "Europe/Madrid" + ref: refs/heads/dev + variables: + - variable_type: env_var + key: CI_DESCRIPTION + value: "Nightly Build Unit Tests OpenSource" + raw: false + - variable_type: env_var + key: NOTIFY_SLACK + value: "true" + raw: false + - variable_type: env_var + key: SLACK_CHANNEL_OK + value: "#ci_gnb" + raw: false + +Nightly E2E Tests OpenSource: + cron: "30 22 * * 1-5" + cron_timezone: "Europe/Madrid" + ref: refs/heads/dev + variables: + - variable_type: env_var + key: CI_DESCRIPTION + value: "Nightly E2E Tests OpenSource" + raw: false + - variable_type: env_var + key: NOTIFY_SLACK + value: "true" + raw: false + - variable_type: env_var + key: SLACK_CHANNEL_OK + value: "#ci_gnb" + raw: false diff --git a/.gitlab/run_custom_pipeline.py b/.gitlab/run_custom_pipeline.py index d51dd95c97..64b4bb4e4c 100755 --- a/.gitlab/run_custom_pipeline.py +++ b/.gitlab/run_custom_pipeline.py @@ -11,7 +11,7 @@ GITLAB_URL = "https://gitlab.com" NEEDS_REGEX = re.compile(r"Downloading artifacts for .* \((\d+)\)...", flags=re.MULTILINE) -VARIABLE_REGEX = re.compile(r"^(\w+)=(.*)?$", flags=re.MULTILINE) +VARIABLE_REGEX = re.compile(r"^(?:\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z \d{2}O )?(\w+)=(.*)?$", flags=re.MULTILINE) try: @@ -22,7 +22,7 @@ sys.exit(1) -def _parse_args() -> Tuple[str, str, str, str, int, bool]: +def _parse_args() -> Tuple[str, str, str, str, str, int, bool]: parser = argparse.ArgumentParser(description="Run a custom pipeline") parser.add_argument( "--token", @@ -44,6 +44,13 @@ def _parse_args() -> Tuple[str, str, str, str, int, bool]: type=str, help='Job name. Please use "" when the job name contains spaces', ) + parser.add_argument( + "--plugin-branch", + required=False, + type=str, + help="Remote branch for plugin repository. Set to '' to skip plugin repository.", + default="", + ) parser.add_argument( "--timeout", required=False, type=int, default=300, help="Search for job timeout (default: %(default)s)" ) @@ -51,7 +58,7 @@ def _parse_args() -> Tuple[str, str, str, str, int, bool]: "--dryrun", action="store_true", help="Search the job but skip pipeline creation (default: false)" ) args = parser.parse_args() - return args.token, args.project, args.branch, args.job.strip(), args.timeout, args.dryrun + return args.token, args.project, args.branch, args.plugin_branch, args.job.strip(), args.timeout, args.dryrun def _get_project(token: str, instance: str, project: str) -> Project: @@ -114,9 +121,10 @@ def main(): Entrypoint runner. """ try: - token, project_name, branch, job, timeout, dryrun = _parse_args() + token, project_name, branch, plugin_branch, job, timeout, dryrun = _parse_args() project = _get_project(token=token, instance=GITLAB_URL, project=project_name) variable_dict = _search_job_by_name(project=project, job_name=job, timeout=timeout) + variable_dict["PLUGIN_BRANCH"] = plugin_branch _create_pipeline(project=project, branch=branch, variables=variable_dict, dryrun=dryrun) except KeyboardInterrupt: print() From a6af65b830eb455fd490e1a7118aefa801d3969b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 15:48:50 +0100 Subject: [PATCH 134/227] ci: srsue compatible example --- tests/e2e/pyproject.toml | 3 ++- tests/e2e/tests/ping.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index 5db84f008e..dac25400cd 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -16,7 +16,6 @@ log_date_format = "%Y-%m-%d %H:%M:%S" log_format = "%(asctime)s [%(levelname)s] %(message)s" log_level = "INFO" markers = [ - "example", "smoke", "zmq", "zmq_single_ue", @@ -45,6 +44,8 @@ markers = [ "viavi", "viavi_manual", "viavi_debug", + "example", + "example_srsue", ] minversion = "6.0" python_files = [ diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index 85919a07a1..b7688d3cce 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -326,6 +326,36 @@ def test_example( ) +@mark.example_srsue +def test_example_srsue( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue: Tuple[UEStub, ...], + fivegc: FiveGCStub, + gnb: GNBStub, +): + """ + ZMQ Pings + """ + + _ping( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=(ue,), + gnb=gnb, + fivegc=fivegc, + band=3, + common_scs=15, + bandwidth=10, + sample_rate=11520000, + global_timing_advance=0, + time_alignment_calibration=0, + common_search_space_enable=True, + prach_config_index=1, + ue_stop_timeout=3, + ) + + @mark.parametrize( "band, common_scs, bandwidth, ciphering", ( @@ -545,6 +575,8 @@ def _ping( enable_security_mode: bool = False, ims_mode: str = "", enable_drx: bool = False, + common_search_space_enable: bool = False, + prach_config_index=-1, ): logging.info("Ping Test") @@ -562,6 +594,8 @@ def _ping( enable_security_mode=enable_security_mode, ims_mode=ims_mode, enable_drx=enable_drx, + common_search_space_enable=common_search_space_enable, + prach_config_index=prach_config_index, ) configure_artifacts( retina_data=retina_data, From 760ddd79db1b99ad8612746994e24958f274b369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 15:51:55 +0100 Subject: [PATCH 135/227] ci: remove allow failure in ric test --- .gitlab/ci/e2e.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 4be3ac9107..c3c95f3e96 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -300,7 +300,6 @@ ric: variables: TESTBED: "zmq_ric" MARKERS: "zmq_ric" - allow_failure: true ################################################################################ # TEST MODE From f5dee6faaa1f9c2e51fd4663046d4ecf4650b4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 21:25:06 +0100 Subject: [PATCH 136/227] ci: scheduled pipeline cron fixed --- .gitlab/ci/schedules.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/schedules.yml b/.gitlab/ci/schedules.yml index 996f50b1ac..ce0ce3d78e 100644 --- a/.gitlab/ci/schedules.yml +++ b/.gitlab/ci/schedules.yml @@ -109,7 +109,7 @@ Alternative OSs: raw: false Nightly Build Unit Tests OpenSource: - cron: "45 23 * * 1-5" + cron: "45 23 * * 0" cron_timezone: "Europe/Madrid" ref: refs/heads/dev variables: @@ -127,7 +127,7 @@ Nightly Build Unit Tests OpenSource: raw: false Nightly E2E Tests OpenSource: - cron: "30 22 * * 1-5" + cron: "30 22 * * 0" cron_timezone: "Europe/Madrid" ref: refs/heads/dev variables: From 395b30d9ea0d99f7fc4600a092713d1758ee4d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 22:56:10 +0100 Subject: [PATCH 137/227] ci: fix build with target --- .gitlab/ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index bb7d66df22..3ecdf10e6e 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -192,7 +192,7 @@ variables: git submodule add https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_SHELL_SSH_HOST}/${PLUGIN_REPO}.git ${PLUGIN_PATH} >/dev/null 2>&1 git submodule set-branch --branch ${PLUGIN_BRANCH} ${PLUGIN_PATH} >/dev/null 2>&1 fi - - build_srsgnb ${SRS_TARGET} + - build_srsgnb "${SRS_TARGET}" - launch_tests timeout: 6h From b8eda5bbc4d5a9ba6804f9dec9647d75cf7c54b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 23:05:19 +0100 Subject: [PATCH 138/227] ci: update retina due to config change --- .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/test_mode/config_ue.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index cd7e609146..78f1ac94c7 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.58.2 +RETINA_VERSION=0.58.4 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/tests/test_mode/config_ue.yml b/tests/e2e/tests/test_mode/config_ue.yml index dbd63c0a1c..90f7e2dd03 100644 --- a/tests/e2e/tests/test_mode/config_ue.yml +++ b/tests/e2e/tests/test_mode/config_ue.yml @@ -35,7 +35,7 @@ cell_cfg: sr_period_ms: 10 min_k1: 2 f0_or_f1_nof_cell_res_sr: 6 - f2_nof_cell_res_csi: 6 + f2_or_f3_or_f4_nof_cell_res_csi: 6 nof_cell_harq_pucch_res_sets: 1 f1_nof_cyclic_shifts: 6 csi: From 80c2f9b3f6adae25c01502b1a646e8937e320922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 23:05:42 +0100 Subject: [PATCH 139/227] configs: update param after name change --- configs/cell_cfg_max_128_ues.yml | 2 +- configs/cell_cfg_max_256_ues.yml | 2 +- configs/cell_cfg_max_32_ues.yml | 2 +- configs/cell_cfg_max_512_ues.yml | 2 +- configs/cell_cfg_max_64_ues.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configs/cell_cfg_max_128_ues.yml b/configs/cell_cfg_max_128_ues.yml index 9cd24c5b24..fdf7dffa6a 100644 --- a/configs/cell_cfg_max_128_ues.yml +++ b/configs/cell_cfg_max_128_ues.yml @@ -12,7 +12,7 @@ cell_cfg: pucch: sr_period_ms: 20 # This can be set either 20 or 40 ms. f0_or_f1_nof_cell_res_sr: 50 - f2_nof_cell_res_csi: 50 + f2_or_f3_or_f4_nof_cell_res_csi: 50 csi: csi_rs_period: 40 # This can be set either 20 or 40 ms. ul_common: diff --git a/configs/cell_cfg_max_256_ues.yml b/configs/cell_cfg_max_256_ues.yml index 5441a8d6f3..f70bfc3215 100644 --- a/configs/cell_cfg_max_256_ues.yml +++ b/configs/cell_cfg_max_256_ues.yml @@ -14,7 +14,7 @@ cell_cfg: nof_ue_res_harq_per_set: 8 nof_cell_harq_pucch_res_sets: 2 # Increase this if UEs are not scheduled PDSCH due to PUCCH resources starvation. f0_or_f1_nof_cell_res_sr: 50 - f2_nof_cell_res_csi: 50 + f2_or_f3_or_f4_nof_cell_res_csi: 50 csi: csi_rs_period: 40 # This can be set either 20 or 40 ms. ul_common: diff --git a/configs/cell_cfg_max_32_ues.yml b/configs/cell_cfg_max_32_ues.yml index 62a808ef86..1989d236ab 100644 --- a/configs/cell_cfg_max_32_ues.yml +++ b/configs/cell_cfg_max_32_ues.yml @@ -10,7 +10,7 @@ cell_cfg: pucch: sr_period_ms: 20 # This can be set either 20 or 40 ms. f0_or_f1_nof_cell_res_sr: 15 - f2_nof_cell_res_csi: 15 + f2_or_f3_or_f4_nof_cell_res_csi: 15 csi: csi_rs_period: 40 # This can be set either 20 or 40 ms. ul_common: diff --git a/configs/cell_cfg_max_512_ues.yml b/configs/cell_cfg_max_512_ues.yml index 71afd39b89..044d22eae9 100644 --- a/configs/cell_cfg_max_512_ues.yml +++ b/configs/cell_cfg_max_512_ues.yml @@ -15,7 +15,7 @@ cell_cfg: nof_ue_res_harq_per_set: 8 nof_cell_harq_pucch_res_sets: 2 # Increase this if UEs are not scheduled PDSCH due to PUCCH resources starvation. f0_or_f1_nof_cell_res_sr: 80 - f2_nof_cell_res_csi: 80 + f2_or_f3_or_f4_nof_cell_res_csi: 80 csi: csi_rs_period: 40 # This can be set to 20 only with TDD 6D-3U. ul_common: diff --git a/configs/cell_cfg_max_64_ues.yml b/configs/cell_cfg_max_64_ues.yml index 8c9e472f15..c8ae93d490 100644 --- a/configs/cell_cfg_max_64_ues.yml +++ b/configs/cell_cfg_max_64_ues.yml @@ -10,7 +10,7 @@ cell_cfg: pucch: sr_period_ms: 20 # This can be set either 20 or 40 ms. f0_or_f1_nof_cell_res_sr: 31 - f2_nof_cell_res_csi: 31 + f2_or_f3_or_f4_nof_cell_res_csi: 31 csi: csi_rs_period: 40 # This can be set either 20 or 40 ms. ul_common: From 7c912b3f517d9a63cfff52c1803b968b29562155 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 12 Dec 2024 19:52:23 +0100 Subject: [PATCH 140/227] sched: update pusch pw ctrl state in fallback sched Signed-off-by: Carlo Galiotto --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 567fb7cc38..f776fc9402 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -1096,6 +1096,9 @@ ue_fallback_scheduler::schedule_ul_srb(ue& pusch_alloc.ul_res_grid.fill( grant_info{cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.scs, pusch_td.symbols, ue_grant_crbs}); + // Update the number of PRBs used in the PUSCH allocation. + u.get_pcell().get_ul_power_controller().update_pusch_pw_ctrl_state(pusch_alloc.slot, ue_grant_crbs.length()); + // Update DRX controller state. u.drx_controller().on_new_pdcch_alloc(pdcch_alloc.slot); From 91b5160e8821a84f135f913d69669fc7f470e3b5 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 22 Nov 2024 18:06:51 +0100 Subject: [PATCH 141/227] phy: optimize LLR combine for general purpose phy: review LLR related phy: add NEON sum phy: review LLR related phy: fix LLR --- .../srsran/phy/upper/log_likelihood_ratio.h | 51 ++--- .../short/short_block_detector_impl.cpp | 33 +++- lib/phy/upper/log_likelihood_ratio.cpp | 182 ++++++++++++++++++ .../phy/upper/log_likelihood_ratio_test.cpp | 28 ++- 4 files changed, 248 insertions(+), 46 deletions(-) diff --git a/include/srsran/phy/upper/log_likelihood_ratio.h b/include/srsran/phy/upper/log_likelihood_ratio.h index 4cd9f56f92..6a25b6d667 100644 --- a/include/srsran/phy/upper/log_likelihood_ratio.h +++ b/include/srsran/phy/upper/log_likelihood_ratio.h @@ -206,9 +206,26 @@ class log_likelihood_ratio template static int norm_squared(const T& x); - // Documentation at definition (see below). - template - static V dot_prod(const T& x, const U& y, V init); + /// \brief Dot product of a sequence of LLRs and a sequence of signs expressed as +1 or -1. + /// + /// Computes the dot product (a.k.a. inner product or scalar product) of the first input sequence and the signs + /// (+1, -1 or 0) of the second input sequence. + /// + /// \param[in] x A sequence of (possibly constant) log-likelihood ratios. + /// \param[in] y Sequence of 8-bit integers. + /// \return The dot product between the two sequences, i.e. \f$ x \cdot y + = \sum_i x_i \cdot + /// \operatorname{sign}(y_i)\f$. + /// \remark The two input spans must have the same length. + /// \remark This function treats the LLRs as integer values, thus neither saturation nor promotion applies. + static int32_t dot_prod_sign(span x, span y); + + /// \brief Performs a saturated sum of the LLRs from two sequences of log-likelihood ratios, \c x and \c y, and it + /// stores the result in \c out. + /// \param[out] out Result. + /// \param[in ] x First sequence of log-likelihood ratios. + /// \param[in ] y Second sequence of log-likelihood ratios. + static void + sum(span out, span x, span y); private: /// Actual LLR value. @@ -258,34 +275,6 @@ struct is_llr_span_compatible -V log_likelihood_ratio::dot_prod(const T& x, const U& y, V init) -{ - static_assert(detail::is_llr_span_compatible::value, "Template type is not compatible with a span of LLRs"); - static_assert(srsvec::is_arithmetic_span_compatible::value, - "Template type is not compatible with a span of arithmetics"); - srsran_assert(x.size() == y.size(), "Input spans must have identical sizes: '{}' vs '{}'", x.size(), y.size()); - return std::inner_product( - x.begin(), x.end(), y.begin(), init, std::plus(), [](log_likelihood_ratio a, log_likelihood_ratio b) { - return a.to_int() * b.to_int(); - }); -} - /// \brief Clamps the input values between a lower and higher bound. /// /// The equivalent code is: diff --git a/lib/phy/upper/channel_coding/short/short_block_detector_impl.cpp b/lib/phy/upper/channel_coding/short/short_block_detector_impl.cpp index 821ece6874..75433b566c 100644 --- a/lib/phy/upper/channel_coding/short/short_block_detector_impl.cpp +++ b/lib/phy/upper/channel_coding/short/short_block_detector_impl.cpp @@ -12,7 +12,13 @@ #include "short_block_encoder_impl.h" #include "srsran/adt/static_vector.h" #include "srsran/srsvec/bit.h" +#include "srsran/srsvec/copy.h" #include "srsran/srsvec/dot_prod.h" +#include "srsran/srsvec/fill.h" + +#if __AVX2__ +#include "../ldpc/avx2_support.h" +#endif // __AVX2__ using namespace srsran; @@ -112,7 +118,7 @@ double short_block_detector_impl::detect_3_11(span output, span max_metric) { max_metric = metric_abs; @@ -135,12 +141,27 @@ double short_block_detector_impl::detect_3_11(span output, span output, span input) { - unsigned output_size = output.size(); - unsigned input_size = input.size(); + // Copy the first samples in common. + unsigned nof_copy = std::min(input.size(), output.size()); + srsvec::copy(output.first(nof_copy), input.first(nof_copy)); + + // Pad the output with zeros if longer than the input. + if (input.size() <= output.size()) { + srsvec::fill(output.last(output.size() - nof_copy), 0); + return; + } + + // Combine the rest of LLRs in blocks. + input = input.last(input.size() - output.size()); + while (!input.empty()) { + // Determine the block size. + unsigned block_size = std::min(output.size(), input.size()); + + // Combine block of LLR. + log_likelihood_ratio::sum(output.first(block_size), output.first(block_size), input.first(block_size)); - std::fill(output.begin(), output.end(), 0); - for (unsigned idx = 0; idx != input_size; ++idx) { - output[idx % output_size] += input[idx]; + // Advance input. + input = input.last(input.size() - block_size); } }; diff --git a/lib/phy/upper/log_likelihood_ratio.cpp b/lib/phy/upper/log_likelihood_ratio.cpp index 6536e3df35..05b3e4850f 100644 --- a/lib/phy/upper/log_likelihood_ratio.cpp +++ b/lib/phy/upper/log_likelihood_ratio.cpp @@ -10,6 +10,7 @@ #include "srsran/phy/upper/log_likelihood_ratio.h" #include "srsran/srsvec/compare.h" +#include "srsran/srsvec/copy.h" #include #include @@ -325,3 +326,184 @@ bool srsran::hard_decision(bit_buffer& hard_bits, span(result); +} + +#endif // __AVX2__ + +int32_t log_likelihood_ratio::dot_prod_sign(span x, span y) +{ + srsran_assert(x.size() == y.size(), "Sizes must be equal."); + +#ifdef __AVX2__ + // Optimized calculation in AVX2 for 32 values. + if (x.size() == 32) { + __m256i x_epi8 = _mm256_loadu_si256(reinterpret_cast(x.data())); + __m256i y_epi8 = _mm256_loadu_si256(reinterpret_cast(y.data())); + return dot_prod_sign_avx2(x_epi8, y_epi8); + } +#endif // __AVX2__ + + int32_t ret = + std::inner_product(x.begin(), x.end(), y.begin(), 0, std::plus(), [](log_likelihood_ratio a, int8_t b) { + return a.to_int() * std::copysign(1, b); + }); + + return ret; +} + +#ifdef __AVX2__ +static inline __m256i avx2_sum_llr(__m256i in0_epi8, __m256i in1_epi8) +{ + __m256i LLR_MAX_epi8 = _mm256_set1_epi8(static_cast(LLR_MAX)); + __m256i LLR_MIN_epi8 = _mm256_set1_epi8(static_cast(LLR_MIN)); + + __m256i result = _mm256_adds_epi8(in0_epi8, in1_epi8); + + __m256i mask_epi8 = _mm256_cmpgt_epi8(result, LLR_MAX_epi8); + result = _mm256_blendv_epi8(result, LLR_MAX_epi8, mask_epi8); + + mask_epi8 = _mm256_cmpgt_epi8(LLR_MIN_epi8, result); + return _mm256_blendv_epi8(result, LLR_MIN_epi8, mask_epi8); +} +#endif // __AVX2__ + +#ifdef __ARM_NEON +static inline int8x16_t neon_sum_llr(int8x16_t in0_s8, int8x16_t in1_s8) +{ + const int8x16_t LLR_MAX_s8 = vdupq_n_s8(static_cast(LLR_MAX)); + const int8x16_t LLR_MIN_s8 = vdupq_n_s8(static_cast(LLR_MIN)); + + int8x16_t result = vqaddq_s8(in0_s8, in1_s8); + + uint8x16_t mask_s8 = vcgtq_s8(result, LLR_MAX_s8); + result = vbslq_s8(mask_s8, LLR_MAX_s8, result); + mask_s8 = vcgtq_s8(LLR_MIN_s8, result); + result = vbslq_s8(mask_s8, LLR_MIN_s8, result); + + return result; +} +#endif // __ARM_NEON + +void log_likelihood_ratio::sum(span out, + span in0, + span in1) +{ + srsran_assert(out.size() == in0.size(), "All sizes must be equal."); + srsran_assert(out.size() == in1.size(), "All sizes must be equal."); + +#if defined(__AVX2__) + unsigned index = 0; + + static constexpr unsigned AVX2_SIZE_BYTE = 32; + __m256i* avx_out = reinterpret_cast<__m256i*>(out.data()); + const __m256i* avx_in0 = reinterpret_cast(in0.data()); + const __m256i* avx_in1 = reinterpret_cast(in1.data()); + + for (unsigned index_end = (out.size() / AVX2_SIZE_BYTE); index != index_end; ++index) { + __m256i in0_epi8 = _mm256_loadu_si256(avx_in0++); + __m256i in1_epi8 = _mm256_loadu_si256(avx_in1++); + _mm256_storeu_si256(avx_out++, avx2_sum_llr(in0_epi8, in1_epi8)); + } + index *= AVX2_SIZE_BYTE; + + // Calculate the remainder of bits. + unsigned remainder = out.size() - index; + + // Copy the end of the input bits in vectors of AVX register size. + std::array in0_remainder; + std::array in1_remainder; + srsvec::copy(span(in0_remainder).first(remainder), in0.last(remainder)); + srsvec::copy(span(in1_remainder).first(remainder), in1.last(remainder)); + + // Load the remainder bits in AVX registers. + __m256i in0_epi8 = _mm256_loadu_si256(reinterpret_cast(in0_remainder.data())); + __m256i in1_epi8 = _mm256_loadu_si256(reinterpret_cast(in1_remainder.data())); + + // Process last AVX block and store it in a vector of AVX register size. + std::array out_remainder; + _mm256_storeu_si256(reinterpret_cast<__m256i*>(out_remainder.data()), avx2_sum_llr(in0_epi8, in1_epi8)); + + // Copy the last bits. + srsvec::copy(out.last(remainder), span(out_remainder).first(remainder)); +#elif defined(__ARM_NEON) + unsigned index = 0; + unsigned out_size = out.size(); + static constexpr unsigned NEON_SIZE_BYTE = 16; + + // Process batches of 32 values. + for (unsigned index_end = (out_size / 32) * 32; index != index_end; index += 32) { + int8x16x2_t in0_s8 = vld1q_s8_x2(reinterpret_cast(&in0[index])); + int8x16x2_t in1_s8 = vld1q_s8_x2(reinterpret_cast(&in1[index])); + + int8x16x2_t result; + result.val[0] = neon_sum_llr(in0_s8.val[0], in1_s8.val[0]); + result.val[1] = neon_sum_llr(in0_s8.val[1], in1_s8.val[1]); + + vst1q_s8_x2(reinterpret_cast(&out[index]), result); + } + + // Process batch of 16 values. + if (out_size & 0x10) { + int8x16_t in0_s8 = vld1q_s8(reinterpret_cast(&in0[index])); + int8x16_t in1_s8 = vld1q_s8(reinterpret_cast(&in1[index])); + int8x16_t result = neon_sum_llr(in0_s8, in1_s8); + + vst1q_s8(reinterpret_cast(&out[index]), result); + index += 16; + } + + // Calculate the remainder of bits. + unsigned remainder = out.size() - index; + + // Copy the end of the input bits in vectors of AVX register size. + std::array in0_remainder; + std::array in1_remainder; + srsvec::copy(span(in0_remainder).first(remainder), in0.last(remainder)); + srsvec::copy(span(in1_remainder).first(remainder), in1.last(remainder)); + + // Load the remainder bits in NEON registers. + int8x16_t in0_s8 = vld1q_s8(reinterpret_cast(in0_remainder.data())); + int8x16_t in1_s8 = vld1q_s8(reinterpret_cast(in1_remainder.data())); + + // Process last NEON block and store it in a vector of NEON register size. + std::array out_remainder; + vst1q_s8(reinterpret_cast(out_remainder.data()), neon_sum_llr(in0_s8, in1_s8)); + + // Copy the last bits. + srsvec::copy(out.last(remainder), span(out_remainder).first(remainder)); +#else + std::transform( + in0.begin(), in0.end(), in1.begin(), out.begin(), [](log_likelihood_ratio left, log_likelihood_ratio right) { + return left + right; + }); +#endif +} \ No newline at end of file diff --git a/tests/unittests/phy/upper/log_likelihood_ratio_test.cpp b/tests/unittests/phy/upper/log_likelihood_ratio_test.cpp index 2d7f5035bc..0cc3babcf1 100644 --- a/tests/unittests/phy/upper/log_likelihood_ratio_test.cpp +++ b/tests/unittests/phy/upper/log_likelihood_ratio_test.cpp @@ -70,11 +70,8 @@ int main() "norm_sqr_llr does not propagate type with const values."); TESTASSERT_EQ(16, log_likelihood_ratio::norm_squared(llr_sequence), "norm_sqr_llr not working."); - std::array rhs = {1, 1, 1, 1}; - TESTASSERT(typeid(float) == typeid(log_likelihood_ratio::dot_prod(llr_sequence, rhs, 1.1F)), - "dot_prod_llr does not propagate type."); - TESTASSERT(std::abs(1.1F - log_likelihood_ratio::dot_prod(llr_sequence, rhs, 1.1F)) < .00001, - "dot_prod_llr not working."); + std::array rhs = {-1, -1, 1, 1}; + TESTASSERT_EQ(0, log_likelihood_ratio::dot_prod_sign(llr_sequence, rhs), "dot_prod_llr not working."); fmt::memory_buffer buf; fmt::format_to(buf, "{}", log_likelihood_ratio(1)); @@ -83,13 +80,12 @@ int main() log_likelihood_ratio low = -32; log_likelihood_ratio high = 32; std::mt19937 rgen; - std::uniform_int_distribution llr_clamp_dist(log_likelihood_ratio::min().to_int(), - log_likelihood_ratio::max().to_int()); + std::uniform_int_distribution llr_dist(log_likelihood_ratio::min().to_int(), + log_likelihood_ratio::max().to_int()); std::array clamp_in_data; std::array clamp_expected_data; std::array clamp_out_data; - std::generate( - clamp_in_data.begin(), clamp_in_data.end(), [&llr_clamp_dist, &rgen]() { return llr_clamp_dist(rgen); }); + std::generate(clamp_in_data.begin(), clamp_in_data.end(), [&llr_dist, &rgen]() { return llr_dist(rgen); }); std::transform(clamp_in_data.begin(), clamp_in_data.end(), clamp_expected_data.begin(), @@ -98,5 +94,19 @@ int main() TESTASSERT_EQ(span(clamp_expected_data), span(clamp_out_data)); + std::array sum_x; + std::array sum_y; + std::array sum_out; + std::generate(sum_x.begin(), sum_x.end(), [&llr_dist, &rgen]() { return llr_dist(rgen); }); + std::generate(sum_y.begin(), sum_y.end(), [&llr_dist, &rgen]() { return llr_dist(rgen); }); + std::array sum_expected; + std::transform(sum_x.begin(), + sum_x.end(), + sum_y.begin(), + sum_expected.begin(), + [](log_likelihood_ratio x, log_likelihood_ratio y) { return x + y; }); + log_likelihood_ratio::sum(sum_out, sum_x, sum_y); + TESTASSERT_EQ(span(sum_expected), span(sum_out)); + return 0; } From 0ece7edfe5c21ee84e64ece96a7ba6f94c4cbab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Fri, 13 Dec 2024 11:15:06 +0100 Subject: [PATCH 142/227] ci: create standalone build job for ru dummy tests --- .gitlab/ci/build.yml | 27 +++++++++++++++++++++++++++ .gitlab/ci/e2e.yml | 2 +- .gitlab/ci/e2e/.env | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 3ecdf10e6e..946ac3a1cf 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -69,6 +69,7 @@ variables: echo "MAKE_ARGS=${MAKE_ARGS}" echo "UHD_VERSION=${UHD_VERSION}" echo "DPDK_VERSION=${DPDK_VERSION}" + echo "SRS_TARGET=${SRS_TARGET}" echo "PLUGIN_BRANCH=${PLUGIN_BRANCH}" build_srsgnb() { @@ -1660,6 +1661,32 @@ basic memcheck: <<: *build_artifacts expire_in: 3 days +basic ru dummy: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests/ + retry: 2 + interruptible: false + variables: + SRS_TARGET: gnb + OS: ubuntu-24.04 + COMPILER: gcc + CMAKE_BUILD_TYPE: Release + TEST_MODE: none + ENABLE_UHD: "False" + ENABLE_ZEROMQ: "False" + ENABLE_DPDK: "True" + DPDK_VERSION: "23.11.1_avx512" + MARCH: x86-64-v4 + FORCE_DEBUG_INFO: "True" + ASSERT_LEVEL: AUTO + INFRASTRUCTURE_TAG: amd64-avx2-avx512 + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts + expire_in: 3 days + basic avx512 dpdk: extends: .build_and_unit rules: diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index c3c95f3e96..2924ca06f4 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -343,7 +343,7 @@ test mode ru: E2E_LOG_LEVEL: "warning" RETINA_LAUNCHER_ARGS: "--retina-pod-timeout 900" needs: - - job: "basic avx512 dpdk" + - job: "basic ru dummy" artifacts: true - *txrx-lib - *retina-needs diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 78f1ac94c7..d296fba376 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.58.4 +RETINA_VERSION=0.58.5 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From 848d66ec9b03011439b584faeea768c0e4849167 Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 12 Dec 2024 17:41:13 +0100 Subject: [PATCH 143/227] du-high: fix du-high benchmark --- .../benchmarks/du_high/du_high_benchmark.cpp | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 7ab33a1945..68bac3bf26 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -68,7 +68,7 @@ struct bench_params { /// Setting this value to 0 will disable DL Tx. /// If the air interface cannot keep up with the DL F1-U PDU rate, the F1-U will be throttled, to avoid depleting /// the buffer pool. - unsigned dl_bytes_per_slot = 1500; + unsigned dl_bytes_per_slot = 9000; /// \brief Set size of the UL Buffer status report to push for UL Tx. Setting this value to 0 will disable UL Tx. unsigned ul_bsr_bytes = 0; /// \brief Maximum number of RBs per UE DL grant per slot. @@ -550,7 +550,7 @@ class du_high_bench static constexpr unsigned PDCP_MAX_HDR_LEN = 3; public: - du_high_bench(unsigned dl_buffer_state_bytes_, + du_high_bench(unsigned dl_bytes_per_slot_, unsigned ul_bsr_bytes_, unsigned max_nof_rbs_per_dl_grant, units::bytes f1u_pdu_size_, @@ -559,7 +559,7 @@ class du_high_bench bool sched_tracing_enabled, const cell_config_builder_params& builder_params = {}) : params(builder_params), - f1u_dl_pdu_bytes_per_slot(dl_buffer_state_bytes_), + f1u_dl_pdu_bytes_per_slot(dl_bytes_per_slot_), f1u_pdu_size(f1u_pdu_size_), workers(test_helpers::create_multi_threaded_du_high_executor_mapper({1, true, du_cell_cores})), ul_bsr_bytes(ul_bsr_bytes_) @@ -795,7 +795,7 @@ class du_high_bench static std::array pdcp_sn_list{0}; const unsigned nof_dl_pdus_per_slot = divide_ceil(f1u_dl_pdu_bytes_per_slot, this->f1u_pdu_size.value()); const unsigned last_dl_pdu_size = - std::max(PDCP_MAX_HDR_LEN, f1u_dl_pdu_bytes_per_slot % this->f1u_pdu_size.value()); + std::max(PDCP_MAX_HDR_LEN, ((f1u_dl_pdu_bytes_per_slot - 1) % this->f1u_pdu_size.value()) + 1); // Forward DL buffer occupancy updates to all bearers in a Round-robin fashion. for (unsigned i = 0; i != nof_dl_pdus_per_slot; ++i) { @@ -825,6 +825,7 @@ class du_high_bench } } f1u_dl_total_bytes.fetch_add(pdcp_pdu.length(), std::memory_order_relaxed); + test_logger.debug("Pushing PDCP PDU of size={}", pdcp_pdu.length()); du_notif->on_new_pdu(nru_dl_message{.t_pdu = std::move(pdcp_pdu)}); } })) { @@ -1136,21 +1137,22 @@ static cell_config_builder_params generate_custom_cell_config_builder_params(dup void benchmark_dl_ul_only_rlc_um(benchmarker& bm, unsigned nof_ues, duplex_mode dplx_mode, - unsigned dl_buffer_state_bytes, + unsigned dl_bytes_per_slot, unsigned ul_bsr_bytes, unsigned max_nof_rbs_per_dl_grant, units::bytes dl_pdu_size, span du_cell_cores, bool sched_tracing_enabled, - const policy_scheduler_expert_config& strategy_cfg) + const policy_scheduler_expert_config& strategy_cfg, + unsigned nof_repetitions) { auto benchname = fmt::format("{}{}{}, {} UEs, RLC UM", - dl_buffer_state_bytes > 0 ? "DL" : "", - std::min(dl_buffer_state_bytes, ul_bsr_bytes) > 0 ? "+" : "", + dl_bytes_per_slot > 0 ? "DL" : "", + std::min(dl_bytes_per_slot, ul_bsr_bytes) > 0 ? "+" : "", ul_bsr_bytes > 0 ? "UL" : "", nof_ues); test_delimit_logger test_delim(benchname.c_str()); - du_high_bench bench{dl_buffer_state_bytes, + du_high_bench bench{dl_bytes_per_slot, ul_bsr_bytes, max_nof_rbs_per_dl_grant, dl_pdu_size, @@ -1199,15 +1201,28 @@ void benchmark_dl_ul_only_rlc_um(benchmarker& bm, bench.sim_phy.metrics.ul_mbps(scs)); // Some sanity checks to avoid regressions. - if (dl_buffer_state_bytes > 0) { - report_fatal_error_if_not(pdschs_per_slot > 0.5, "The scheduler is not scheduling enough DL grants"); + if (dl_bytes_per_slot > 0) { + if (nof_repetitions > 1000) { + // Only do these checks if a non-negligible number of slots was simulated. + const unsigned actual_dl_bytes_per_dl_slot = + bench.sim_phy.metrics.nof_dl_bytes / (double)bench.sim_phy.metrics.slot_dl_count; + if (actual_dl_bytes_per_dl_slot < dl_bytes_per_slot) { + // DL saturation scenario. + report_fatal_error_if_not(pdschs_per_slot > 0.99, "The scheduler is not scheduling enough DL grants"); + } else { + report_fatal_error_if_not(pdschs_per_slot > 0.05, "The scheduler is not scheduling enough DL grants"); + } + } } else { - report_fatal_error_if_not(pdschs_per_slot < 0.1, "The scheduler is not scheduling enough DL grants"); + report_fatal_error_if_not(pdschs_per_slot < 0.01, "The scheduler is not scheduling enough DL grants"); } if (ul_bsr_bytes > 0) { - report_fatal_error_if_not(puschs_per_slot > 0.1, "The scheduler is not scheduling enough UL grants"); + if (nof_repetitions > 1000) { + // Only do these checks if a non-negligible number of slots was simulated. + report_fatal_error_if_not(puschs_per_slot > 0.05, "The scheduler is not scheduling enough UL grants"); + } } else { - report_fatal_error_if_not(puschs_per_slot < 0.1, "The scheduler is scheduling too many UL grants"); + report_fatal_error_if_not(puschs_per_slot < 0.01, "The scheduler is scheduling too many UL grants"); } } @@ -1300,7 +1315,8 @@ int main(int argc, char** argv) params.pdu_size, params.du_cell_cores, params.sched_trace_enabled, - params.strategy_cfg); + params.strategy_cfg, + params.nof_repetitions); } if (not tracing_filename.empty()) { From d8d7ceb467a0237c65f14b1660adf3c9cd15bd97 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 19:36:50 +0100 Subject: [PATCH 144/227] sched: transition to fallback during UE reconfiguration --- lib/scheduler/slicing/slice_scheduler.cpp | 1 - lib/scheduler/ue_context/ue.cpp | 26 ++++++++++++---- lib/scheduler/ue_context/ue.h | 13 ++++++++ .../ue_scheduling/ue_event_manager.cpp | 10 +++---- .../ue_scheduling/ue_fallback_scheduler.cpp | 30 +++++++++++-------- .../ue_scheduling/ue_configuration_test.cpp | 26 ++++++++++++++-- 6 files changed, 81 insertions(+), 25 deletions(-) diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index 52c0d5b181..bdb3643d61 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -132,7 +132,6 @@ void slice_scheduler::reconf_ue(du_ue_index_t ue_idx) if (u == nullptr) { return; } - add_impl(*u); // Check if any UE HARQs need to be cancelled in case the UE got removed from the respective slice. ue_cell& ue_cell = *u->find_cell(cell_cfg.cell_index); diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 08904e7cba..584c5f72ac 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -32,7 +32,7 @@ ue::ue(const ue_creation_command& cmd) : logger) { // Apply configuration. - handle_reconfiguration_request(ue_reconf_command{cmd.cfg}); + set_config(cmd.cfg); for (auto& cell : ue_du_cells) { if (cell != nullptr) { @@ -77,16 +77,32 @@ void ue::release_resources() void ue::handle_reconfiguration_request(const ue_reconf_command& cmd) { - srsran_assert(cmd.cfg.nof_cells() > 0, "Creation of a UE requires at least PCell configuration."); - ue_ded_cfg = &cmd.cfg; + // UE enters fallback mode when a Reconfiguration takes place. + reconf_ongoing = true; + get_pcell().set_fallback_state(true); + + // Update UE config. + set_config(cmd.cfg); +} + +void ue::handle_config_applied() +{ + get_pcell().set_fallback_state(false); + reconf_ongoing = false; +} + +void ue::set_config(const ue_configuration& new_cfg) +{ + srsran_assert(new_cfg.nof_cells() > 0, "Creation of a UE requires at least PCell configuration."); + ue_ded_cfg = &new_cfg; // Configure Logical Channels. dl_lc_ch_mgr.configure(ue_ded_cfg->logical_channels()); ul_lc_ch_mgr.configure(ue_ded_cfg->logical_channels()); // DRX config. - if (cmd.cfg.drx_cfg().has_value()) { - drx.reconfigure(cmd.cfg.drx_cfg()); + if (ue_ded_cfg->drx_cfg().has_value()) { + drx.reconfigure(ue_ded_cfg->drx_cfg()); } // Cell configuration. diff --git a/lib/scheduler/ue_context/ue.h b/lib/scheduler/ue_context/ue.h index 6da64d9e97..f7c73d34c4 100644 --- a/lib/scheduler/ue_context/ue.h +++ b/lib/scheduler/ue_context/ue.h @@ -110,8 +110,15 @@ class ue dl_lc_ch_mgr.handle_mac_ce_indication({.ce_lcid = msg.ce_lcid, .ce_payload = dummy_ce_payload{}}); } + /// Called when a new UE configuration is passed to the scheduler, as part of the RRC Reconfiguration procedure. void handle_reconfiguration_request(const ue_reconf_command& params); + /// Called when the UE confirms that it applied the new configuration. + void handle_config_applied(); + + /// Determines whether a UE reconfiguration is being processed. + bool is_reconfig_ongoing() const { return reconf_ongoing; } + /// \brief Handles DL Buffer State indication. void handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& msg); @@ -168,6 +175,9 @@ class ue unsigned build_dl_fallback_transport_block_info(dl_msg_tb_info& tb_info, unsigned tb_size_bytes); private: + /// Update UE configuration. + void set_config(const ue_configuration& new_cfg); + // Expert config parameters used for UE scheduler. const scheduler_ue_expert_config& expert_cfg; // Cell configuration. This is common to all UEs within the same cell. @@ -194,6 +204,9 @@ class ue slot_point last_sl_tx; + /// Whether a UE reconfiguration is taking place. + bool reconf_ongoing = false; + /// UE Timing Advance Manager. ta_manager ta_mgr; diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index 35f9f2c7a6..3b3b9f114d 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -350,14 +350,14 @@ void ue_event_manager::handle_ue_config_applied(du_ue_index_t ue_idx) ue& u = ue_db[ue_idx]; auto& pcell = du_cells[u.get_pcell().cell_index]; - // Log UE config applied event. - pcell.ev_logger->enqueue(scheduler_event_logger::ue_cfg_applied_event{ue_idx, u.crnti}); - - // Remove UE from fallback mode. - u.get_pcell().set_fallback_state(false); + // Confirm that UE applied new config. + u.handle_config_applied(); // Add UE to slice scheduler, once it leaves fallback mode. pcell.slice_sched->config_applied(ue_idx); + + // Log UE config applied event. + pcell.ev_logger->enqueue(scheduler_event_logger::ue_cfg_applied_event{ue_idx, u.crnti}); }; if (not common_events.try_push(common_event_t{ue_idx, handle_ue_config_applied_impl})) { diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index f776fc9402..da9e42d677 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -417,7 +417,8 @@ allocate_ue_fallback_pucch(ue& u, span k1_values, slot_point pdsch_slot, slot_point min_ack_slot, - bool common_and_ded_alloc) + bool common_alloc, + bool ded_alloc) { const unsigned pdsch_delay = pdsch_slot - res_alloc.slot_tx(); @@ -434,11 +435,18 @@ allocate_ue_fallback_pucch(ue& u, } last_valid_k1 = k1_candidate; - std::optional pucch_res_indicator = - common_and_ded_alloc - ? pucch_alloc.alloc_common_and_ded_harq_res( - res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate, pdcch_info) - : pucch_alloc.alloc_common_pucch_harq_ack_ue(res_alloc, u.crnti, pdsch_delay, k1_candidate, pdcch_info); + std::optional pucch_res_indicator; + if (common_alloc and ded_alloc) { + pucch_res_indicator = pucch_alloc.alloc_common_and_ded_harq_res( + res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate, pdcch_info); + } else if (common_alloc) { + pucch_res_indicator = + pucch_alloc.alloc_common_pucch_harq_ack_ue(res_alloc, u.crnti, pdsch_delay, k1_candidate, pdcch_info); + } else { + srsran_assert(ded_alloc, "Invalid params passed to this function"); + pucch_res_indicator = + pucch_alloc.alloc_ded_pucch_harq_ack_ue(res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate); + } if (pucch_res_indicator.has_value()) { return std::make_pair(*pucch_res_indicator, k1_candidate); } @@ -585,7 +593,8 @@ ue_fallback_scheduler::alloc_grant(ue& u, // configuration, the UE is provided by higher layers with one or more PUCCH resources [...]"). // - If the UE object in the scheduler doesn't have a complete configuration (i.e., when SRB0 is for RRC Reject), // don't use the PUCCH ded. resources. - const bool use_common_and_ded_res = u.ue_cfg_dedicated()->is_ue_cfg_complete() and is_retx; + const bool use_common = not u.is_reconfig_ongoing(); + const bool use_dedicated = u.is_reconfig_ongoing() or (u.ue_cfg_dedicated()->is_ue_cfg_complete() and is_retx); auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, res_alloc, pucch_alloc, @@ -593,7 +602,8 @@ ue_fallback_scheduler::alloc_grant(ue& u, dci_1_0_k1_values, pdsch_alloc.slot, most_recent_ack_slot, - use_common_and_ded_res); + use_common, + use_dedicated); if (not pucch_res_indicator.has_value()) { if (chosen_k1.has_value()) { // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. @@ -602,10 +612,6 @@ ue_fallback_scheduler::alloc_grant(ue& u, pdsch_alloc.slot); } pdcch_sch.cancel_last_pdcch(pdcch_alloc); - if (not use_common_and_ded_res) { - // If there isn't enough space for common PUCCH, then there is no point of repeating this slot. - slots_with_no_pdxch_space[pdcch_alloc.slot.to_uint() % FALLBACK_SCHED_RING_BUFFER_SIZE] = true; - } return {}; } diff --git a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp index d1fbb6e4b9..d3f09e4815 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_configuration_test.cpp @@ -89,6 +89,28 @@ TEST_F(ue_configuration_test, when_reconfiguration_is_received_then_ue_updates_l u.handle_reconfiguration_request(ue_reconf_command{ue_ded_cfg2}); dl_buffer_state_indication_message ind{recfg.ue_index, uint_to_lcid(4), 0}; + // Confirm that the UE is in fallback. + ASSERT_TRUE(u.get_pcell().is_in_fallback_mode()); + ASSERT_TRUE(u.is_reconfig_ongoing()); + + // While in fallback, DL buffer status that are not for SRB0/SRB1, do not get represented in pending bytes. + ASSERT_FALSE(u.has_pending_dl_newtx_bytes()); + for (const auto& lc : *recfg.cfg.lc_config_list) { + ind.lcid = lc.lcid; + ind.bs = 10; + u.handle_dl_buffer_state_indication(ind); + if (lc.lcid <= LCID_SRB1) { + ASSERT_TRUE(u.has_pending_dl_newtx_bytes()); + } else { + ASSERT_FALSE(u.has_pending_dl_newtx_bytes()); + } + ind.bs = 0; + u.handle_dl_buffer_state_indication(ind); + } + + // Confirm that UE config applied config. + u.handle_config_applied(); + // Verify that DL buffer state indications affect newly active logical channels. for (const auto& lc : *recfg.cfg.lc_config_list) { if (lc.lcid == uint_to_lcid(0)) { @@ -98,10 +120,10 @@ TEST_F(ue_configuration_test, when_reconfiguration_is_received_then_ue_updates_l ind.lcid = lc.lcid; ind.bs = 10; u.handle_dl_buffer_state_indication(ind); - ASSERT_TRUE(u.pending_dl_newtx_bytes()); + ASSERT_TRUE(u.has_pending_dl_newtx_bytes()); ind.bs = 0; u.handle_dl_buffer_state_indication(ind); - ASSERT_FALSE(u.pending_dl_newtx_bytes()); + ASSERT_FALSE(u.has_pending_dl_newtx_bytes()); } // Verify that inactive logical channels do not affect pending bytes. From a156987dc7a3f5038439a483cf5e9f87213c4052 Mon Sep 17 00:00:00 2001 From: frankist Date: Wed, 11 Dec 2024 22:33:49 +0100 Subject: [PATCH 145/227] sched: apply fallback transition during ue context setup --- .../f1ap_du_ue_context_setup_procedure.cpp | 12 ++++++++++++ .../du_high/test_utils/du_high_env_simulator.cpp | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp index 7701d3581a..f1cfe12d30 100644 --- a/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp +++ b/lib/f1ap/du/procedures/f1ap_du_ue_context_setup_procedure.cpp @@ -23,6 +23,12 @@ using namespace asn1::f1ap; // Time waiting for RRC container delivery. constexpr std::chrono::milliseconds rrc_container_delivery_timeout{120}; +static bool requires_ue_ran_config_update(const ue_context_setup_request_s& msg) +{ + return msg->srbs_to_be_setup_list_present or msg->drbs_to_be_setup_list_present or + msg->scell_to_be_setup_list_present; +} + f1ap_du_ue_context_setup_procedure::f1ap_du_ue_context_setup_procedure( const asn1::f1ap::ue_context_setup_request_s& msg_, f1ap_du_ue_manager& ue_mng_, @@ -55,6 +61,12 @@ void f1ap_du_ue_context_setup_procedure::operator()(coro_contextcontext.rrc_state = f1ap_ue_context::ue_rrc_state::config_pending; + } + } else { // [TS38.473, 8.3.1.2] If no UE-associated logical F1-connection exists, the UE-associated logical F1-connection // shall be established as part of the procedure. diff --git a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp index d0694c83f3..8a5cec13c3 100644 --- a/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp +++ b/tests/integrationtests/du_high/test_utils/du_high_env_simulator.cpp @@ -487,6 +487,18 @@ bool du_high_env_simulator::run_ue_context_setup(rnti_t rnti) return false; } + // Await for Reconfiguration Complete that signals the UE config update completion. + if (srb1_pdu_size > 0) { + cu_notifier.last_f1ap_msgs.clear(); + du_hi->get_pdu_handler().handle_rx_data_indication( + test_helpers::create_pdu_with_sdu(next_slot, u.rnti, LCID_SRB1, 1)); + bool ret = run_until([this]() { return not cu_notifier.last_f1ap_msgs.empty(); }); + if (not ret or not test_helpers::is_ul_rrc_msg_transfer_valid(cu_notifier.last_f1ap_msgs.back(), srb_id_t::srb1)) { + test_logger.error("rnti={}: F1AP UL RRC Message not sent or is invalid", u.rnti); + return false; + } + } + return true; } From 058309e152da6a1a8aab758b3c2018ab90a184cc Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 12 Dec 2024 14:08:41 +0100 Subject: [PATCH 146/227] sched: fix du-high benchmark after changes to the ue rrc reconf procedure --- tests/benchmarks/du_high/CMakeLists.txt | 1 + .../benchmarks/du_high/du_high_benchmark.cpp | 128 ++++++++++++------ 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/tests/benchmarks/du_high/CMakeLists.txt b/tests/benchmarks/du_high/CMakeLists.txt index 298c66271b..06f2e6c4cb 100644 --- a/tests/benchmarks/du_high/CMakeLists.txt +++ b/tests/benchmarks/du_high/CMakeLists.txt @@ -16,6 +16,7 @@ target_link_libraries(du_high_benchmark f1ap_du_test_helpers pdcp_test_doubles sched_test_doubles + mac_test_doubles du_test_doubles srsran_pcap gtest diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 68bac3bf26..2489641e2a 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -31,6 +31,7 @@ #include "lib/mac/mac_ul/ul_bsr.h" #include "tests/test_doubles/du/test_du_high_worker_manager.h" #include "tests/test_doubles/f1ap/f1ap_test_messages.h" +#include "tests/test_doubles/mac/mac_test_messages.h" #include "tests/test_doubles/pdcp/pdcp_pdu_generator.h" #include "tests/test_doubles/scheduler/scheduler_result_test.h" #include "tests/unittests/f1ap/du/f1ap_du_test_helpers.h" @@ -286,12 +287,7 @@ class dummy_metrics_handler : public scheduler_metrics_notifier class cu_cp_simulator : public srs_du::f1c_connection_client { public: - cu_cp_simulator() : du_rx_pdu_notifier(nullptr) - { - for (auto& flag : ue_created_flag_list) { - flag.store(false, std::memory_order_relaxed); - } - } + cu_cp_simulator() : rx_f1ap_pdus(MAX_NOF_DU_UES) {} private: class f1ap_du_tx_pdu_notifier : public f1ap_message_notifier @@ -307,8 +303,11 @@ class cu_cp_simulator : public srs_du::f1c_connection_client }; public: - std::unique_ptr du_rx_pdu_notifier; - std::array, MAX_NOF_DU_UES> ue_created_flag_list; + using rx_f1ap_pdu_queue = concurrent_queue, + concurrent_queue_policy::lockfree_mpmc, + concurrent_queue_wait_policy::non_blocking>; + + rx_f1ap_pdu_queue rx_f1ap_pdus; std::unique_ptr handle_du_connection_request(std::unique_ptr du_rx_pdu_notifier_) override @@ -317,7 +316,11 @@ class cu_cp_simulator : public srs_du::f1c_connection_client return std::make_unique(*this); } + void send_message(const f1ap_message& msg) { du_rx_pdu_notifier->on_new_message(msg); } + private: + std::array ue_rrc_setup_complete_received = {false}; + void handle_message(const f1ap_message& msg) { switch (msg.pdu.type().value) { @@ -325,7 +328,7 @@ class cu_cp_simulator : public srs_du::f1c_connection_client handle_init_msg(msg); break; case asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome: - handle_success_outcome(msg.pdu.successful_outcome()); + handle_success_outcome(msg); break; default: report_fatal_error("Received invalid PDU type {} in this benchmark", msg.pdu.type().value); @@ -355,40 +358,27 @@ class cu_cp_simulator : public srs_du::f1c_connection_client du_rx_pdu_notifier->on_new_message(dl_msg); } break; case init_opts::ul_rrc_msg_transfer: { - // Send UE Context Setup to create DRB1. - gnb_du_ue_f1ap_id_t du_ue_id = - int_to_gnb_du_ue_f1ap_id(init_msg.value.ul_rrc_msg_transfer()->gnb_du_ue_f1ap_id); - gnb_cu_ue_f1ap_id_t cu_ue_id = - int_to_gnb_cu_ue_f1ap_id(init_msg.value.ul_rrc_msg_transfer()->gnb_du_ue_f1ap_id); - f1ap_message uectxt_msg = test_helpers::create_ue_context_setup_request( - cu_ue_id, du_ue_id, 0, {drb_id_t::drb1}, config_helpers::make_default_du_cell_config().nr_cgi); - auto& ue_ctxt_setup = *uectxt_msg.pdu.init_msg().value.ue_context_setup_request(); - // Do not send RRC container, otherwise we have to send an RLC ACK. - ue_ctxt_setup.rrc_container_present = false; - // Note: Use UM because AM requires status PDUs. - auto& drb1 = ue_ctxt_setup.drbs_to_be_setup_list[0]->drbs_to_be_setup_item(); - drb1.rlc_mode.value = asn1::f1ap::rlc_mode_opts::rlc_um_bidirectional; - drb1.qos_info.choice_ext()->drb_info().drb_qos.qos_characteristics.non_dyn_5qi().five_qi = - 7; // UM in default configs - du_rx_pdu_notifier->on_new_message(uectxt_msg); + report_fatal_error_if_not(rx_f1ap_pdus.try_push(std::make_unique(msg)), "Failed to push Rx PDU"); } break; default: report_fatal_error("Unhandled PDU type {} in this benchmark", init_msg.value.type().to_string()); } } - void handle_success_outcome(const asn1::f1ap::successful_outcome_s& succ_outcome) + void handle_success_outcome(const f1ap_message& msg) { using namespace asn1::f1ap; + auto& succ_outcome = msg.pdu.successful_outcome(); switch (succ_outcome.value.type().value) { case f1ap_elem_procs_o::successful_outcome_c::types_opts::ue_context_setup_resp: { - ue_created_flag_list[succ_outcome.value.ue_context_setup_resp()->gnb_du_ue_f1ap_id].store( - true, std::memory_order_relaxed); + report_fatal_error_if_not(rx_f1ap_pdus.try_push(std::make_unique(msg)), "Failed to push Rx PDU"); } break; default: report_fatal_error("Unreachable code in this benchmark"); } } + + std::unique_ptr du_rx_pdu_notifier; }; /// \brief Dummy F1-U bearer for the purpose of benchmark. @@ -472,6 +462,10 @@ class phy_simulator : public mac_result_notifier, public mac_cell_result_notifie void new_slot() { + slot_dl_data_result.rar_pdus.clear(); + slot_dl_data_result.si_pdus.clear(); + slot_dl_data_result.paging_pdus.clear(); + slot_dl_data_result.ue_pdus.clear(); slot_dl_result.dl_res = nullptr; slot_ul_result.ul_res = nullptr; } @@ -754,8 +748,7 @@ class du_high_bench report_fatal_error_if_not(run_slot_until(dl_pdu_sched), "Msg4 with RRC Setup was not scheduled"); test_logger.info("rnti={}: DU-high scheduled Msg4 (containing RRC Setup)", rnti); - // Push MAC UL SDU that will trigger UE Context Setup. - // Note: MAC UL SDU will make the UE go out of fallback mode. + // Push MAC UL SDU that corresponds to the RRC Setup Complete. rx_ind = {}; rx_ind.sl_rx = next_sl_tx - tx_rx_delay; rx_ind.cell_index = to_du_cell_index(0); @@ -763,13 +756,69 @@ class du_high_bench rx_ind.pdus.push_back(mac_rx_pdu{du_ue_index_to_rnti(ue_idx), 0, 0, ul_pdu.copy()}); du_hi->get_pdu_handler().handle_rx_data_indication(rx_ind); - // Wait for UE Context Modification Response to arrive to CU. - while (not sim_cu_cp.ue_created_flag_list[ue_idx]) { - // Need to run one slot for scheduler to handle pending events. - run_slot(); - process_results(); - std::this_thread::sleep_for(std::chrono::milliseconds{1}); + // Wait for RRC Setup Complete. + std::unique_ptr pdu; + auto ul_rrc_msg_rx = [this, &pdu]() { + return sim_cu_cp.rx_f1ap_pdus.try_pop(pdu) and + pdu->pdu.type().value == asn1::f1ap::f1ap_pdu_c::types_opts::init_msg and + pdu->pdu.init_msg().value.type().value == + asn1::f1ap::f1ap_elem_procs_o::init_msg_c::types_opts::ul_rrc_msg_transfer; + }; + report_fatal_error_if_not(run_slot_until(ul_rrc_msg_rx), "F1AP UL RRC Message missing"); + + // Start UE Context Setup. + { + gnb_du_ue_f1ap_id_t du_ue_id = + int_to_gnb_du_ue_f1ap_id(pdu->pdu.init_msg().value.ul_rrc_msg_transfer()->gnb_du_ue_f1ap_id); + gnb_cu_ue_f1ap_id_t cu_ue_id = + int_to_gnb_cu_ue_f1ap_id(pdu->pdu.init_msg().value.ul_rrc_msg_transfer()->gnb_du_ue_f1ap_id); + f1ap_message uectxt_msg = test_helpers::create_ue_context_setup_request( + cu_ue_id, du_ue_id, 0, {drb_id_t::drb1}, config_helpers::make_default_du_cell_config().nr_cgi); + auto& ue_ctxt_setup = *uectxt_msg.pdu.init_msg().value.ue_context_setup_request(); + // Do not send RRC container, otherwise we have to send an RLC ACK. + ue_ctxt_setup.rrc_container_present = false; + // Note: Use UM because AM requires status PDUs. + auto& drb1 = ue_ctxt_setup.drbs_to_be_setup_list[0]->drbs_to_be_setup_item(); + drb1.rlc_mode.value = asn1::f1ap::rlc_mode_opts::rlc_um_bidirectional; + drb1.qos_info.choice_ext()->drb_info().drb_qos.qos_characteristics.non_dyn_5qi().five_qi = + 7; // UM in default configs + sim_cu_cp.send_message(uectxt_msg); } + + // Wait for UE Context Setup Response. + auto ue_setup_resp_rx = [this, &pdu]() { + return sim_cu_cp.rx_f1ap_pdus.try_pop(pdu) and + pdu->pdu.type().value == asn1::f1ap::f1ap_pdu_c::types_opts::successful_outcome and + pdu->pdu.successful_outcome().value.type().value == + asn1::f1ap::f1ap_elem_procs_o::successful_outcome_c::types_opts::ue_context_setup_resp; + }; + report_fatal_error_if_not(run_slot_until(ue_setup_resp_rx), "F1AP UL RRC Message missing"); + + // Push MAC UL SDU that will serve as RRC Reconf Complete and make the UE go out of fallback mode. + rx_ind = test_helpers::create_pdu_with_sdu(next_sl_tx - tx_rx_delay, rnti, LCID_SRB1, 1); + du_hi->get_pdu_handler().handle_rx_data_indication(rx_ind); + + // Wait for RRC Reconf Complete to arrive to F1AP and that the RLC sends status report. + auto dl_pdu_sched_srb1 = [this, rnti]() { + if (sim_phy.slot_dl_result.dl_res != nullptr) { + return find_ue_pdsch_with_lcid(rnti, LCID_SRB1, sim_phy.slot_dl_result.dl_res->ue_grants) != nullptr; + } + return false; + }; + bool rlc_status_rx = false; + bool rrc_reconf_comp_rx = false; + report_fatal_error_if_not(run_slot_until([&]() { + rlc_status_rx |= dl_pdu_sched_srb1(); + rrc_reconf_comp_rx |= ul_rrc_msg_rx(); + return rlc_status_rx & rrc_reconf_comp_rx; + }), + rrc_reconf_comp_rx ? "RLC Status Report was not scheduled" + : "F1AP UL RRC Message missing"); + + // Mark the UE as fully setup. + ue_created_flag_list[ue_idx] = true; + + test_logger.info("ue={}: Creation completed successfully", ue_idx); } // \brief Push a DL PDUs to DU-high via F1-U interface. @@ -938,8 +987,8 @@ class du_high_bench return; } - // Encode MAC SDU for LCID 4 only if UE Context Modification Response has arrived to CU and LCID 4 is configured. - if (sim_cu_cp.ue_created_flag_list[rnti_to_du_ue_index(pusch.pusch_cfg.rnti)]) { + // Encode MAC SDU for LCID 4 only if UE Configuration is completed and LCID 4 is configured. + if (ue_created_flag_list[rnti_to_du_ue_index(pusch.pusch_cfg.rnti)]) { // Prepare MAC SDU for LCID 4. static const lcid_t drb_lcid = uint_to_lcid(4); mac_rx_pdu rx_pdu{pusch.pusch_cfg.rnti, 0, pusch.pusch_cfg.harq_id, {}}; @@ -1062,6 +1111,9 @@ class du_high_bench phy_simulator sim_phy; slot_point next_sl_tx{0, 0}; + /// Determines whether a UE setup has completed. + std::array ue_created_flag_list{false}; + /// Queue of MAC UCI indication message to be sent in their expected receive slot. std::deque pending_ucis; /// Queue of MAC Rx data indication message to be sent in their expected receive slot. From d1f19eb7b3effe0d492eac8c1f1dfa10e5f2ab3e Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 12 Dec 2024 14:35:06 +0100 Subject: [PATCH 147/227] remove unused variable --- tests/benchmarks/du_high/du_high_benchmark.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 2489641e2a..754fa4074c 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -319,8 +319,6 @@ class cu_cp_simulator : public srs_du::f1c_connection_client void send_message(const f1ap_message& msg) { du_rx_pdu_notifier->on_new_message(msg); } private: - std::array ue_rrc_setup_complete_received = {false}; - void handle_message(const f1ap_message& msg) { switch (msg.pdu.type().value) { From 090ae0e438dea6476b154952cbde6ff4b6dc20de Mon Sep 17 00:00:00 2001 From: sauka Date: Fri, 13 Dec 2024 10:33:50 +0100 Subject: [PATCH 148/227] ofh: add sector id to rx window statistics --- .../ofh/receiver/ofh_receiver_configuration.h | 2 ++ lib/ofh/ofh_factories.cpp | 1 + lib/ofh/receiver/ofh_receiver_impl.cpp | 1 + lib/ofh/receiver/ofh_rx_window_checker.cpp | 6 ++++-- lib/ofh/receiver/ofh_rx_window_checker.h | 7 ++++++- .../ofh/receiver/ofh_message_receiver_test.cpp | 2 +- .../receiver/ofh_rx_window_checker_test.cpp | 18 +++++++++--------- 7 files changed, 24 insertions(+), 13 deletions(-) diff --git a/include/srsran/ofh/receiver/ofh_receiver_configuration.h b/include/srsran/ofh/receiver/ofh_receiver_configuration.h index a24e7057a6..ecbbe15b8a 100644 --- a/include/srsran/ofh/receiver/ofh_receiver_configuration.h +++ b/include/srsran/ofh/receiver/ofh_receiver_configuration.h @@ -24,6 +24,8 @@ namespace ofh { /// Open Fronthaul receiver configuration. struct receiver_config { + /// Radio sector identifier. + unsigned sector; /// Subcarrier spacing. subcarrier_spacing scs; /// Cyclic prefix. diff --git a/lib/ofh/ofh_factories.cpp b/lib/ofh/ofh_factories.cpp index ec2e6f7427..8f4beca4c4 100644 --- a/lib/ofh/ofh_factories.cpp +++ b/lib/ofh/ofh_factories.cpp @@ -40,6 +40,7 @@ std::unique_ptr srsran::ofh::create_ofh_timing_manager(const con static receiver_config generate_receiver_config(const sector_configuration& config) { receiver_config rx_config; + rx_config.sector = config.sector_id; rx_config.ru_operating_bw = config.ru_operating_bw; rx_config.scs = config.scs; rx_config.cp = config.cp; diff --git a/lib/ofh/receiver/ofh_receiver_impl.cpp b/lib/ofh/receiver/ofh_receiver_impl.cpp index ce1bf0172f..4b73db1cfc 100644 --- a/lib/ofh/receiver/ofh_receiver_impl.cpp +++ b/lib/ofh/receiver/ofh_receiver_impl.cpp @@ -77,6 +77,7 @@ receiver_impl::receiver_impl(const receiver_config& config, receiver_impl_depend closed_window_handler(get_closed_rx_window_handler_config(config), std::move(dependencies.window_handler_dependencies)), window_checker(*dependencies.logger, + config.sector, config.rx_timing_params, std::chrono::duration( 1e6 / (get_nsymb_per_slot(config.cp) * get_nof_slots_per_subframe(config.scs)))), diff --git a/lib/ofh/receiver/ofh_rx_window_checker.cpp b/lib/ofh/receiver/ofh_rx_window_checker.cpp index 9ddc8307d3..b1f3718ce2 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.cpp +++ b/lib/ofh/receiver/ofh_rx_window_checker.cpp @@ -16,13 +16,14 @@ using namespace ofh; static constexpr unsigned OFH_MAX_NOF_SFN = 256U; rx_window_checker::rx_window_checker(srslog::basic_logger& logger_, + unsigned sector_id, const rx_window_timing_parameters& params, std::chrono::duration symbol_duration) : timing_parameters(params), nof_symbols_in_one_second(std::ceil(std::chrono::seconds(1) / symbol_duration)), is_disabled(!is_log_enabled(logger_)), nof_symbols(0), - statistics(logger_) + statistics(logger_, sector_id) { } @@ -127,7 +128,8 @@ void rx_window_checker::rx_window_checker_statistics::print_statistics() uint64_t nof_early = current_nof_early - last_early_value_printed; uint64_t nof_late = current_nof_late - last_late_value_printed; - logger.info("Received packets: rx_total={} rx_early={}, rx_on_time={}, rx_late={}", + logger.info("Sector#{} received packets: rx_total={} rx_early={}, rx_on_time={}, rx_late={}", + sector_id, nof_on_time + nof_late + nof_early, nof_early, nof_on_time, diff --git a/lib/ofh/receiver/ofh_rx_window_checker.h b/lib/ofh/receiver/ofh_rx_window_checker.h index bbb64d746e..77217bcf2c 100644 --- a/lib/ofh/receiver/ofh_rx_window_checker.h +++ b/lib/ofh/receiver/ofh_rx_window_checker.h @@ -30,6 +30,7 @@ class rx_window_checker : public ota_symbol_boundary_notifier static constexpr unsigned NOF_BITS_PER_COUNTER = 21U; srslog::basic_logger& logger; + const unsigned sector_id; std::atomic on_time_counter{0}; std::atomic early_counter{0}; std::atomic late_counter{0}; @@ -38,7 +39,10 @@ class rx_window_checker : public ota_symbol_boundary_notifier uint64_t last_late_value_printed = 0U; public: - explicit rx_window_checker_statistics(srslog::basic_logger& logger_) : logger(logger_) {} + rx_window_checker_statistics(srslog::basic_logger& logger_, unsigned sector_id_) : + logger(logger_), sector_id(sector_id_) + { + } /// Prints the statistics. void print_statistics(); @@ -63,6 +67,7 @@ class rx_window_checker : public ota_symbol_boundary_notifier public: rx_window_checker(srslog::basic_logger& logger_, + unsigned sector_id, const rx_window_timing_parameters& params, std::chrono::duration symbol_duration); diff --git a/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp b/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp index 6af0cbe3ca..afc448a6bf 100644 --- a/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_message_receiver_test.cpp @@ -155,7 +155,7 @@ class ofh_message_receiver_fixture : public ::testing::Test std::make_shared(20), std::make_shared(20), std::make_shared()}), - window_checker(srslog::fetch_basic_logger("TEST"), {}, {}), + window_checker(srslog::fetch_basic_logger("TEST"), 0, {}, {}), ul_handler(generate_config(), generate_dependencies()) { window_checker.on_new_symbol({{1, 0}, 0, 14}); diff --git a/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp b/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp index 674187b4bf..018fd316db 100644 --- a/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_rx_window_checker_test.cpp @@ -26,7 +26,7 @@ TEST(ofh_rx_window_checker, on_time_packet_counts_one_packet) logger.set_level(srslog::basic_levels::info); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 0, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -50,7 +50,7 @@ TEST(ofh_rx_window_checker, packet_on_the_window_start_count_as_valid) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 0, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -74,7 +74,7 @@ TEST(ofh_rx_window_checker, packet_on_the_window_end_count_as_valid) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=510us. - rx_window_checker rx_window(logger, {2, 15}, symbol_duration); + rx_window_checker rx_window(logger, 0, {2, 15}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -98,7 +98,7 @@ TEST(ofh_rx_window_checker, early_packet_counts_one_packet) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=80us, Ta4_max=300us. - rx_window_checker rx_window(logger, {3, 9}, symbol_duration); + rx_window_checker rx_window(logger, 0, {3, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -122,7 +122,7 @@ TEST(ofh_rx_window_checker, late_packet_counts_one_packet) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 1, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 1}, 7, 14); @@ -146,7 +146,7 @@ TEST(ofh_rx_window_checker, window_change_slot_works) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 1, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 1, 0}, 1, 14); @@ -170,7 +170,7 @@ TEST(ofh_rx_window_checker, window_change_sfn_works) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 1, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 1, 0, 0}, 1, 14); @@ -194,7 +194,7 @@ TEST(ofh_rx_window_checker, window_change_sfn_byte_works) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 1, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 0, 0, 0}, 1, 14); @@ -218,7 +218,7 @@ TEST(ofh_rx_window_checker, window_change_sfn_byte_and_message_is_in_sfn_0) std::chrono::duration(1e6 / (nof_symbols_per_slot * get_nof_slots_per_subframe(scs)))); // Create window checker with timing parameters corresponding to Ta4_min=50us, Ta4_max=300us. - rx_window_checker rx_window(logger, {2, 9}, symbol_duration); + rx_window_checker rx_window(logger, 1, {2, 9}, symbol_duration); // Create the OTA notification. slot_symbol_point ota_slot({1, 0, 0, 0}, 3, 14); From 343ae835438b7a5dd51ea26c64412c01f9dd08ca Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 13 Dec 2024 12:37:49 +0100 Subject: [PATCH 149/227] cu_cp: fix check for periodic reports for neighbor cells --- apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp index 7857cccc4e..673cd680ce 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp @@ -129,9 +129,8 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili for (const auto& ncell : cell.ncells) { // try to add report config ids to cell_to_report_cfg_id map for (const auto& id : ncell.report_cfg_ids) { - if (cell_to_report_cfg_id.find(nci) != cell_to_report_cfg_id.end() && - !cell_to_report_cfg_id.at(nci).emplace(id).second) { - fmt::print("cell={}: report_config_id={} already configured for this cell\n", ncell.nr_cell_id, id); + if (report_cfg_ids_to_report_type.at(id) == "periodical") { + fmt::print("cell={:#x}: For neighbor cells no periodic reports are allowed\n", cell.nr_cell_id); return false; } } From aa76be342d94b683324c8d047367667e64cbbbd6 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 13 Dec 2024 12:38:26 +0100 Subject: [PATCH 150/227] cu_cp: improve logging --- apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp index 673cd680ce..4a15000e21 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp @@ -90,7 +90,7 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili cell_to_report_cfg_id.emplace(nci, std::set()); auto& report_cfg_ids = cell_to_report_cfg_id.at(nci); if (!report_cfg_ids.emplace(cell.periodic_report_cfg_id.value()).second) { - fmt::print("cell={}: report_config_id={} already configured for this cell)\n", + fmt::print("cell={:#x}: report_config_id={} already configured for this cell)\n", cell.nr_cell_id, cell.periodic_report_cfg_id.value()); return false; From c7641415ef207a0ddc9f233fd7e28541b32f7144 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 13 Dec 2024 12:38:46 +0100 Subject: [PATCH 151/227] cu_cp: fix documentation --- .../cu_cp/cu_cp_unit_config_validator.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp index 4a15000e21..23db2e2981 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_unit_config_validator.cpp @@ -23,14 +23,14 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili { std::map report_cfg_ids_to_report_type; for (const auto& report_cfg : config.report_configs) { - // check that report config ids are unique + // Check that report config ids are unique. if (report_cfg_ids_to_report_type.find(report_cfg.report_cfg_id) != report_cfg_ids_to_report_type.end()) { fmt::print("Report config ids must be unique\n"); return false; } report_cfg_ids_to_report_type.emplace(report_cfg.report_cfg_id, report_cfg.report_type); - // check that report configs are valid + // Check that report configs are valid. if (report_cfg.report_type == "event_triggered") { if (!report_cfg.event_triggered_report_type.has_value()) { fmt::print("Invalid CU-CP configuration. If report type is set to \"event_triggered\" then " @@ -70,7 +70,7 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili std::map> cell_to_report_cfg_id; - // check cu_cp_cell_config + // Check cu_cp_cell_config. std::set ncis; for (const auto& cell : config.cells) { nr_cell_identity nci = nr_cell_identity::create(cell.nr_cell_id).value(); @@ -86,7 +86,7 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili } if (cell.periodic_report_cfg_id.has_value()) { - // try to add report config id to cell_to_report_cfg_id map + // Try to add report config id to cell_to_report_cfg_id map. cell_to_report_cfg_id.emplace(nci, std::set()); auto& report_cfg_ids = cell_to_report_cfg_id.at(nci); if (!report_cfg_ids.emplace(cell.periodic_report_cfg_id.value()).second) { @@ -95,14 +95,14 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili cell.periodic_report_cfg_id.value()); return false; } - // check that for the serving cell only periodic reports are configured + // Check that for the serving cell only periodic reports are configured. if (report_cfg_ids_to_report_type.at(cell.periodic_report_cfg_id.value()) != "periodical") { fmt::print("For the serving cell only periodic reports are allowed\n"); return false; } } - // check if cell is an external managed cell + // Check if cell is an external managed cell. if (nci.gnb_id(gnb_id.bit_length) != gnb_id) { if (!cell.gnb_id_bit_length.has_value() || !cell.pci.has_value() || !cell.band.has_value() || !cell.ssb_arfcn.has_value() || !cell.ssb_scs.has_value() || !cell.ssb_period.has_value() || @@ -125,9 +125,8 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili } } - // check that for neighbor cells managed by this CU-CP no periodic reports are configured + // Check that for neighbor cells managed by this CU-CP no periodic reports are configured. for (const auto& ncell : cell.ncells) { - // try to add report config ids to cell_to_report_cfg_id map for (const auto& id : ncell.report_cfg_ids) { if (report_cfg_ids_to_report_type.at(id) == "periodical") { fmt::print("cell={:#x}: For neighbor cells no periodic reports are allowed\n", cell.nr_cell_id); @@ -137,7 +136,7 @@ static bool validate_mobility_appconfig(gnb_id_t gnb_id, const cu_cp_unit_mobili } } - // verify that each configured neighbor cell is present + // Verify that each configured neighbor cell is present. for (const auto& cell : config.cells) { for (const auto& ncell : cell.ncells) { nr_cell_identity nci = nr_cell_identity::create(ncell.nr_cell_id).value(); From ac5e5fe1bb1a5cf6ea368f40a20af5453c2aa5c1 Mon Sep 17 00:00:00 2001 From: faluco Date: Tue, 19 Nov 2024 11:53:33 +0100 Subject: [PATCH 152/227] [EPOLL_BROKER] Offload the fd events into dedicated executors --- apps/cu/cu.cpp | 29 +- apps/du/adapters/f1_gateways.h | 3 +- apps/du/du.cpp | 29 +- apps/gnb/gnb.cpp | 27 +- apps/services/stdin_command_dispatcher.cpp | 25 +- apps/services/stdin_command_dispatcher.h | 8 +- .../worker_manager/worker_manager.cpp | 3 + apps/services/worker_manager/worker_manager.h | 6 +- .../cu_cp/cu_cp_config_translators.cpp | 5 +- .../o_cu_cp/cu_cp/cu_cp_config_translators.h | 3 +- apps/units/o_cu_cp/o_cu_cp_builder.cpp | 21 +- apps/units/o_cu_cp/o_cu_cp_builder.h | 15 +- apps/units/o_cu_up/o_cu_up_builder.cpp | 7 +- include/srsran/adt/detail/has_member.h | 2 +- .../gateways/e1_local_connector_factory.h | 5 +- .../e1ap/gateways/e1_network_client_factory.h | 3 + .../e1ap/gateways/e1_network_server_factory.h | 3 + include/srsran/e2/e2ap_config_translators.h | 9 +- .../e2/gateways/e2_network_client_factory.h | 3 + .../gateways/f1c_local_connector_factory.h | 5 +- .../gateways/f1c_network_client_factory.h | 3 + .../gateways/f1c_network_server_factory.h | 3 + .../gateways/sctp_network_client_factory.h | 5 +- .../gateways/sctp_network_gateway_factory.h | 11 +- .../gateways/sctp_network_server_factory.h | 5 +- .../gateways/udp_network_gateway_factory.h | 9 +- include/srsran/gtpu/gtpu_gateway.h | 7 +- .../gateways/n2_connection_client_factory.h | 1 + include/srsran/support/io/io_broker.h | 46 ++- include/srsran/support/io/io_broker_factory.h | 2 +- include/srsran/support/io/io_timer_source.h | 16 +- include/srsran/support/io/unique_fd.h | 42 ++- .../gateways/e1_local_connector_factory.cpp | 9 +- .../gateways/e1_network_client_factory.cpp | 2 +- .../gateways/e1_network_server_factory.cpp | 3 +- lib/e2/gateways/e2_network_client_factory.cpp | 2 +- .../gateways/f1c_local_connector_factory.cpp | 9 +- .../gateways/f1c_network_client_factory.cpp | 2 +- .../gateways/f1c_network_server_factory.cpp | 3 +- lib/gateways/sctp_network_client_factory.cpp | 4 +- lib/gateways/sctp_network_client_impl.cpp | 17 +- lib/gateways/sctp_network_client_impl.h | 10 +- lib/gateways/sctp_network_gateway_factory.cpp | 3 +- lib/gateways/sctp_network_gateway_impl.cpp | 9 +- lib/gateways/sctp_network_gateway_impl.h | 4 +- lib/gateways/sctp_network_server_factory.cpp | 3 +- lib/gateways/sctp_network_server_impl.cpp | 17 +- lib/gateways/sctp_network_server_impl.h | 3 + lib/gateways/udp_network_gateway_factory.cpp | 3 +- lib/gateways/udp_network_gateway_impl.cpp | 15 +- lib/gateways/udp_network_gateway_impl.h | 6 +- lib/gtpu/gtpu_gateway.cpp | 21 +- .../gateways/n2_connection_client_factory.cpp | 9 +- lib/support/network/io_broker_epoll.cpp | 295 ++++++++++++------ lib/support/network/io_broker_epoll.h | 47 ++- lib/support/network/io_broker_factory.cpp | 2 +- lib/support/network/io_timer_source.cpp | 25 +- .../udp_network_gateway_benchmark.cpp | 8 +- .../udp_network_gateway_rx_benchmark.cpp | 7 +- .../udp_network_gateway_tx_benchmark.cpp | 8 +- .../e2ap/e2ap_integration_test.cpp | 21 +- .../ngap/ngap_integration_test.cpp | 7 +- tests/unittests/cu_up/cu_up_test.cpp | 6 +- .../e1ap/gateways/e1_gateway_test.cpp | 4 +- tests/unittests/e2/dummy_ric.cpp | 3 +- tests/unittests/e2/dummy_ric.h | 4 +- .../e2/e2ap_network_adapter_test.cpp | 14 +- .../f1ap/gateways/f1c_gateway_test.cpp | 22 +- .../common/f1u_cu_split_connector_test.cpp | 6 +- .../common/f1u_du_split_connector_test.cpp | 6 +- .../gateways/sctp_network_client_test.cpp | 14 +- .../gateways/sctp_network_gateway_test.cpp | 12 +- .../gateways/sctp_network_link_test.cpp | 8 +- .../gateways/sctp_network_server_test.cpp | 15 +- tests/unittests/gateways/sctp_test_helpers.h | 16 +- ...dp_network_gateway_pool_depletion_test.cpp | 3 +- .../gateways/udp_network_gateway_test.cpp | 6 +- .../support/network/io_broker_epoll_test.cpp | 135 ++++---- .../support/network/io_timer_source_test.cpp | 6 +- 79 files changed, 777 insertions(+), 438 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 18b543fea0..b0bad2a2bb 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -273,7 +273,8 @@ int main(int argc, char** argv) f1c_sctp_cfg.bind_address = cu_cfg.f1ap_cfg.bind_addr; f1c_sctp_cfg.bind_port = F1AP_PORT; f1c_sctp_cfg.ppid = F1AP_PPID; - f1c_cu_sctp_gateway_config f1c_server_cfg({f1c_sctp_cfg, *epoll_broker, *cu_cp_dlt_pcaps.f1ap}); + f1c_cu_sctp_gateway_config f1c_server_cfg( + {f1c_sctp_cfg, *epoll_broker, *workers.non_rt_hi_prio_exec, *cu_cp_dlt_pcaps.f1ap}); std::unique_ptr cu_f1c_gw = srsran::create_f1c_gateway_server(f1c_server_cfg); // Create F1-U GW (TODO factory and cleanup). @@ -286,8 +287,8 @@ int main(int argc, char** argv) cu_f1u_gw_config.bind_port = GTPU_PORT; cu_f1u_gw_config.reuse_addr = false; cu_f1u_gw_config.pool_occupancy_threshold = cu_cfg.nru_cfg.pool_occupancy_threshold; - std::unique_ptr cu_f1u_gw = - create_udp_gtpu_gateway(cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor()); + std::unique_ptr cu_f1u_gw = create_udp_gtpu_gateway( + cu_f1u_gw_config, *epoll_broker, workers.cu_up_exec_mapper->io_ul_executor(), *workers.non_rt_low_prio_exec); std::unique_ptr cu_f1u_conn = srs_cu_up::create_split_f1u_gw( {*cu_f1u_gw, *cu_f1u_gtpu_demux, *cu_up_dlt_pcaps.f1u, GTPU_PORT, cu_cfg.nru_cfg.ext_addr}); @@ -301,17 +302,19 @@ int main(int argc, char** argv) timer_manager* cu_timers = &app_timers; // Create time source that ticks the timers - io_timer_source time_source{app_timers, *epoll_broker, std::chrono::milliseconds{1}}; + io_timer_source time_source{app_timers, *epoll_broker, *workers.non_rt_hi_prio_exec, std::chrono::milliseconds{1}}; // Instantiate E2AP client gateway. std::unique_ptr e2_gw_cu_cp = create_e2_gateway_client( generate_e2_client_gateway_config(o_cu_cp_app_unit->get_o_cu_cp_unit_config().e2_cfg.base_config, *epoll_broker, + *workers.non_rt_hi_prio_exec, *cu_cp_dlt_pcaps.e2ap, E2_CP_PPID)); std::unique_ptr e2_gw_cu_up = create_e2_gateway_client( generate_e2_client_gateway_config(o_cu_up_app_unit->get_o_cu_up_unit_config().e2_cfg.base_config, *epoll_broker, + *workers.non_rt_hi_prio_exec, *cu_up_dlt_pcaps.e2ap, E2_UP_PPID)); @@ -319,20 +322,22 @@ int main(int argc, char** argv) // Create O-CU-CP dependencies. o_cu_cp_unit_dependencies o_cucp_deps; - o_cucp_deps.cu_cp_executor = workers.cu_cp_exec; - o_cucp_deps.cu_cp_e2_exec = workers.cu_e2_exec; - o_cucp_deps.timers = cu_timers; - o_cucp_deps.ngap_pcap = cu_cp_dlt_pcaps.ngap.get(); - o_cucp_deps.broker = epoll_broker.get(); - o_cucp_deps.e2_gw = e2_gw_cu_cp.get(); - o_cucp_deps.metrics_notifier = &metrics_notifier_forwarder; + o_cucp_deps.cu_cp_executor = workers.cu_cp_exec; + o_cucp_deps.cu_cp_n2_rx_executor = workers.non_rt_hi_prio_exec; + o_cucp_deps.cu_cp_e2_exec = workers.cu_e2_exec; + o_cucp_deps.timers = cu_timers; + o_cucp_deps.ngap_pcap = cu_cp_dlt_pcaps.ngap.get(); + o_cucp_deps.broker = epoll_broker.get(); + o_cucp_deps.e2_gw = e2_gw_cu_cp.get(); + o_cucp_deps.metrics_notifier = &metrics_notifier_forwarder; // Create O-CU-CP. auto o_cucp_unit = o_cu_cp_app_unit->create_o_cu_cp(o_cucp_deps); srs_cu_cp::o_cu_cp& o_cucp_obj = *o_cucp_unit.unit; // Create console helper object for commands and metrics printing. - app_services::stdin_command_dispatcher command_parser(*epoll_broker, o_cucp_unit.commands); + app_services::stdin_command_dispatcher command_parser( + *epoll_broker, *workers.non_rt_low_prio_exec, o_cucp_unit.commands); std::vector metrics_configs = std::move(o_cucp_unit.metrics); // Connect E1AP to O-CU-CP. diff --git a/apps/du/adapters/f1_gateways.h b/apps/du/adapters/f1_gateways.h index c549edcd90..69a4c5c3de 100644 --- a/apps/du/adapters/f1_gateways.h +++ b/apps/du/adapters/f1_gateways.h @@ -18,6 +18,7 @@ namespace srsran { std::unique_ptr create_f1c_client_gateway(const std::string& cu_cp_addr, const std::string& bind_addr, io_broker& broker, + task_executor& io_rx_executor, dlt_pcap& f1ap_pcap) { sctp_network_connector_config f1c_sctp{}; @@ -27,7 +28,7 @@ std::unique_ptr create_f1c_client_gateway(const s f1c_sctp.connect_port = F1AP_PORT; f1c_sctp.ppid = F1AP_PPID; f1c_sctp.bind_address = bind_addr; - return create_f1c_gateway_client(f1c_du_sctp_gateway_config{f1c_sctp, broker, f1ap_pcap}); + return create_f1c_gateway_client(f1c_du_sctp_gateway_config{f1c_sctp, broker, io_rx_executor, f1ap_pcap}); } } // namespace srsran diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 65d44e55d4..80689d1e6a 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -248,13 +248,16 @@ int main(int argc, char** argv) flexible_o_du_pcaps du_pcaps = create_o_du_pcaps(o_du_app_unit->get_o_du_high_unit_config(), workers); // Instantiate F1-C client gateway. - std::unique_ptr f1c_gw = create_f1c_client_gateway( - du_cfg.f1ap_cfg.cu_cp_address, du_cfg.f1ap_cfg.bind_address, *epoll_broker, *du_pcaps.f1ap); + std::unique_ptr f1c_gw = create_f1c_client_gateway(du_cfg.f1ap_cfg.cu_cp_address, + du_cfg.f1ap_cfg.bind_address, + *epoll_broker, + *workers.non_rt_hi_prio_exec, + *du_pcaps.f1ap); // Create manager of timers for DU, which will be driven by the PHY slot ticks. timer_manager app_timers{256}; - // Create F1-U connector + // Create F1-U connector. // TODO: Simplify this and use factory. gtpu_demux_creation_request du_f1u_gtpu_msg = {}; du_f1u_gtpu_msg.cfg.warn_on_drop = true; @@ -265,10 +268,11 @@ int main(int argc, char** argv) du_f1u_gw_config.bind_port = GTPU_PORT; du_f1u_gw_config.reuse_addr = false; du_f1u_gw_config.pool_occupancy_threshold = du_cfg.nru_cfg.pool_threshold; - std::unique_ptr du_f1u_gw = create_udp_gtpu_gateway( - du_f1u_gw_config, - *epoll_broker, - workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0))); + std::unique_ptr du_f1u_gw = + create_udp_gtpu_gateway(du_f1u_gw_config, + *epoll_broker, + workers.get_du_high_executor_mapper(0).ue_mapper().mac_ul_pdu_executor(to_du_ue_index(0)), + *workers.non_rt_low_prio_exec); std::unique_ptr du_f1u_conn = srs_du::create_split_f1u_gw( {du_f1u_gw.get(), du_f1u_gtpu_demux.get(), *du_pcaps.f1u, GTPU_PORT, du_cfg.nru_cfg.ext_addr}); @@ -277,8 +281,12 @@ int main(int argc, char** argv) srslog::fetch_udp_sink(du_cfg.metrics_cfg.addr, du_cfg.metrics_cfg.port, srslog::create_json_formatter()); // Instantiate E2AP client gateway. - std::unique_ptr e2_gw = create_e2_gateway_client(generate_e2_client_gateway_config( - o_du_app_unit->get_o_du_high_unit_config().e2_cfg.base_cfg, *epoll_broker, *du_pcaps.e2ap, E2_DU_PPID)); + std::unique_ptr e2_gw = create_e2_gateway_client( + generate_e2_client_gateway_config(o_du_app_unit->get_o_du_high_unit_config().e2_cfg.base_cfg, + *epoll_broker, + *workers.non_rt_hi_prio_exec, + *du_pcaps.e2ap, + E2_DU_PPID)); app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder; o_du_unit_dependencies du_dependencies; @@ -303,7 +311,8 @@ int main(int argc, char** argv) srs_du::du& du_inst = *du_inst_and_cmds.unit; // Register the commands. - app_services::stdin_command_dispatcher command_parser(*epoll_broker, du_inst_and_cmds.commands); + app_services::stdin_command_dispatcher command_parser( + *epoll_broker, *workers.non_rt_low_prio_exec, du_inst_and_cmds.commands); // Start processing. du_inst.get_power_controller().start(); diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 6e87138256..39a60baa21 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -358,28 +358,35 @@ int main(int argc, char** argv) std::vector metrics_configs; // Instantiate E2AP client gateways. - std::unique_ptr e2_gw_du = create_e2_gateway_client(generate_e2_client_gateway_config( - o_du_app_unit->get_o_du_high_unit_config().e2_cfg.base_cfg, *epoll_broker, *du_pcaps.e2ap, E2_DU_PPID)); + std::unique_ptr e2_gw_du = create_e2_gateway_client( + generate_e2_client_gateway_config(o_du_app_unit->get_o_du_high_unit_config().e2_cfg.base_cfg, + *epoll_broker, + *workers.non_rt_hi_prio_exec, + *du_pcaps.e2ap, + E2_DU_PPID)); std::unique_ptr e2_gw_cu_cp = create_e2_gateway_client( generate_e2_client_gateway_config(o_cu_cp_app_unit->get_o_cu_cp_unit_config().e2_cfg.base_config, *epoll_broker, + *workers.non_rt_hi_prio_exec, *cu_cp_dlt_pcaps.e2ap, E2_CP_PPID)); std::unique_ptr e2_gw_cu_up = create_e2_gateway_client( generate_e2_client_gateway_config(o_cu_up_app_unit->get_o_cu_up_unit_config().e2_cfg.base_config, *epoll_broker, + *workers.non_rt_hi_prio_exec, *cu_up_dlt_pcaps.e2ap, E2_UP_PPID)); // Create O-CU-CP dependencies. o_cu_cp_unit_dependencies o_cucp_deps; - o_cucp_deps.cu_cp_executor = workers.cu_cp_exec; - o_cucp_deps.cu_cp_e2_exec = workers.cu_e2_exec; - o_cucp_deps.timers = cu_timers; - o_cucp_deps.ngap_pcap = cu_cp_dlt_pcaps.ngap.get(); - o_cucp_deps.broker = epoll_broker.get(); - o_cucp_deps.metrics_notifier = &metrics_notifier_forwarder; - o_cucp_deps.e2_gw = e2_gw_cu_cp.get(); + o_cucp_deps.cu_cp_executor = workers.cu_cp_exec; + o_cucp_deps.cu_cp_n2_rx_executor = workers.non_rt_hi_prio_exec; + o_cucp_deps.cu_cp_e2_exec = workers.cu_e2_exec; + o_cucp_deps.timers = cu_timers; + o_cucp_deps.ngap_pcap = cu_cp_dlt_pcaps.ngap.get(); + o_cucp_deps.broker = epoll_broker.get(); + o_cucp_deps.metrics_notifier = &metrics_notifier_forwarder; + o_cucp_deps.e2_gw = e2_gw_cu_cp.get(); // create O-CU-CP. auto o_cucp_unit = o_cu_cp_app_unit->create_o_cu_cp(o_cucp_deps); @@ -435,7 +442,7 @@ int main(int argc, char** argv) commands.push_back(std::move(cmd)); } - app_services::stdin_command_dispatcher command_parser(*epoll_broker, commands); + app_services::stdin_command_dispatcher command_parser(*epoll_broker, *workers.non_rt_low_prio_exec, commands); // Connect E1AP to O-CU-CP. e1_gw->attach_cu_cp(o_cucp_obj.get_cu_cp().get_e1_handler()); diff --git a/apps/services/stdin_command_dispatcher.cpp b/apps/services/stdin_command_dispatcher.cpp index 503ab4eb41..0a6debe283 100644 --- a/apps/services/stdin_command_dispatcher.cpp +++ b/apps/services/stdin_command_dispatcher.cpp @@ -49,7 +49,8 @@ class sleep_app_command : public application_command // See interface for documentation. void execute(span args) override - { // Verify that the number of arguments is valid. + { + // Verify that the number of arguments is valid. if (args.size() != 1) { fmt::print("Invalid sleep command syntax. Usage: sleep \n"); return; @@ -77,6 +78,7 @@ class sleep_app_command : public application_command } // namespace stdin_command_dispatcher::stdin_command_dispatcher(io_broker& io_broker, + task_executor& executor, span> commands_) : logger(srslog::fetch_basic_logger("APP")) { @@ -99,13 +101,13 @@ stdin_command_dispatcher::stdin_command_dispatcher(io_broker& cmd = std::move(app_cmd); } - // Set STDIN file descripter into non-blocking mode + // Set STDIN file descriptor into non-blocking mode. int flags = ::fcntl(STDIN_FILENO, F_GETFL, 0); if (::fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) == -1) { logger.error("Couldn't configure fd to non-blocking"); } - stdin_handle = io_broker.register_fd(STDIN_FILENO, [this]() { parse_stdin(STDIN_FILENO); }); + stdin_handle = io_broker.register_fd(unique_fd(STDIN_FILENO, false), executor, [this]() { parse_stdin(); }); if (!stdin_handle.registered()) { logger.error("Couldn't register stdin handler"); } @@ -116,7 +118,7 @@ static void string_parse_list(const std::string& input, char delimiter, std::vec { std::stringstream ss(input); - // Removes all possible elements of the list + // Removes all possible elements of the list. commands.clear(); while (ss.good()) { @@ -129,18 +131,17 @@ static void string_parse_list(const std::string& input, char delimiter, std::vec } } -void stdin_command_dispatcher::parse_stdin(int file_descriptor) +void stdin_command_dispatcher::parse_stdin() { - static constexpr unsigned read_chunk = 256; + static constexpr size_t read_chunk = 256; + unsigned total_bytes_read = 0; std::array buffer; - int bytes_read = 0; - int total_bytes_read = 0; logger.debug("Stdin has data to read"); do { - // Read from stdin until EWOULDBLOCK is set - bytes_read = ::read(file_descriptor, &buffer[total_bytes_read], read_chunk); + // Read from stdin until EWOULDBLOCK is set. + int bytes_read = ::read(STDIN_FILENO, &buffer[total_bytes_read], read_chunk); if (bytes_read < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) { break; @@ -159,7 +160,7 @@ void stdin_command_dispatcher::parse_stdin(int file_descriptor) logger.debug("read {} B from stdin", total_bytes_read); - // Convert buffer to string + // Convert buffer to string. std::string input_line(buffer.begin(), buffer.begin() + total_bytes_read); std::vector cmd_list; @@ -184,7 +185,7 @@ void stdin_command_dispatcher::handle_command(const std::string& command) srsran_assert(!arg_list.empty(), "Parsing empty command argument list"); - if (const auto& cmd = commands.find(arg_list.front()); cmd != commands.end()) { + if (auto cmd = commands.find(arg_list.front()); cmd != commands.end()) { cmd->second->execute(span(arg_list).last(arg_list.size() - 1)); } else { print_help(); diff --git a/apps/services/stdin_command_dispatcher.h b/apps/services/stdin_command_dispatcher.h index 296980aa76..c2822b07cc 100644 --- a/apps/services/stdin_command_dispatcher.h +++ b/apps/services/stdin_command_dispatcher.h @@ -27,11 +27,13 @@ namespace app_services { class stdin_command_dispatcher { public: - stdin_command_dispatcher(io_broker& io_broker, span> commands_); + stdin_command_dispatcher(io_broker& io_broker, + task_executor& executor, + span> commands_); private: - /// Parses STDIN with the given file decriptor. - void parse_stdin(int file_descriptor); + /// Parses any contents in the STDIN file descriptor. + void parse_stdin(); /// Handles the given command; void handle_command(const std::string& command); diff --git a/apps/services/worker_manager/worker_manager.cpp b/apps/services/worker_manager/worker_manager.cpp index d2c1f836dc..0b977296fc 100644 --- a/apps/services/worker_manager/worker_manager.cpp +++ b/apps/services/worker_manager/worker_manager.cpp @@ -346,6 +346,9 @@ void worker_manager::create_low_prio_executors(const worker_manager_config& work if (not exec_mng.add_execution_context(create_execution_context(non_rt_pool))) { report_fatal_error("Failed to instantiate {} execution context", non_rt_pool.name); } + + non_rt_low_prio_exec = exec_mng.executors().at("low_prio_exec"); + non_rt_hi_prio_exec = exec_mng.executors().at("high_prio_exec"); } void worker_manager::associate_low_prio_executors(const worker_manager_config& config) diff --git a/apps/services/worker_manager/worker_manager.h b/apps/services/worker_manager/worker_manager.h index fc75a603ed..345d818e68 100644 --- a/apps/services/worker_manager/worker_manager.h +++ b/apps/services/worker_manager/worker_manager.h @@ -55,8 +55,10 @@ struct worker_manager : public worker_manager_executor_getter { std::vector fapi_exec; std::vector ru_dl_exec; std::vector ru_rx_exec; - task_executor* cu_e2_exec = nullptr; - task_executor* metrics_hub_exec = nullptr; + task_executor* cu_e2_exec = nullptr; + task_executor* metrics_hub_exec = nullptr; + task_executor* non_rt_low_prio_exec = nullptr; + task_executor* non_rt_hi_prio_exec = nullptr; std::unique_ptr cu_up_exec_mapper; diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.cpp b/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.cpp index efab33e110..5aacba861a 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.cpp @@ -454,13 +454,14 @@ srs_cu_cp::cu_cp_configuration srsran::generate_cu_cp_config(const cu_cp_unit_co srs_cu_cp::n2_connection_client_config srsran::generate_n2_client_config(bool no_core, const cu_cp_unit_amf_config_item& amf_cfg, dlt_pcap& pcap_writer, - io_broker& broker) + io_broker& broker, + task_executor& io_rx_executor) { using no_core_mode_t = srs_cu_cp::n2_connection_client_config::no_core; using network_mode_t = srs_cu_cp::n2_connection_client_config::network; using ngap_mode_t = std::variant; - ngap_mode_t mode = no_core ? ngap_mode_t{no_core_mode_t{}} : ngap_mode_t{network_mode_t{broker}}; + ngap_mode_t mode = no_core ? ngap_mode_t{no_core_mode_t{}} : ngap_mode_t{network_mode_t{broker, io_rx_executor}}; if (not no_core) { network_mode_t& nw_mode = std::get(mode); nw_mode.amf_address = amf_cfg.ip_addr; diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.h b/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.h index 15fa3e671d..c04d115f71 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.h +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_config_translators.h @@ -26,7 +26,8 @@ srs_cu_cp::cu_cp_configuration generate_cu_cp_config(const cu_cp_unit_config& cu srs_cu_cp::n2_connection_client_config generate_n2_client_config(bool no_core, const cu_cp_unit_amf_config_item& amf_cfg, dlt_pcap& pcap_writer, - io_broker& broker); + io_broker& broker, + task_executor& io_rx_executor); /// Fills the CU-CP worker manager parameters of the given worker manager configuration. void fill_cu_cp_worker_manager_config(worker_manager_config& config, const cu_cp_unit_config& unit_cfg); diff --git a/apps/units/o_cu_cp/o_cu_cp_builder.cpp b/apps/units/o_cu_cp/o_cu_cp_builder.cpp index 45a2e673d2..c11e5c672e 100644 --- a/apps/units/o_cu_cp/o_cu_cp_builder.cpp +++ b/apps/units/o_cu_cp/o_cu_cp_builder.cpp @@ -24,6 +24,7 @@ using namespace srsran; o_cu_cp_unit srsran::build_o_cu_cp(const o_cu_cp_unit_config& unit_cfg, o_cu_cp_unit_dependencies& dependencies) { srsran_assert(dependencies.cu_cp_executor, "Invalid CU-CP executor"); + srsran_assert(dependencies.cu_cp_n2_rx_executor, "Invalid N2 Rx executor"); srsran_assert(dependencies.cu_cp_e2_exec, "Invalid E2 executor"); srsran_assert(dependencies.ngap_pcap, "Invalid NGAP PCAP"); srsran_assert(dependencies.broker, "Invalid IO broker"); @@ -40,16 +41,24 @@ o_cu_cp_unit srsran::build_o_cu_cp(const o_cu_cp_unit_config& unit_cfg, o_cu_cp_ // Create N2 Client Gateways. std::vector> n2_clients; - n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( - cucp_unit_cfg.amf_config.no_core, cucp_unit_cfg.amf_config.amf, *dependencies.ngap_pcap, *dependencies.broker))); + n2_clients.push_back( + srs_cu_cp::create_n2_connection_client(generate_n2_client_config(cucp_unit_cfg.amf_config.no_core, + cucp_unit_cfg.amf_config.amf, + *dependencies.ngap_pcap, + *dependencies.broker, + *dependencies.cu_cp_n2_rx_executor))); for (const auto& amf : cucp_unit_cfg.extra_amfs) { - n2_clients.push_back(srs_cu_cp::create_n2_connection_client(generate_n2_client_config( - cucp_unit_cfg.amf_config.no_core, amf, *dependencies.ngap_pcap, *dependencies.broker))); + n2_clients.push_back( + srs_cu_cp::create_n2_connection_client(generate_n2_client_config(cucp_unit_cfg.amf_config.no_core, + amf, + *dependencies.ngap_pcap, + *dependencies.broker, + *dependencies.cu_cp_n2_rx_executor))); } - for (unsigned pos = 0; pos < n2_clients.size(); pos++) { - cu_cp_cfg.ngaps[pos].n2_gw = n2_clients[pos].get(); + for (unsigned i = 0, e = n2_clients.size(); i != e; ++i) { + cu_cp_cfg.ngaps[i].n2_gw = n2_clients[i].get(); } auto e2_metric_connectors = std::make_unique(); diff --git a/apps/units/o_cu_cp/o_cu_cp_builder.h b/apps/units/o_cu_cp/o_cu_cp_builder.h index f4628a441a..23f43dcf2e 100644 --- a/apps/units/o_cu_cp/o_cu_cp_builder.h +++ b/apps/units/o_cu_cp/o_cu_cp_builder.h @@ -38,13 +38,14 @@ class e2_gateway_remote_connector; /// O-RAN CU-CP build dependencies. struct o_cu_cp_unit_dependencies { - task_executor* cu_cp_executor = nullptr; - task_executor* cu_cp_e2_exec = nullptr; - timer_manager* timers = nullptr; - dlt_pcap* ngap_pcap = nullptr; - io_broker* broker = nullptr; - e2_connection_client* e2_gw = nullptr; - app_services::metrics_notifier* metrics_notifier = nullptr; + task_executor* cu_cp_executor = nullptr; + task_executor* cu_cp_n2_rx_executor = nullptr; + task_executor* cu_cp_e2_exec = nullptr; + timer_manager* timers = nullptr; + dlt_pcap* ngap_pcap = nullptr; + io_broker* broker = nullptr; + e2_connection_client* e2_gw = nullptr; + app_services::metrics_notifier* metrics_notifier = nullptr; }; /// O-RAN CU-CP unit. diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index a6b2f97761..44c107045e 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -75,8 +75,11 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets - std::unique_ptr ngu_gw = create_udp_gtpu_gateway( - n3_udp_cfg, *dependencies.io_brk, dependencies.workers->cu_up_exec_mapper->io_ul_executor()); + std::unique_ptr ngu_gw = + create_udp_gtpu_gateway(n3_udp_cfg, + *dependencies.io_brk, + dependencies.workers->cu_up_exec_mapper->io_ul_executor(), + *dependencies.workers->non_rt_low_prio_exec); ngu_gws.push_back(std::move(ngu_gw)); } } else { diff --git a/include/srsran/adt/detail/has_member.h b/include/srsran/adt/detail/has_member.h index 11c02d8723..17d0606204 100644 --- a/include/srsran/adt/detail/has_member.h +++ b/include/srsran/adt/detail/has_member.h @@ -32,4 +32,4 @@ constexpr bool has_member_impl(...) /// Check if type T has the method/member EXPR. #define has_member(T, EXPR) detail::has_member_impl([](auto&& obj) -> decltype(obj.EXPR) {}) -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/e1ap/gateways/e1_local_connector_factory.h b/include/srsran/e1ap/gateways/e1_local_connector_factory.h index 830dcb1f79..76322518d8 100644 --- a/include/srsran/e1ap/gateways/e1_local_connector_factory.h +++ b/include/srsran/e1ap/gateways/e1_local_connector_factory.h @@ -17,6 +17,7 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; class e1_local_connector : public srs_cu_up::e1_connection_client, public srs_cu_cp::e1_connection_server {}; @@ -35,6 +36,8 @@ struct e1_local_sctp_connector_config { dlt_pcap& pcap; /// IO broker to handle the SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// Port to bind the SCTP socket. int bind_port = 0; }; @@ -44,4 +47,4 @@ struct e1_local_sctp_connector_config { /// Note: This class is useful for testing. std::unique_ptr create_e1_local_connector(const e1_local_sctp_connector_config& cfg); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/e1ap/gateways/e1_network_client_factory.h b/include/srsran/e1ap/gateways/e1_network_client_factory.h index fc85fb93a9..e94d8204de 100644 --- a/include/srsran/e1ap/gateways/e1_network_client_factory.h +++ b/include/srsran/e1ap/gateways/e1_network_client_factory.h @@ -17,6 +17,7 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; /// Configuration of an SCTP-based E1 Gateway in the CU-UP. struct e1_cu_up_sctp_gateway_config { @@ -24,6 +25,8 @@ struct e1_cu_up_sctp_gateway_config { sctp_network_connector_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// PCAP writer for the E1AP messages. dlt_pcap& pcap; }; diff --git a/include/srsran/e1ap/gateways/e1_network_server_factory.h b/include/srsran/e1ap/gateways/e1_network_server_factory.h index 059842f8a9..1a8c849bad 100644 --- a/include/srsran/e1ap/gateways/e1_network_server_factory.h +++ b/include/srsran/e1ap/gateways/e1_network_server_factory.h @@ -18,6 +18,7 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; /// Configuration of an SCTP-based E1 Gateway in the CU-CP. struct e1_cu_cp_sctp_gateway_config { @@ -25,6 +26,8 @@ struct e1_cu_cp_sctp_gateway_config { sctp_network_gateway_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// PCAP writer for the E1AP messages. dlt_pcap& pcap; }; diff --git a/include/srsran/e2/e2ap_config_translators.h b/include/srsran/e2/e2ap_config_translators.h index cf349ad2d4..66fce50f10 100644 --- a/include/srsran/e2/e2ap_config_translators.h +++ b/include/srsran/e2/e2ap_config_translators.h @@ -16,8 +16,11 @@ namespace srsran { /// Retuns the E2 SCTP gateway configuration from the given parameters. -inline e2_sctp_gateway_config -generate_e2_client_gateway_config(const e2_config& e2_cfg, io_broker& broker, dlt_pcap& f1ap_pcap, uint16_t ppid) +inline e2_sctp_gateway_config generate_e2_client_gateway_config(const e2_config& e2_cfg, + io_broker& broker, + task_executor& io_rx_executor, + dlt_pcap& f1ap_pcap, + uint16_t ppid) { sctp_network_connector_config e2ap_sctp{}; e2ap_sctp.if_name = "E2AP"; @@ -27,7 +30,7 @@ generate_e2_client_gateway_config(const e2_config& e2_cfg, io_broker& broker, dl e2ap_sctp.ppid = ppid; e2ap_sctp.bind_address = e2_cfg.bind_addr; - return {e2ap_sctp, broker, f1ap_pcap}; + return {e2ap_sctp, broker, io_rx_executor, f1ap_pcap}; } } // namespace srsran diff --git a/include/srsran/e2/gateways/e2_network_client_factory.h b/include/srsran/e2/gateways/e2_network_client_factory.h index c7ed8b20df..7ae92b2095 100644 --- a/include/srsran/e2/gateways/e2_network_client_factory.h +++ b/include/srsran/e2/gateways/e2_network_client_factory.h @@ -17,12 +17,15 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; struct e2_sctp_gateway_config { /// SCTP configuration. sctp_network_connector_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// PCAP writer for the E2AP messages. dlt_pcap& pcap; }; diff --git a/include/srsran/f1ap/gateways/f1c_local_connector_factory.h b/include/srsran/f1ap/gateways/f1c_local_connector_factory.h index 94040541db..929c33b30a 100644 --- a/include/srsran/f1ap/gateways/f1c_local_connector_factory.h +++ b/include/srsran/f1ap/gateways/f1c_local_connector_factory.h @@ -17,6 +17,7 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; class f1c_local_connector : public srs_du::f1c_connection_client, public srs_cu_cp::f1c_connection_server {}; @@ -35,6 +36,8 @@ struct f1c_local_sctp_connector_config { dlt_pcap& pcap; /// IO broker to handle the SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; }; /// Creates an F1-C local connector using an SCTP socket as channel. @@ -42,4 +45,4 @@ struct f1c_local_sctp_connector_config { /// Note: This class is useful for testing. std::unique_ptr create_f1c_local_connector(const f1c_local_sctp_connector_config& cfg); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/f1ap/gateways/f1c_network_client_factory.h b/include/srsran/f1ap/gateways/f1c_network_client_factory.h index fc83643127..a1a157b3ba 100644 --- a/include/srsran/f1ap/gateways/f1c_network_client_factory.h +++ b/include/srsran/f1ap/gateways/f1c_network_client_factory.h @@ -17,12 +17,15 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; struct f1c_du_sctp_gateway_config { /// SCTP configuration. sctp_network_connector_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// PCAP writer for the F1AP messages. dlt_pcap& pcap; }; diff --git a/include/srsran/f1ap/gateways/f1c_network_server_factory.h b/include/srsran/f1ap/gateways/f1c_network_server_factory.h index 28b81f8c3f..28767056ed 100644 --- a/include/srsran/f1ap/gateways/f1c_network_server_factory.h +++ b/include/srsran/f1ap/gateways/f1c_network_server_factory.h @@ -18,6 +18,7 @@ namespace srsran { class dlt_pcap; class io_broker; +class task_executor; /// Configuration of an SCTP-based F1-C Gateway. struct f1c_cu_sctp_gateway_config { @@ -25,6 +26,8 @@ struct f1c_cu_sctp_gateway_config { sctp_network_gateway_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// PCAP writer for the F1AP messages. dlt_pcap& pcap; }; diff --git a/include/srsran/gateways/sctp_network_client_factory.h b/include/srsran/gateways/sctp_network_client_factory.h index e3d9d1397b..8886c62687 100644 --- a/include/srsran/gateways/sctp_network_client_factory.h +++ b/include/srsran/gateways/sctp_network_client_factory.h @@ -15,13 +15,16 @@ namespace srsran { +class task_executor; + /// Configuration of an SCTP client. struct sctp_network_client_config { sctp_network_gateway_config sctp; io_broker& broker; + task_executor& io_rx_executor; }; /// Creates an SCTP network client. std::unique_ptr create_sctp_network_client(const sctp_network_client_config& config); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/gateways/sctp_network_gateway_factory.h b/include/srsran/gateways/sctp_network_gateway_factory.h index 1dedd17021..b9231c5a79 100644 --- a/include/srsran/gateways/sctp_network_gateway_factory.h +++ b/include/srsran/gateways/sctp_network_gateway_factory.h @@ -16,16 +16,23 @@ namespace srsran { +class task_executor; + struct sctp_network_gateway_creation_message { sctp_network_gateway_creation_message(sctp_network_connector_config config_, sctp_network_gateway_control_notifier& ctrl_notifier_, - network_gateway_data_notifier& data_notifier_) : - config(std::move(config_)), ctrl_notifier(ctrl_notifier_), data_notifier(data_notifier_) + network_gateway_data_notifier& data_notifier_, + task_executor& io_rx_executor_) : + config(std::move(config_)), + ctrl_notifier(ctrl_notifier_), + data_notifier(data_notifier_), + io_rx_executor(io_rx_executor_) { } sctp_network_connector_config config; sctp_network_gateway_control_notifier& ctrl_notifier; network_gateway_data_notifier& data_notifier; + task_executor& io_rx_executor; }; /// Creates an instance of an network gateway diff --git a/include/srsran/gateways/sctp_network_server_factory.h b/include/srsran/gateways/sctp_network_server_factory.h index 85f782c969..63ef9943c0 100644 --- a/include/srsran/gateways/sctp_network_server_factory.h +++ b/include/srsran/gateways/sctp_network_server_factory.h @@ -15,10 +15,13 @@ namespace srsran { +class task_executor; + /// Configuration of an SCTP server. struct sctp_network_server_config { sctp_network_gateway_config sctp; io_broker& broker; + task_executor& io_rx_executor; sctp_network_association_factory& association_handler_factory; }; @@ -26,4 +29,4 @@ struct sctp_network_server_config { /// associations. std::unique_ptr create_sctp_network_server(const sctp_network_server_config& config); -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/gateways/udp_network_gateway_factory.h b/include/srsran/gateways/udp_network_gateway_factory.h index 04c21e9f95..53af32ebd8 100644 --- a/include/srsran/gateways/udp_network_gateway_factory.h +++ b/include/srsran/gateways/udp_network_gateway_factory.h @@ -20,13 +20,18 @@ namespace srsran { struct udp_network_gateway_creation_message { udp_network_gateway_creation_message(udp_network_gateway_config config_, network_gateway_data_notifier_with_src_addr& data_notifier_, - task_executor& io_tx_executor_) : - config(std::move(config_)), data_notifier(data_notifier_), io_tx_executor(io_tx_executor_) + task_executor& io_tx_executor_, + task_executor& io_rx_executor_) : + config(std::move(config_)), + data_notifier(data_notifier_), + io_tx_executor(io_tx_executor_), + io_rx_executor(io_rx_executor_) { } udp_network_gateway_config config; network_gateway_data_notifier_with_src_addr& data_notifier; task_executor& io_tx_executor; + task_executor& io_rx_executor; }; /// Creates an instance of an network gateway diff --git a/include/srsran/gtpu/gtpu_gateway.h b/include/srsran/gtpu/gtpu_gateway.h index 43ad0af336..fec75398cd 100644 --- a/include/srsran/gtpu/gtpu_gateway.h +++ b/include/srsran/gtpu/gtpu_gateway.h @@ -58,9 +58,12 @@ class gtpu_gateway /// \param[in] config Configuration of the UDP network gateway. /// \param[in] io_brk IO broker that will manage the reception of new PDUs from the UDP socket. /// \param[in] io_tx_executor Executor that will be used to handle the transmission of PDUs to the UDP socket. +/// \param[in] io_rx_executor Executor that will be used to handle the reception of PDUs on the UDP socket. /// \return Returns the instantiated GTP-U gateway. Returns nullptr, if the GTP-U gateway could not be established. -std::unique_ptr -create_udp_gtpu_gateway(const udp_network_gateway_config& config, io_broker& io_brk, task_executor& io_tx_executor); +std::unique_ptr create_udp_gtpu_gateway(const udp_network_gateway_config& config, + io_broker& io_brk, + task_executor& io_tx_executor, + task_executor& io_rx_executor); /// \brief Creates a GTP-U gateway that establishes a connection to a null/dummy UPF. /// diff --git a/include/srsran/ngap/gateways/n2_connection_client_factory.h b/include/srsran/ngap/gateways/n2_connection_client_factory.h index 1cd6135c5a..494457db45 100644 --- a/include/srsran/ngap/gateways/n2_connection_client_factory.h +++ b/include/srsran/ngap/gateways/n2_connection_client_factory.h @@ -29,6 +29,7 @@ struct n2_connection_client_config { /// Parameters specific to an SCTP network gateway. struct network { io_broker& broker; + task_executor& io_rx_executor; std::string bind_address; std::string bind_interface; std::string amf_address; diff --git a/include/srsran/support/io/io_broker.h b/include/srsran/support/io/io_broker.h index 99e75d641a..a4ef4335b8 100644 --- a/include/srsran/support/io/io_broker.h +++ b/include/srsran/support/io/io_broker.h @@ -10,18 +10,21 @@ #pragma once +#include "srsran/support/executors/task_executor.h" #include "srsran/support/executors/unique_thread.h" +#include "srsran/support/io/unique_fd.h" +#include #include #include namespace srsran { struct io_broker_config { + explicit io_broker_config(os_sched_affinity_bitmask mask_ = {}) : cpu_mask(std::move(mask_)) {} + std::string thread_name = "io_broker_epoll"; os_thread_realtime_priority thread_prio = os_thread_realtime_priority::no_realtime(); - os_sched_affinity_bitmask cpu_mask = {}; - /// Constructor receives CPU affinity mask. - io_broker_config(os_sched_affinity_bitmask mask_ = {}) : cpu_mask(mask_) {} + os_sched_affinity_bitmask cpu_mask; }; /// \brief Describes the interface for an (async) IO broker. @@ -37,21 +40,26 @@ class io_broker { public: subscriber() = default; + subscriber(io_broker& broker_, int fd_) : broker(&broker_), fd(fd_) {} + subscriber(subscriber&& other) noexcept { std::lock_guard lock(other.mutex); broker = other.broker; fd = std::exchange(other.fd, -1); } + subscriber& operator=(subscriber&& other) noexcept { std::scoped_lock lock(mutex, other.mutex); + reset_nolock(); broker = other.broker; fd = std::exchange(other.fd, -1); return *this; } + ~subscriber() { reset(); } /// Checks whether the FD is connected to the broker. @@ -62,18 +70,35 @@ class io_broker } /// Resets the handle, deregistering the FD from the broker. + /// \note: This function will block until the FD has been removed from the broker. bool reset() { std::lock_guard lock(mutex); - return reset_nolock(); + std::promise p; + std::future fut = p.get_future(); + + bool ret = reset_nolock(&p); + fut.get(); + + return ret; + } + + /// Returns the file descriptor value held by this subscriber. + int value() const + { + std::lock_guard lock(mutex); + return fd; } private: - bool reset_nolock() + bool reset_nolock(std::promise* complete_notifier = nullptr) { int fd_tmp = std::exchange(fd, -1); if (fd_tmp >= 0) { - return broker->unregister_fd(fd_tmp); + return broker->unregister_fd(fd_tmp, complete_notifier); + } + if (complete_notifier) { + complete_notifier->set_value(false); } return false; } @@ -95,20 +120,23 @@ class io_broker /// \brief Register a file descriptor to be handled by the IO interface. /// \param[in] fd File descriptor to be registered. + /// \param[in] executor Execution context where the given callbacks will be called. /// \param[in] handler Callback that handles receive events. /// \param[in] err_handler Callback that handles error events. /// \return An RAII handle to the registered file descriptor. On destruction, the fd is automatically deregistered /// from the io_broker. [[nodiscard]] virtual subscriber register_fd( - int fd, + unique_fd fd, + task_executor& executor, recv_callback_t handler, error_callback_t err_handler = [](error_code) {}) = 0; private: /// \brief Unregister a file descriptor from the IO interface. - /// \param[in] fd File descriptor to be unregistered. + /// \param[in] fd File descriptor to be unregistered. + /// \param[in] complete_notifier Synchronization primitive to wait for the deregistration of the FD to be completed. /// \return true if the file descriptor was successfully unregistered, false otherwise. - [[nodiscard]] virtual bool unregister_fd(int fd) = 0; + [[nodiscard]] virtual bool unregister_fd(int fd, std::promise* complete_notifier) = 0; }; } // namespace srsran diff --git a/include/srsran/support/io/io_broker_factory.h b/include/srsran/support/io/io_broker_factory.h index 5d4d05e5a1..1d945dfdba 100644 --- a/include/srsran/support/io/io_broker_factory.h +++ b/include/srsran/support/io/io_broker_factory.h @@ -18,6 +18,6 @@ namespace srsran { enum class io_broker_type { epoll, io_uring }; /// Creates an instance of an IO broker -std::unique_ptr create_io_broker(io_broker_type type, io_broker_config config = {}); +std::unique_ptr create_io_broker(io_broker_type type, const io_broker_config& config = io_broker_config()); } // namespace srsran diff --git a/include/srsran/support/io/io_timer_source.h b/include/srsran/support/io/io_timer_source.h index 0d5a363e13..4cbc2a02d1 100644 --- a/include/srsran/support/io/io_timer_source.h +++ b/include/srsran/support/io/io_timer_source.h @@ -19,20 +19,18 @@ namespace srsran { /// \brief Interface for a timer source. class io_timer_source { + timer_manager& tick_sink; + srslog::basic_logger& logger; + io_broker::subscriber io_sub; + public: io_timer_source(timer_manager& tick_sink_, io_broker& broker_, - std::chrono::milliseconds tick_period = std::chrono::milliseconds{1}); + task_executor& executor, + std::chrono::milliseconds tick_period); private: void read_time(); - - timer_manager& tick_sink; - srslog::basic_logger& logger; - - unique_fd timer_fd; - - io_broker::subscriber io_sub; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/support/io/unique_fd.h b/include/srsran/support/io/unique_fd.h index 903932b37a..bbbc38d935 100644 --- a/include/srsran/support/io/unique_fd.h +++ b/include/srsran/support/io/unique_fd.h @@ -10,40 +10,43 @@ #pragma once -#include "srsran/support/compiler.h" #include "fmt/format.h" #include +#include namespace srsran { -/// \brief Scoped file descriptor that calls ::close(fd) on destruction and is not copyable. +/// Scoped file descriptor that calls ::close(fd) on destruction (if auto-close is enabled) and is not copyable. class unique_fd { public: unique_fd() = default; - explicit unique_fd(int fd_) : fd(fd_) {} - unique_fd(const unique_fd& other) = delete; - unique_fd(unique_fd&& other) noexcept : fd(other.fd) { other.fd = -1; } + explicit unique_fd(int fd_, bool auto_close_ = true) : fd(fd_), auto_close(auto_close_) {} + + unique_fd(const unique_fd& other) = delete; unique_fd& operator=(const unique_fd& other) = delete; + + unique_fd(unique_fd&& other) noexcept : fd(std::exchange(other.fd, -1)), auto_close(other.auto_close) {} + unique_fd& operator=(unique_fd&& other) noexcept { - if (is_open()) { - if (not close()) { - fmt::print("Error: Failed to close file descriptor: {}.", strerror(errno)); - } + if (is_open() && auto_close && !close()) { + print_close_error_msg(); } - fd = other.fd; - other.fd = -1; + + fd = std::exchange(other.fd, -1); + auto_close = other.auto_close; return *this; } + ~unique_fd() { - bool ret = close(); - if (not ret) { - fmt::print("Error: Failed to close file descriptor: {}.", strerror(errno)); + if (auto_close && !close()) { + print_close_error_msg(); } } + /// Closes the file descriptor if it is open. Returns true on success, otherwise false. [[nodiscard]] bool close() { if (fd >= 0) { @@ -56,12 +59,21 @@ class unique_fd return true; } + /// Returns true if the file descriptor is open. [[nodiscard]] bool is_open() const { return fd >= 0; } + /// Returns the raw file descriptor value or -1 if the file descriptor is not open. [[nodiscard]] int value() const { return fd; } private: - int fd = -1; + /// Prints a close error message with the corresponding cause. + void print_close_error_msg() + { + fmt::print("Error: Failed to close file descriptor '{}': {}.\n", fd, ::strerror(errno)); + } + + int fd = -1; + bool auto_close = true; }; } // namespace srsran diff --git a/lib/e1ap/gateways/e1_local_connector_factory.cpp b/lib/e1ap/gateways/e1_local_connector_factory.cpp index 985fa45b88..b24e03e523 100644 --- a/lib/e1ap/gateways/e1_local_connector_factory.cpp +++ b/lib/e1ap/gateways/e1_local_connector_factory.cpp @@ -95,7 +95,8 @@ class e1_local_connector_impl final : public e1_local_connector class e1_sctp_connector_impl final : public e1_local_connector { public: - e1_sctp_connector_impl(const e1_local_sctp_connector_config& cfg) : broker(cfg.broker), pcap_writer(cfg.pcap) + e1_sctp_connector_impl(const e1_local_sctp_connector_config& cfg) : + broker(cfg.broker), io_rx_executor(cfg.io_rx_executor), pcap_writer(cfg.pcap) { // Create SCTP server. sctp_network_gateway_config sctp; @@ -104,7 +105,7 @@ class e1_sctp_connector_impl final : public e1_local_connector sctp.bind_address = "127.0.0.1"; // Use any bind port available. sctp.bind_port = cfg.bind_port; - server = create_e1_gateway_server(e1_cu_cp_sctp_gateway_config{sctp, broker, pcap_writer}); + server = create_e1_gateway_server(e1_cu_cp_sctp_gateway_config{sctp, broker, cfg.io_rx_executor, pcap_writer}); } void attach_cu_cp(srs_cu_cp::cu_cp_e1_handler& cu_e1_handler_) override @@ -119,7 +120,8 @@ class e1_sctp_connector_impl final : public e1_local_connector sctp_client.connect_port = server->get_listen_port().value(); sctp_client.ppid = E1AP_PPID; // Note: We only need to save the PCAPs in one side of the connection. - client = create_e1_gateway_client(e1_cu_up_sctp_gateway_config{sctp_client, broker, *null_pcap_writer}); + client = + create_e1_gateway_client(e1_cu_up_sctp_gateway_config{sctp_client, broker, io_rx_executor, *null_pcap_writer}); } std::optional get_listen_port() const override { return server->get_listen_port(); } @@ -133,6 +135,7 @@ class e1_sctp_connector_impl final : public e1_local_connector private: io_broker& broker; + task_executor& io_rx_executor; dlt_pcap& pcap_writer; std::unique_ptr null_pcap_writer = create_null_dlt_pcap(); std::unique_ptr server; diff --git a/lib/e1ap/gateways/e1_network_client_factory.cpp b/lib/e1ap/gateways/e1_network_client_factory.cpp index de3a1d85a3..4738796814 100644 --- a/lib/e1ap/gateways/e1_network_client_factory.cpp +++ b/lib/e1ap/gateways/e1_network_client_factory.cpp @@ -102,7 +102,7 @@ class e1_sctp_gateway_client final : public srs_cu_up::e1_connection_client pcap_writer(params.pcap), broker(params.broker), sctp_params(params.sctp) { // Create SCTP network adapter. - sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker}); + sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker, params.io_rx_executor}); report_error_if_not(sctp_gateway != nullptr, "Failed to create SCTP gateway client.\n"); } diff --git a/lib/e1ap/gateways/e1_network_server_factory.cpp b/lib/e1ap/gateways/e1_network_server_factory.cpp index e1f9c83107..a733bcd2c3 100644 --- a/lib/e1ap/gateways/e1_network_server_factory.cpp +++ b/lib/e1ap/gateways/e1_network_server_factory.cpp @@ -101,7 +101,8 @@ class e1_sctp_server final : public srs_cu_cp::e1_connection_server, public sctp e1_sctp_server(const e1_cu_cp_sctp_gateway_config& params_) : params(params_) { // Create SCTP server. - sctp_server = create_sctp_network_server(sctp_network_server_config{params.sctp, params.broker, *this}); + sctp_server = create_sctp_network_server( + sctp_network_server_config{params.sctp, params.broker, params.io_rx_executor, *this}); report_error_if_not(sctp_server != nullptr, "Failed to create SCTP server"); } diff --git a/lib/e2/gateways/e2_network_client_factory.cpp b/lib/e2/gateways/e2_network_client_factory.cpp index 7a0b32d25f..45e18d7a59 100644 --- a/lib/e2/gateways/e2_network_client_factory.cpp +++ b/lib/e2/gateways/e2_network_client_factory.cpp @@ -102,7 +102,7 @@ class e2_sctp_gateway_client final : public e2_connection_client pcap_writer(params.pcap), broker(params.broker), sctp_params(params.sctp) { // Create SCTP network adapter. - sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker}); + sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker, params.io_rx_executor}); report_error_if_not(sctp_gateway != nullptr, "Failed to create SCTP gateway client.\n"); } diff --git a/lib/f1ap/gateways/f1c_local_connector_factory.cpp b/lib/f1ap/gateways/f1c_local_connector_factory.cpp index 7571b5dadb..a20e69eb47 100644 --- a/lib/f1ap/gateways/f1c_local_connector_factory.cpp +++ b/lib/f1ap/gateways/f1c_local_connector_factory.cpp @@ -99,7 +99,8 @@ class f1c_local_connector_impl final : public f1c_local_connector class f1c_sctp_connector_impl final : public f1c_local_connector { public: - f1c_sctp_connector_impl(const f1c_local_sctp_connector_config& cfg) : broker(cfg.broker), pcap_writer(cfg.pcap) + f1c_sctp_connector_impl(const f1c_local_sctp_connector_config& cfg) : + broker(cfg.broker), io_rx_executor(cfg.io_rx_executor), pcap_writer(cfg.pcap) { // Create SCTP server. sctp_network_gateway_config sctp; @@ -108,7 +109,7 @@ class f1c_sctp_connector_impl final : public f1c_local_connector sctp.bind_address = "127.0.0.1"; // Use any bind port available. sctp.bind_port = 0; - server = create_f1c_gateway_server(f1c_cu_sctp_gateway_config{sctp, broker, pcap_writer}); + server = create_f1c_gateway_server(f1c_cu_sctp_gateway_config{sctp, broker, cfg.io_rx_executor, pcap_writer}); } void attach_cu_cp(srs_cu_cp::cu_cp_f1c_handler& cu_f1c_handler_) override @@ -123,7 +124,8 @@ class f1c_sctp_connector_impl final : public f1c_local_connector sctp_client.connect_port = server->get_listen_port().value(); sctp_client.ppid = F1AP_PPID; // Note: We only need to save the PCAPs in one side of the connection. - client = create_f1c_gateway_client(f1c_du_sctp_gateway_config{sctp_client, broker, *null_pcap_writer}); + client = + create_f1c_gateway_client(f1c_du_sctp_gateway_config{sctp_client, broker, io_rx_executor, *null_pcap_writer}); } std::optional get_listen_port() const override { return server->get_listen_port(); } @@ -137,6 +139,7 @@ class f1c_sctp_connector_impl final : public f1c_local_connector private: io_broker& broker; + task_executor& io_rx_executor; dlt_pcap& pcap_writer; std::unique_ptr null_pcap_writer = create_null_dlt_pcap(); std::unique_ptr server; diff --git a/lib/f1ap/gateways/f1c_network_client_factory.cpp b/lib/f1ap/gateways/f1c_network_client_factory.cpp index 8be8dcdec5..b94ebd2bb6 100644 --- a/lib/f1ap/gateways/f1c_network_client_factory.cpp +++ b/lib/f1ap/gateways/f1c_network_client_factory.cpp @@ -100,7 +100,7 @@ class f1c_sctp_gateway_client final : public srs_du::f1c_connection_client pcap_writer(params.pcap), broker(params.broker), sctp_params(params.sctp) { // Create SCTP network adapter. - sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker}); + sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker, params.io_rx_executor}); report_error_if_not(sctp_gateway != nullptr, "Failed to create SCTP gateway client.\n"); } diff --git a/lib/f1ap/gateways/f1c_network_server_factory.cpp b/lib/f1ap/gateways/f1c_network_server_factory.cpp index b76d7ef3e8..38bf84ea65 100644 --- a/lib/f1ap/gateways/f1c_network_server_factory.cpp +++ b/lib/f1ap/gateways/f1c_network_server_factory.cpp @@ -102,7 +102,8 @@ class f1c_sctp_server final : public srs_cu_cp::f1c_connection_server, public sc f1c_sctp_server(const f1c_cu_sctp_gateway_config& params_) : params(params_) { // Create SCTP server. - sctp_server = create_sctp_network_server(sctp_network_server_config{params.sctp, params.broker, *this}); + sctp_server = create_sctp_network_server( + sctp_network_server_config{params.sctp, params.broker, params.io_rx_executor, *this}); report_error_if_not(sctp_server != nullptr, "Failed to create SCTP server"); } diff --git a/lib/gateways/sctp_network_client_factory.cpp b/lib/gateways/sctp_network_client_factory.cpp index 27718a1404..d0e543b240 100644 --- a/lib/gateways/sctp_network_client_factory.cpp +++ b/lib/gateways/sctp_network_client_factory.cpp @@ -15,5 +15,5 @@ using namespace srsran; std::unique_ptr srsran::create_sctp_network_client(const sctp_network_client_config& config) { - return sctp_network_client_impl::create(config.sctp, config.broker); -} \ No newline at end of file + return sctp_network_client_impl::create(config.sctp, config.broker, config.io_rx_executor); +} diff --git a/lib/gateways/sctp_network_client_impl.cpp b/lib/gateways/sctp_network_client_impl.cpp index b261d6d59c..6afee051a8 100644 --- a/lib/gateways/sctp_network_client_impl.cpp +++ b/lib/gateways/sctp_network_client_impl.cpp @@ -116,8 +116,13 @@ class sctp_network_client_impl::sctp_send_notifier final : public sctp_associati std::shared_ptr> closed_flag; }; -sctp_network_client_impl::sctp_network_client_impl(const sctp_network_gateway_config& sctp_cfg, io_broker& broker_) : - sctp_network_gateway_common_impl(sctp_cfg), broker(broker_), temp_recv_buffer(network_gateway_sctp_max_len) +sctp_network_client_impl::sctp_network_client_impl(const sctp_network_gateway_config& sctp_cfg, + io_broker& broker_, + task_executor& io_rx_executor_) : + sctp_network_gateway_common_impl(sctp_cfg), + broker(broker_), + io_rx_executor(io_rx_executor_), + temp_recv_buffer(network_gateway_sctp_max_len) { } @@ -243,7 +248,8 @@ sctp_network_client_impl::connect_to(const std::string& // Register the socket in the IO broker. io_sub = broker.register_fd( - socket.fd().value(), + unique_fd(socket.fd().value(), false), + io_rx_executor, [this]() { receive(); }, [this](io_broker::error_code code) { std::string cause = fmt::format("IO error code={}", (int)code); @@ -389,7 +395,8 @@ void sctp_network_client_impl::handle_notification(span } std::unique_ptr sctp_network_client_impl::create(const sctp_network_gateway_config& sctp_cfg, - io_broker& broker_) + io_broker& broker_, + task_executor& io_rx_executor) { // Validate arguments. if (sctp_cfg.if_name.empty()) { @@ -398,7 +405,7 @@ std::unique_ptr sctp_network_client_impl::create(const sctp } // Create a SCTP client instance. - std::unique_ptr client{new sctp_network_client_impl(sctp_cfg, broker_)}; + std::unique_ptr client{new sctp_network_client_impl(sctp_cfg, broker_, io_rx_executor)}; // If a bind address is provided, create a socket here and bind it. if (not sctp_cfg.bind_address.empty()) { diff --git a/lib/gateways/sctp_network_client_impl.h b/lib/gateways/sctp_network_client_impl.h index 2ad4b07841..3a672c5a23 100644 --- a/lib/gateways/sctp_network_client_impl.h +++ b/lib/gateways/sctp_network_client_impl.h @@ -25,13 +25,16 @@ namespace srsran { /// This implementation assumes single-threaded access to its public interface. class sctp_network_client_impl : public sctp_network_client, public sctp_network_gateway_common_impl { - explicit sctp_network_client_impl(const sctp_network_gateway_config& sctp_cfg, io_broker& broker); + explicit sctp_network_client_impl(const sctp_network_gateway_config& sctp_cfg, + io_broker& broker, + task_executor& io_rx_executor_); public: ~sctp_network_client_impl() override; /// Create an SCTP client. - static std::unique_ptr create(const sctp_network_gateway_config& sctp_cfg, io_broker& broker); + static std::unique_ptr + create(const sctp_network_gateway_config& sctp_cfg, io_broker& broker, task_executor& io_rx_executor); /// Connect to an SCTP server with the provided address. std::unique_ptr @@ -55,7 +58,8 @@ class sctp_network_client_impl : public sctp_network_client, public sctp_network void handle_connection_close(const char* cause); void handle_sctp_shutdown_comp(); - io_broker& broker; + io_broker& broker; + task_executor& io_rx_executor; // Temporary buffer where read data is saved. std::vector temp_recv_buffer; diff --git a/lib/gateways/sctp_network_gateway_factory.cpp b/lib/gateways/sctp_network_gateway_factory.cpp index 269223e9a5..3115cf7315 100644 --- a/lib/gateways/sctp_network_gateway_factory.cpp +++ b/lib/gateways/sctp_network_gateway_factory.cpp @@ -16,5 +16,6 @@ using namespace srsran; std::unique_ptr srsran::create_sctp_network_gateway(sctp_network_gateway_creation_message msg) { - return std::make_unique(msg.config, msg.ctrl_notifier, msg.data_notifier); + return std::make_unique( + msg.config, msg.ctrl_notifier, msg.data_notifier, msg.io_rx_executor); } diff --git a/lib/gateways/sctp_network_gateway_impl.cpp b/lib/gateways/sctp_network_gateway_impl.cpp index 5e8ac1cd16..cfd64f118c 100644 --- a/lib/gateways/sctp_network_gateway_impl.cpp +++ b/lib/gateways/sctp_network_gateway_impl.cpp @@ -20,11 +20,13 @@ using namespace srsran; sctp_network_gateway_impl::sctp_network_gateway_impl(const sctp_network_connector_config& config_, sctp_network_gateway_control_notifier& ctrl_notfier_, - network_gateway_data_notifier& data_notifier_) : + network_gateway_data_notifier& data_notifier_, + task_executor& io_rx_executor_) : sctp_network_gateway_common_impl(config_), config(config_), ctrl_notifier(ctrl_notfier_), - data_notifier(data_notifier_) + data_notifier(data_notifier_), + io_rx_executor(io_rx_executor_) { } @@ -275,7 +277,8 @@ void sctp_network_gateway_impl::handle_pdu(const byte_buffer& pdu) bool sctp_network_gateway_impl::subscribe_to(io_broker& broker) { io_sub = broker.register_fd( - socket.fd().value(), + unique_fd(socket.fd().value(), false), + io_rx_executor, [this]() { receive(); }, [this](io_broker::error_code code) { logger.info("Connection loss due to IO error code={}.", (int)code); diff --git a/lib/gateways/sctp_network_gateway_impl.h b/lib/gateways/sctp_network_gateway_impl.h index 5ca0136790..d597a1d1af 100644 --- a/lib/gateways/sctp_network_gateway_impl.h +++ b/lib/gateways/sctp_network_gateway_impl.h @@ -22,7 +22,8 @@ class sctp_network_gateway_impl final : public sctp_network_gateway_common_impl, public: explicit sctp_network_gateway_impl(const sctp_network_connector_config& config_, sctp_network_gateway_control_notifier& ctrl_notifier_, - network_gateway_data_notifier& data_notifier_); + network_gateway_data_notifier& data_notifier_, + task_executor& io_rx_executor_); /// \brief Create and connect socket to given address. bool create_and_connect() override; @@ -57,6 +58,7 @@ class sctp_network_gateway_impl final : public sctp_network_gateway_common_impl, sctp_network_connector_config config; sctp_network_gateway_control_notifier& ctrl_notifier; network_gateway_data_notifier& data_notifier; + task_executor& io_rx_executor; bool client_mode = false; diff --git a/lib/gateways/sctp_network_server_factory.cpp b/lib/gateways/sctp_network_server_factory.cpp index d0d2beef26..6b1c760dc2 100644 --- a/lib/gateways/sctp_network_server_factory.cpp +++ b/lib/gateways/sctp_network_server_factory.cpp @@ -15,5 +15,6 @@ using namespace srsran; std::unique_ptr srsran::create_sctp_network_server(const sctp_network_server_config& config) { - return sctp_network_server_impl::create(config.sctp, config.broker, config.association_handler_factory); + return sctp_network_server_impl::create( + config.sctp, config.broker, config.io_rx_executor, config.association_handler_factory); } diff --git a/lib/gateways/sctp_network_server_impl.cpp b/lib/gateways/sctp_network_server_impl.cpp index 088e6a9637..be8d57c72b 100644 --- a/lib/gateways/sctp_network_server_impl.cpp +++ b/lib/gateways/sctp_network_server_impl.cpp @@ -129,9 +129,11 @@ sctp_network_server_impl::sctp_associaton_context::sctp_associaton_context(int a sctp_network_server_impl::sctp_network_server_impl(const srsran::sctp_network_gateway_config& sctp_cfg_, io_broker& broker_, + task_executor& io_rx_executor_, sctp_network_association_factory& assoc_factory_) : sctp_network_gateway_common_impl(sctp_cfg_), broker(broker_), + io_rx_executor(io_rx_executor_), assoc_factory(assoc_factory_), temp_recv_buffer(network_gateway_sctp_max_len) { @@ -305,11 +307,11 @@ void sctp_network_server_impl::handle_association_shutdown(int assoc_id, const c return; } - // The client wishes to close the association. - // Signal that the upper layer sender should stop sending new SCTP data (including the EOF, which would fail anyway). + // The business domain or the peer side wishes to close the association. + // Signal that the business domain should stop sending new SCTP data (including the EOF, which would fail anyway). bool prev = assoc_it->second.association_shutdown_received->exchange(true); if (not prev and cause != nullptr) { - // The association sender didn't yet close the connection and the association was closed by the client + // The association sender didn't yet close the connection and the association was closed by the peer side. logger.info("{} assoc={}: SCTP association was shut down (client_addr={}). Cause: {}", node_cfg.if_name, assoc_it->first, @@ -360,7 +362,8 @@ std::optional sctp_network_server_impl::get_listen_port() bool sctp_network_server_impl::subscribe_to_broker() { io_sub = broker.register_fd( - socket.fd().value(), + unique_fd(socket.fd().value(), false), + io_rx_executor, [this]() { receive(); }, [this](io_broker::error_code code) { logger.info("Connection loss due to IO error code={}.", (int)code); @@ -371,7 +374,8 @@ bool sctp_network_server_impl::subscribe_to_broker() std::unique_ptr sctp_network_server_impl::create(const sctp_network_gateway_config& sctp_cfg, io_broker& broker_, - sctp_network_association_factory& assoc_factory_) + task_executor& io_rx_executor_, + sctp_network_association_factory& assoc_factory_) { // Validate arguments if (sctp_cfg.if_name.empty()) { @@ -384,7 +388,8 @@ std::unique_ptr sctp_network_server_impl::create(const sctp } // Create a SCTP server instance. - std::unique_ptr server{new sctp_network_server_impl(sctp_cfg, broker_, assoc_factory_)}; + std::unique_ptr server{ + new sctp_network_server_impl(sctp_cfg, broker_, io_rx_executor_, assoc_factory_)}; // Create a socket and bind it to the provided address. if (not server->create_and_bind()) { diff --git a/lib/gateways/sctp_network_server_impl.h b/lib/gateways/sctp_network_server_impl.h index ed5a6d15ae..59c1e7be22 100644 --- a/lib/gateways/sctp_network_server_impl.h +++ b/lib/gateways/sctp_network_server_impl.h @@ -26,6 +26,7 @@ class sctp_network_server_impl : public sctp_network_server, public sctp_network { explicit sctp_network_server_impl(const sctp_network_gateway_config& sctp_cfg, io_broker& broker, + task_executor& io_rx_executor, sctp_network_association_factory& assoc_factory); public: @@ -33,6 +34,7 @@ class sctp_network_server_impl : public sctp_network_server, public sctp_network static std::unique_ptr create(const sctp_network_gateway_config& sctp_cfg, io_broker& broker, + task_executor& io_rx_executor, sctp_network_association_factory& assoc_factory); int get_socket_fd() const override { return socket.fd().value(); } @@ -81,6 +83,7 @@ class sctp_network_server_impl : public sctp_network_server, public sctp_network handle_sctp_comm_up(const struct sctp_assoc_change& assoc_change, const sockaddr& src_addr, socklen_t src_addr_len); io_broker& broker; + task_executor& io_rx_executor; sctp_network_association_factory& assoc_factory; association_map associations; diff --git a/lib/gateways/udp_network_gateway_factory.cpp b/lib/gateways/udp_network_gateway_factory.cpp index 6767a7a817..53dd31f5d0 100644 --- a/lib/gateways/udp_network_gateway_factory.cpp +++ b/lib/gateways/udp_network_gateway_factory.cpp @@ -15,5 +15,6 @@ using namespace srsran; std::unique_ptr srsran::create_udp_network_gateway(udp_network_gateway_creation_message msg) { - return std::make_unique(msg.config, msg.data_notifier, msg.io_tx_executor); + return std::make_unique( + msg.config, msg.data_notifier, msg.io_tx_executor, msg.io_rx_executor); } diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index 507ee578c2..747ba3cb38 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -24,11 +24,13 @@ using namespace srsran; udp_network_gateway_impl::udp_network_gateway_impl(udp_network_gateway_config config_, network_gateway_data_notifier_with_src_addr& data_notifier_, - task_executor& io_tx_executor_) : + task_executor& io_tx_executor_, + task_executor& io_rx_executor_) : config(std::move(config_)), data_notifier(data_notifier_), logger(srslog::fetch_basic_logger("UDP-GW")), - io_tx_executor(io_tx_executor_) + io_tx_executor(io_tx_executor_), + io_rx_executor(io_rx_executor_) { logger.info("UDP GW configured. rx_max_mmsg={} pool_thres={}", config.rx_max_mmsg, config.pool_occupancy_threshold); @@ -47,7 +49,10 @@ udp_network_gateway_impl::udp_network_gateway_impl(udp_network_gateway_config bool udp_network_gateway_impl::subscribe_to(io_broker& broker) { io_subcriber = broker.register_fd( - get_socket_fd(), [this]() { receive(); }, [this](io_broker::error_code code) { handle_io_error(code); }); + unique_fd(get_socket_fd()), + io_rx_executor, + [this]() { receive(); }, + [this](io_broker::error_code code) { handle_io_error(code); }); if (not io_subcriber.registered()) { logger.error("Failed to register UDP network gateway at IO broker. socket_fd={}", get_socket_fd()); return false; @@ -129,7 +134,7 @@ bool udp_network_gateway_impl::create_and_bind() struct addrinfo* result; for (result = results; result != nullptr; result = result->ai_next) { // create UDP socket - sock_fd = unique_fd{::socket(result->ai_family, result->ai_socktype, result->ai_protocol)}; + sock_fd = unique_fd{::socket(result->ai_family, result->ai_socktype, result->ai_protocol), false}; if (not sock_fd.is_open()) { ret = errno; continue; @@ -220,6 +225,7 @@ void udp_network_gateway_impl::receive() } int rx_msgs = recvmmsg(sock_fd.value(), rx_msghdr.data(), config.rx_max_mmsg, MSG_WAITFORONE, nullptr); + srslog::fetch_basic_logger("IO-EPOLL").info("UDP rx {} packets, max is {}", rx_msgs, config.rx_max_mmsg); if (rx_msgs == -1 && errno != EAGAIN) { logger.error("Error reading from UDP socket: {}", strerror(errno)); return; @@ -397,7 +403,6 @@ bool udp_network_gateway_impl::set_reuse_addr() bool udp_network_gateway_impl::close_socket() { - io_subcriber.reset(); if (not sock_fd.close()) { logger.error("Error closing socket: {}", strerror(errno)); return false; diff --git a/lib/gateways/udp_network_gateway_impl.h b/lib/gateways/udp_network_gateway_impl.h index b6c309ff9f..999b95f2f5 100644 --- a/lib/gateways/udp_network_gateway_impl.h +++ b/lib/gateways/udp_network_gateway_impl.h @@ -27,8 +27,9 @@ class udp_network_gateway_impl final : public udp_network_gateway public: explicit udp_network_gateway_impl(udp_network_gateway_config config_, network_gateway_data_notifier_with_src_addr& data_notifier_, - task_executor& io_tx_executor_); - ~udp_network_gateway_impl() override { close_socket(); } + task_executor& io_tx_executor_, + task_executor& io_rx_executor_); + ~udp_network_gateway_impl() override { io_subcriber.reset(); } bool subscribe_to(io_broker& broker) override; @@ -61,6 +62,7 @@ class udp_network_gateway_impl final : public udp_network_gateway network_gateway_data_notifier_with_src_addr& data_notifier; srslog::basic_logger& logger; task_executor& io_tx_executor; + task_executor& io_rx_executor; unique_fd sock_fd; io_broker::subscriber io_subcriber; diff --git a/lib/gtpu/gtpu_gateway.cpp b/lib/gtpu/gtpu_gateway.cpp index 7932d8c71e..903b8550c5 100644 --- a/lib/gtpu/gtpu_gateway.cpp +++ b/lib/gtpu/gtpu_gateway.cpp @@ -35,12 +35,14 @@ class udp_ngu_tnl_session final : public gtpu_tnl_pdu_session static std::unique_ptr create(const udp_network_gateway_config& cfg, network_gateway_data_notifier_with_src_addr& data_notifier, io_broker& io_brk, - task_executor& io_tx_executor) + task_executor& io_tx_executor, + task_executor& io_rx_executor) { std::unique_ptr conn(new udp_ngu_tnl_session(data_notifier)); // Create a new UDP network gateway instance. - conn->udp_gw = create_udp_network_gateway(udp_network_gateway_creation_message{cfg, *conn, io_tx_executor}); + conn->udp_gw = + create_udp_network_gateway(udp_network_gateway_creation_message{cfg, *conn, io_tx_executor, io_rx_executor}); // Bind/open the gateway, start handling of incoming traffic from UPF, e.g. echo if (not conn->udp_gw->create_and_bind()) { @@ -83,29 +85,34 @@ class udp_ngu_tnl_session final : public gtpu_tnl_pdu_session class udp_ngu_gateway final : public gtpu_gateway { public: - udp_ngu_gateway(const udp_network_gateway_config& cfg_, io_broker& io_brk_, task_executor& io_tx_executor_) : - cfg(cfg_), io_brk(io_brk_), io_tx_executor(io_tx_executor_) + udp_ngu_gateway(const udp_network_gateway_config& cfg_, + io_broker& io_brk_, + task_executor& io_tx_executor_, + task_executor& io_rx_executor_) : + cfg(cfg_), io_brk(io_brk_), io_tx_executor(io_tx_executor_), io_rx_executor(io_rx_executor_) { } std::unique_ptr create(network_gateway_data_notifier_with_src_addr& data_notifier) override { - return udp_ngu_tnl_session::create(cfg, data_notifier, io_brk, io_tx_executor); + return udp_ngu_tnl_session::create(cfg, data_notifier, io_brk, io_tx_executor, io_rx_executor); } private: const udp_network_gateway_config cfg; io_broker& io_brk; task_executor& io_tx_executor; + task_executor& io_rx_executor; }; } // namespace std::unique_ptr srsran::create_udp_gtpu_gateway(const udp_network_gateway_config& config, io_broker& io_brk, - task_executor& io_tx_executor) + task_executor& io_tx_executor, + task_executor& io_rx_executor) { - return std::make_unique(config, io_brk, io_tx_executor); + return std::make_unique(config, io_brk, io_tx_executor, io_rx_executor); } /* ---- No Core version ---- */ diff --git a/lib/ngap/gateways/n2_connection_client_factory.cpp b/lib/ngap/gateways/n2_connection_client_factory.cpp index 671edc479f..5eae9621f3 100644 --- a/lib/ngap/gateways/n2_connection_client_factory.cpp +++ b/lib/ngap/gateways/n2_connection_client_factory.cpp @@ -209,11 +209,14 @@ class ngap_gateway_local_stub final : public n2_connection_client class n2_sctp_gateway_client : public n2_connection_client { public: - n2_sctp_gateway_client(io_broker& broker_, const sctp_network_connector_config& sctp_, dlt_pcap& pcap_) : + n2_sctp_gateway_client(io_broker& broker_, + task_executor& io_rx_executor_, + const sctp_network_connector_config& sctp_, + dlt_pcap& pcap_) : broker(broker_), sctp_cfg(sctp_), pcap_writer(pcap_) { // Create SCTP network adapter. - sctp_gateway = create_sctp_network_client(sctp_network_client_config{sctp_cfg, broker}); + sctp_gateway = create_sctp_network_client(sctp_network_client_config{sctp_cfg, broker, io_rx_executor_}); report_error_if_not(sctp_gateway != nullptr, "Failed to create SCTP gateway client.\n"); } @@ -288,5 +291,5 @@ srsran::srs_cu_cp::create_n2_connection_client(const n2_connection_client_config sctp_cfg.init_max_attempts = nw_mode.init_max_attempts; sctp_cfg.max_init_timeo = nw_mode.max_init_timeo; sctp_cfg.ppid = NGAP_PPID; - return std::make_unique(nw_mode.broker, sctp_cfg, params.pcap); + return std::make_unique(nw_mode.broker, nw_mode.io_rx_executor, sctp_cfg, params.pcap); } diff --git a/lib/support/network/io_broker_epoll.cpp b/lib/support/network/io_broker_epoll.cpp index ffd78ef59b..3392a06a46 100644 --- a/lib/support/network/io_broker_epoll.cpp +++ b/lib/support/network/io_broker_epoll.cpp @@ -19,9 +19,17 @@ using namespace srsran; // TODO: parameterize const unsigned event_queue_size = 32; +/// Tracks the FD that is currently being read in the receive callback. +thread_local int fd_read_in_callback = -1; + +/// Sentinel value used by \c fd_read_in_callback to signal that the FD should not be rearmed. +static constexpr int AVOID_FD_REARMING = -2; + io_broker_epoll::io_broker_epoll(const io_broker_config& config) : logger(srslog::fetch_basic_logger("IO-EPOLL")), event_queue(event_queue_size) { + pending_fds_to_remove.reserve(16); + // Init epoll socket epoll_fd = unique_fd{::epoll_create1(0)}; if (not epoll_fd.is_open()) { @@ -29,7 +37,7 @@ io_broker_epoll::io_broker_epoll(const io_broker_config& config) : } // Register fd and event_handler to handle stops, fd registrations and fd deregistrations. - ctrl_event_fd = unique_fd{::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)}; + auto ctrl_event_fd = unique_fd{::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)}; if (not ctrl_event_fd.is_open()) { report_fatal_error("IO broker: failed to create control event file descriptor. error={}", strerror(errno)); } @@ -37,9 +45,10 @@ io_broker_epoll::io_broker_epoll(const io_broker_config& config) : auto error_handler = [this](error_code code) { logger.error("Error on control event file descriptor. Error code: {}", (int)code); }; - if (not handle_fd_registration(ctrl_event_fd.value(), data_handler, error_handler, nullptr)) { + ctrl_event_raw_fd = ctrl_event_fd.value(); + if (not handle_fd_registration(std::move(ctrl_event_fd), data_handler, error_handler, nullptr, nullptr)) { report_fatal_error("IO broker: failed to register control event file descriptor. ctrl_event_fd={}", - ctrl_event_fd.value()); + ctrl_event_raw_fd); } // start thread to handle epoll events. @@ -59,15 +68,10 @@ io_broker_epoll::~io_broker_epoll() { // Wait for completion. if (thread.running()) { - enqueue_event(control_event{control_event::event_type::close_io_broker, 0, {}, nullptr}); + enqueue_event(control_event{control_event::event_type::close_io_broker, {}, -1, nullptr, {}, {}, nullptr}); thread.join(); } - // Close epoll control event fd. - if (not ctrl_event_fd.close()) { - logger.error("Failed to close control event socket: {}", strerror(errno)); - } - // Close epoll socket. if (not epoll_fd.close()) { logger.error("Failed to close io epoll broker file descriptor: {}", strerror(errno)); @@ -76,14 +80,38 @@ io_broker_epoll::~io_broker_epoll() logger.info("Closed io_broker"); } +void io_broker_epoll::rearm_fd(int fd) +{ + ::epoll_event epoll_ev; + epoll_ev.events = EPOLLIN | EPOLLONESHOT; + epoll_ev.data.fd = fd; + + if (::epoll_ctl(epoll_fd.value(), EPOLL_CTL_MOD, fd, &epoll_ev) == -1) { + logger.error("Failed to rearm file descriptor: {}", fd); + } +} + // Function is executed in a loop until the destructor is called. void io_broker_epoll::thread_loop() { logger.debug("io_broker thread started..."); - while (running) { + + while (true) { + // Process any pending file descriptor removals. + for (auto it = pending_fds_to_remove.begin(); it != pending_fds_to_remove.end();) { + if (auto event_it = event_handler.find(it->first); event_it != event_handler.end()) { + if (not event_it->second.is_executing_recv_callback.load(std::memory_order_acquire)) { + handle_fd_epoll_removal(it->first, true, std::nullopt, it->second); + it = pending_fds_to_remove.erase(it); + continue; + } + } + ++it; + } + // wait for event const int32_t epoll_timeout_ms = -1; - const uint32_t MAX_EVENTS = 1; + const uint32_t MAX_EVENTS = 8; struct epoll_event events[MAX_EVENTS] = {}; int nof_events = ::epoll_wait(epoll_fd.value(), events, MAX_EVENTS, epoll_timeout_ms); @@ -101,7 +129,8 @@ void io_broker_epoll::thread_loop() for (int i = 0; i < nof_events; ++i) { int fd = events[i].data.fd; uint32_t epoll_events = events[i].events; - if ((epoll_events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) || (!(epoll_events & EPOLLIN))) { + + if ((epoll_events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) or not(epoll_events & EPOLLIN)) { error_code code = io_broker::error_code::other; // An error or hang up happened on this file descriptor, or the socket is not ready for reading if (epoll_events & (EPOLLHUP | EPOLLRDHUP)) { @@ -120,25 +149,55 @@ void io_broker_epoll::thread_loop() continue; } - const auto& it = event_handler.find(fd); - if (it != event_handler.end() and it->second.registed_in_epoll()) { + const auto it = event_handler.find(fd); + if (it == event_handler.end() or not it->second.registed_in_epoll()) { + logger.info("fd={}: Ignoring event. Cause: File descriptor handler not found", fd); + continue; + } + + if (fd == ctrl_event_raw_fd) { it->second.read_callback(); - } else { - logger.error("fd={}: Ignoring event. Cause: File descriptor handler not found", fd); + // No rearming needed when the stop command has been executed by the callback. + if (running.load(std::memory_order_relaxed)) { + rearm_fd(fd); + } else { + logger.debug("io_broker thread stopped"); + return; + } + continue; + } + + it->second.is_executing_recv_callback.store(true, std::memory_order_release); + if (not it->second.executor->defer([this, + fd, + callback = &it->second.read_callback, + is_in_callback = &it->second.is_executing_recv_callback]() { + // Track the current FD that is being read by this executor. + fd_read_in_callback = fd; + (*callback)(); + is_in_callback->store(false, std::memory_order_release); + // Avoid rearming this FD if the callback unregistered it. + if (fd_read_in_callback != AVOID_FD_REARMING) { + rearm_fd(fd); + } + fd_read_in_callback = -1; + })) { + rearm_fd(fd); + it->second.is_executing_recv_callback.store(false, std::memory_order_release); + logger.error("Could not enqueue task for processing file descriptor: {}", fd); } } } - logger.debug("io_broker thread stopped"); } -bool io_broker_epoll::enqueue_event(const control_event& event) +bool io_broker_epoll::enqueue_event(control_event&& event) { // Push of an event - event_queue.push_blocking(event); + event_queue.push_blocking(std::move(event)); // trigger epoll event to interrupt possible epoll_wait() uint64_t tmp = 1; - ssize_t ret = ::write(ctrl_event_fd.value(), &tmp, sizeof(tmp)); + ssize_t ret = ::write(ctrl_event_raw_fd, &tmp, sizeof(tmp)); if (ret == -1) { logger.error("Error notifying io CTRL event_fd"); } @@ -149,7 +208,7 @@ void io_broker_epoll::handle_enqueued_events() { // Read from the FD to avoid keep triggering the epoll. uint64_t ignore_counter; - int ignore = ::read(ctrl_event_fd.value(), &ignore_counter, sizeof(ignore_counter)); + int ignore = ::read(ctrl_event_raw_fd, &ignore_counter, sizeof(ignore_counter)); (void)ignore; // Keep popping from the event queue. @@ -159,11 +218,21 @@ void io_broker_epoll::handle_enqueued_events() switch (ev.type) { case control_event::event_type::register_fd: // Register new fd and event handler. - handle_fd_registration(ev.fd, ev.handler, ev.err_handler, ev.completed); + handle_fd_registration(std::move(ev.fd), ev.handler, ev.err_handler, ev.executor, ev.completed); break; case control_event::event_type::deregister_fd: - // Deregister fd and event handler. - handle_fd_epoll_removal(ev.fd, true, std::nullopt, ev.completed); + if (auto it = event_handler.find(ev.raw_fd); it != event_handler.end()) { + // It is safe to directly deregister the FD if we are not reading from it. + if (not it->second.is_executing_recv_callback.load(std::memory_order_acquire)) { + handle_fd_epoll_removal(ev.raw_fd, false, std::nullopt, ev.completed); + break; + } + // Enqueue fd deregistration. + pending_fds_to_remove.emplace_back(ev.raw_fd, ev.completed); + break; + } + // FD may have been already deregistered. + ev.completed->set_value(false); break; case control_event::event_type::close_io_broker: // Close io broker. @@ -175,25 +244,29 @@ void io_broker_epoll::handle_enqueued_events() } } -bool io_broker_epoll::handle_fd_registration(int fd, +bool io_broker_epoll::handle_fd_registration(unique_fd fd, const recv_callback_t& handler, const error_callback_t& err_handler, + task_executor* executor, std::promise* complete_notifier) { - if (event_handler.count(fd) > 0) { - logger.error("fd={}: Failed to register file descriptor. Cause: File descriptor already registered", fd); + if (event_handler.count(fd.value()) > 0) { + logger.error("fd={}: Failed to register file descriptor. Cause: File descriptor already registered", fd.value()); if (complete_notifier != nullptr) { complete_notifier->set_value(false); } return false; } + int raw_fd = fd.value(); + // Add fd to epoll handler. struct epoll_event epoll_ev = {}; - epoll_ev.data.fd = fd; - epoll_ev.events = EPOLLIN; - if (::epoll_ctl(epoll_fd.value(), EPOLL_CTL_ADD, fd, &epoll_ev) == -1) { - logger.error("fd={}: Failed to register file descriptor. Cause: epoll_ctl failed with \"{}\"", fd, strerror(errno)); + epoll_ev.data.fd = raw_fd; + epoll_ev.events = EPOLLIN | EPOLLONESHOT; + if (::epoll_ctl(epoll_fd.value(), EPOLL_CTL_ADD, raw_fd, &epoll_ev) == -1) { + logger.error( + "fd={}: Failed to register file descriptor. Cause: epoll_ctl failed with \"{}\"", raw_fd, strerror(errno)); if (complete_notifier != nullptr) { complete_notifier->set_value(false); } @@ -201,7 +274,10 @@ bool io_broker_epoll::handle_fd_registration(int fd, } // Register the handler of the fd. - event_handler.insert(std::make_pair(fd, fd_handler{handler, err_handler})); + event_handler.emplace(std::piecewise_construct, + std::forward_as_tuple(raw_fd), + std::forward_as_tuple(executor, handler, err_handler, std::move(fd))); + if (complete_notifier != nullptr) { complete_notifier->set_value(true); } @@ -217,7 +293,8 @@ bool io_broker_epoll::handle_fd_epoll_removal(int fd, auto ev_it = event_handler.find(fd); if (ev_it == event_handler.end()) { // File descriptor not found. - // Note: It could have been automatically deregistered by the io broker. + // Note: It could have been automatically deregistered by the io broker and the subscriber could trigger the removal + // on its destruction. logger.error("fd={}: Failed to deregister file descriptor. Cause: File descriptor not found", fd); if (complete_notifier != nullptr) { complete_notifier->set_value(false); @@ -225,43 +302,30 @@ bool io_broker_epoll::handle_fd_epoll_removal(int fd, return false; } - // Regardless of the cause for the call, we always remove the FD from the epoll, so epoll errors won't spam the - // logger, and so that we do not remove the same FD from the epoll more than once. - if (ev_it->second.registed_in_epoll()) { - // In case the cause for the FD removal was an epoll error, forward the error to the event handler. - // Note: We avoid calling the error handling callback in case the FD removal was due to the subscriber - // close/destruction or due to the io_broker being destroyed. - if (epoll_error.has_value()) { - ev_it->second.error_callback(*epoll_error); - } - - // Remove FD from the epoll. - struct epoll_event epoll_ev = {}; - epoll_ev.data.fd = fd; - epoll_ev.events = EPOLLIN; - if (::epoll_ctl(epoll_fd.value(), EPOLL_CTL_DEL, fd, &epoll_ev) == -1) { - logger.error( - "fd={}: Failed to deregister file descriptor. Cause: epoll_ctl failed with \"{}\"", fd, strerror(errno)); - event_handler.erase(ev_it); - if (complete_notifier != nullptr) { - complete_notifier->set_value(false); - } - return false; - } - - // Mark the FD as not registered in the epoll. - // Note: We keep the FD in the lookup table, so we avoid that the frontend points to inexistent FD. - ev_it->second.read_callback = {}; - ev_it->second.error_callback = {}; - logger.debug("fd={}: File descriptor deregistered from epoll interest list", fd); + // In case the cause for the FD removal was an epoll error, forward the error to the event handler. + // Note: We avoid calling the error handling callback in case the FD removal was due to the subscriber + // close/destruction or due to the io_broker being destroyed. + if (epoll_error.has_value()) { + ev_it->second.error_callback(*epoll_error); } - if (io_broker_deregistration_required) { - // In case it was the frontend requesting the deregistration of the FD (e.g. via subscriber destruction), remove - // FD from the lookup as well. This will allow the same FD to be available to be re-registered later. + // Remove FD from the epoll. + struct epoll_event epoll_ev = {}; + epoll_ev.data.fd = fd; + epoll_ev.events = EPOLLIN; + if (::epoll_ctl(epoll_fd.value(), EPOLL_CTL_DEL, fd, &epoll_ev) == -1) { + logger.error( + "fd={}: Failed to deregister file descriptor. Cause: epoll_ctl failed with \"{}\"", fd, strerror(errno)); event_handler.erase(ev_it); + if (complete_notifier != nullptr) { + complete_notifier->set_value(false); + } + return false; } + logger.debug("fd={}: File descriptor deregistered from epoll interest list", fd); + event_handler.erase(ev_it); + // Notify completion of asynchronous task. if (complete_notifier != nullptr) { complete_notifier->set_value(true); @@ -271,21 +335,27 @@ bool io_broker_epoll::handle_fd_epoll_removal(int fd, /// Adds a new file descriptor to the epoll-handler. The call is thread-safe and new /// file descriptors can be added while the epoll_wait() is blocking. -io_broker::subscriber io_broker_epoll::register_fd(int fd, recv_callback_t handler, error_callback_t err_handler) +io_broker::subscriber io_broker_epoll::register_fd(unique_fd fd, + task_executor& executor, + recv_callback_t handler, + error_callback_t err_handler) { - if (fd < 0) { - logger.error("File descriptor registration failed. Cause: Invalid file descriptor value fd={}", fd); + if (not fd.is_open()) { + logger.error("File descriptor registration failed. Cause: Invalid file descriptor value"); return subscriber{}; } + if (not running.load(std::memory_order_relaxed)) { - logger.warning("fd={}: Registration failed. Cause: io_broker is not running", fd); + logger.warning("fd={}: Registration failed. Cause: io_broker is not running", fd.value()); return subscriber{}; } + int raw_fd = fd.value(); + if (std::this_thread::get_id() == thread.get_id()) { // Registration from within the epoll thread. - if (handle_fd_registration(fd, handler, err_handler, nullptr)) { - return subscriber{*this, fd}; + if (handle_fd_registration(std::move(fd), handler, err_handler, nullptr, nullptr)) { + return subscriber{*this, raw_fd}; } return subscriber{}; } @@ -293,47 +363,55 @@ io_broker::subscriber io_broker_epoll::register_fd(int fd, recv_callback_t handl std::promise p; std::future fut = p.get_future(); - enqueue_event(control_event{control_event::event_type::register_fd, fd, handler, err_handler, &p}); + enqueue_event(control_event{ + control_event::event_type::register_fd, std::move(fd), raw_fd, &executor, handler, err_handler, &p}); // Wait for the registration to complete. if (fut.get()) { - logger.info("fd={}: Registered file descriptor successfully", fd); - return subscriber{*this, fd}; + logger.info("fd={}: Registered file descriptor successfully", raw_fd); + return subscriber{*this, raw_fd}; } return subscriber{}; } /// \brief Remove fd from epoll handler. -bool io_broker_epoll::unregister_fd(int fd) +bool io_broker_epoll::unregister_fd(int fd, std::promise* complete_notifier) { if (fd < 0) { logger.error("fd={}: File descriptor deregistration failed. Cause: Invalid file descriptor value", fd); + if (complete_notifier) { + complete_notifier->set_value(false); + } return false; } if (not running.load(std::memory_order_relaxed)) { logger.warning("fd={}: Deregistration failed. Cause: io_broker is not running", fd); + if (complete_notifier) { + complete_notifier->set_value(false); + } return false; } logger.debug("fd={}: Deregistering file descriptor...", fd); - if (std::this_thread::get_id() == thread.get_id()) { - // Deregistration from within the epoll thread. No need to go through the event queue. - return handle_fd_epoll_removal(fd, true, std::nullopt, nullptr); + // Handle the case of calling unregister from the read callback. + if (fd_read_in_callback == fd) { + // No rearming is needed as the FD is going to be being removed and no more callbacks should be called for it. + fd_read_in_callback = AVOID_FD_REARMING; + if (complete_notifier) { + complete_notifier->set_value(true); + complete_notifier = nullptr; + } } - std::promise p; - std::future fut = p.get_future(); - - if (not enqueue_event(control_event{control_event::event_type::deregister_fd, fd, {}, {}, &p})) { + if (not enqueue_event( + control_event{control_event::event_type::deregister_fd, {}, fd, nullptr, {}, {}, complete_notifier})) { + if (complete_notifier) { + complete_notifier->set_value(false); + } return false; } - // Wait for the deregistration to complete. - if (fut.get()) { - logger.info("fd={}: Deregistered file descriptor successfully", fd); - return true; - } - return false; + return true; } void io_broker_epoll::stop_impl() @@ -341,17 +419,42 @@ void io_broker_epoll::stop_impl() // Set flag to stop thread loop. running = false; - // Start by deregistering all existing file descriptors. - for (const auto& it : event_handler) { - handle_fd_epoll_removal(it.first, false, std::nullopt, nullptr); + // Process any pending file descriptor removals. + for (auto it = pending_fds_to_remove.begin(); it != pending_fds_to_remove.end();) { + if (auto event_it = event_handler.find(it->first); event_it != event_handler.end()) { + while (event_it->second.is_executing_recv_callback.load(std::memory_order_acquire)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + handle_fd_epoll_removal(it->first, true, std::nullopt, it->second); + it = pending_fds_to_remove.erase(it); + continue; + } + ++it; } - // Clear event queue. - event_queue.clear(); - - event_handler.erase(ctrl_event_fd.value()); - if (not event_handler.empty()) { + // Check if there are any alive file descriptors apart from the control event file descriptor. + if (event_handler.size() > 1) { logger.warning("File descriptors are still registered during io broker shutdown."); } + + // Deregistering all existing file descriptors. + for (auto it = event_handler.begin(); it != event_handler.end();) { + while (it->second.is_executing_recv_callback.load(std::memory_order_acquire)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + struct epoll_event epoll_ev = {}; + epoll_ev.data.fd = it->first; + epoll_ev.events = EPOLLIN; + if (::epoll_ctl(epoll_fd.value(), EPOLL_CTL_DEL, it->first, &epoll_ev) == -1) { + logger.error("fd={}: Failed to deregister file descriptor. Cause: epoll_ctl failed with \"{}\"", + it->first, + strerror(errno)); + } + it = event_handler.erase(it); + } + + // Clear event queue. + event_queue.clear(); + // Clear event handler map. event_handler.clear(); } diff --git a/lib/support/network/io_broker_epoll.h b/lib/support/network/io_broker_epoll.h index a4135b2322..3a0fe44b6a 100644 --- a/lib/support/network/io_broker_epoll.h +++ b/lib/support/network/io_broker_epoll.h @@ -15,6 +15,7 @@ #include "srsran/support/io/unique_fd.h" #include #include +#include namespace srsran { @@ -25,42 +26,59 @@ class io_broker_epoll final : public io_broker explicit io_broker_epoll(const io_broker_config& config); ~io_broker_epoll() override; - [[nodiscard]] subscriber register_fd(int fd, recv_callback_t handler, error_callback_t err_handler) override; + [[nodiscard]] subscriber + register_fd(unique_fd fd, task_executor& executor, recv_callback_t handler, error_callback_t err_handler) override; private: - // Event enqueued to be handled in the io_broker thread. + /// Event enqueued to be handled in the io_broker thread. struct control_event { enum class event_type { close_io_broker, register_fd, deregister_fd } type; - int fd; + unique_fd fd; + int raw_fd; + task_executor* executor = nullptr; recv_callback_t handler; error_callback_t err_handler; - std::promise* completed; + std::promise* completed = nullptr; }; - // Event handler for a file descriptor. + /// Event handler for a file descriptor. struct fd_handler { - recv_callback_t read_callback; - error_callback_t error_callback; + fd_handler(task_executor* executor_, + recv_callback_t read_callback_, + error_callback_t error_callback_, + unique_fd fd_) : + executor(executor_), + read_callback(std::move(read_callback_)), + error_callback(std::move(error_callback_)), + fd(std::move(fd_)) + { + } + + task_executor* executor; + recv_callback_t read_callback; + error_callback_t error_callback; + std::atomic is_executing_recv_callback{false}; + unique_fd fd; // Determines whether the io_broker has deregistered the event handler from the epoll. bool registed_in_epoll() const { return static_cast(read_callback); } }; - // Note: Blocking function. - [[nodiscard]] bool unregister_fd(int fd) override; + [[nodiscard]] bool unregister_fd(int fd, std::promise* complete_notifier) override; void thread_loop(); // Enqueues event to be asynchronously processed by the epoll thread. - bool enqueue_event(const control_event& event); + bool enqueue_event(control_event&& event); // Handle events stored in the ctrl event queue. void handle_enqueued_events(); // Handle the registration of a new file descriptor. - bool handle_fd_registration(int fd, + bool handle_fd_registration(unique_fd fd, const recv_callback_t& callback, const error_callback_t& err_handler, + task_executor* executor, std::promise* complete_notifier); // Handle the deregistration of an existing file descriptor. @@ -71,13 +89,15 @@ class io_broker_epoll final : public io_broker void stop_impl(); + void rearm_fd(int fd); + srslog::basic_logger& logger; // Main epoll file descriptor unique_fd epoll_fd; // Event file descriptor used to interrupt epoll_wait call when a stop, fd registration, or fd deregistration is // requested. - unique_fd ctrl_event_fd; + int ctrl_event_raw_fd = -1; // Lookup table mapping file descriptors to handlers. std::unordered_map event_handler; @@ -87,6 +107,9 @@ class io_broker_epoll final : public io_broker std::atomic running{true}; unique_thread thread; + + // File descriptors pending to be removed. + std::vector*>> pending_fds_to_remove; }; } // namespace srsran diff --git a/lib/support/network/io_broker_factory.cpp b/lib/support/network/io_broker_factory.cpp index d88d82b1e7..e7fa208e2f 100644 --- a/lib/support/network/io_broker_factory.cpp +++ b/lib/support/network/io_broker_factory.cpp @@ -13,7 +13,7 @@ using namespace srsran; -std::unique_ptr srsran::create_io_broker(io_broker_type type, io_broker_config config) +std::unique_ptr srsran::create_io_broker(io_broker_type type, const io_broker_config& config) { switch (type) { case io_broker_type::epoll: diff --git a/lib/support/network/io_timer_source.cpp b/lib/support/network/io_timer_source.cpp index e7dc1b2794..2c88dc0d26 100644 --- a/lib/support/network/io_timer_source.cpp +++ b/lib/support/network/io_timer_source.cpp @@ -17,30 +17,31 @@ using namespace srsran; -io_timer_source::io_timer_source(timer_manager& tick_sink_, io_broker& broker, std::chrono::milliseconds tick_period) : +io_timer_source::io_timer_source(timer_manager& tick_sink_, + io_broker& broker, + task_executor& executor, + std::chrono::milliseconds tick_period) : tick_sink(tick_sink_), logger(srslog::fetch_basic_logger("IO-EPOLL")) { using namespace std::chrono; - timer_fd = unique_fd{::timerfd_create(CLOCK_MONOTONIC, 0)}; - if (not timer_fd.is_open()) { - report_fatal_error_if_not("Failed to create timer source (errno={})", strerror(errno)); - } + auto timer_fd = unique_fd{::timerfd_create(CLOCK_MONOTONIC, 0)}; + report_fatal_error_if_not(timer_fd.is_open(), "Failed to create timer source (errno={})", ::strerror(errno)); - auto tsecs = duration_cast(tick_period); - auto tnsecs = duration_cast(tick_period) - duration_cast(tsecs); - struct timespec period = {tsecs.count(), tnsecs.count()}; - struct itimerspec timerspec = {period, period}; + auto tsecs = duration_cast(tick_period); + auto tnsecs = duration_cast(tick_period) - duration_cast(tsecs); + ::timespec period = {tsecs.count(), tnsecs.count()}; + ::itimerspec timerspec = {period, period}; ::timerfd_settime(timer_fd.value(), 0, &timerspec, nullptr); - io_sub = broker.register_fd( - timer_fd.value(), [this]() { read_time(); }, [this](io_broker::error_code ev) { io_sub.reset(); }); + io_sub = broker.register_fd(std::move(timer_fd), executor, [this]() { read_time(); }); + report_fatal_error_if_not(io_sub.value() > 0, "Failed to create timer source"); } void io_timer_source::read_time() { char read_buffer[8]; - int n = ::read(timer_fd.value(), read_buffer, sizeof(read_buffer)); + int n = ::read(io_sub.value(), read_buffer, sizeof(read_buffer)); if (n < 0) { logger.error("Failed to read timerfd (errno={})", ::strerror(errno)); return; diff --git a/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp b/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp index e54fec1300..755e31325a 100644 --- a/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp +++ b/tests/benchmarks/gateways/udp_network_gateway_benchmark.cpp @@ -11,6 +11,7 @@ #include "udp_network_gateway_benchmark_helpers.h" #include "srsran/gateways/udp_network_gateway_factory.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include @@ -100,10 +101,11 @@ int main(int argc, char** argv) std::unique_ptr gw1; std::unique_ptr gw2; - manual_task_worker io_tx_executor{128}; + inline_task_executor io_rx_executor; + manual_task_worker io_tx_executor{128}; - gw1 = create_udp_network_gateway({gw1_cfg, gw1_dn, io_tx_executor}); - gw2 = create_udp_network_gateway({gw2_cfg, gw2_dn, io_tx_executor}); + gw1 = create_udp_network_gateway({gw1_cfg, gw1_dn, io_tx_executor, io_rx_executor}); + gw2 = create_udp_network_gateway({gw2_cfg, gw2_dn, io_tx_executor, io_rx_executor}); gw1->create_and_bind(); gw2->create_and_bind(); diff --git a/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp b/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp index a8951b285d..cdbdfbbb7e 100644 --- a/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp +++ b/tests/benchmarks/gateways/udp_network_gateway_rx_benchmark.cpp @@ -14,11 +14,11 @@ #include "udp_network_gateway_benchmark_helpers.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include #include -#include using namespace srsran; @@ -90,9 +90,10 @@ int main(int argc, char** argv) dummy_network_gateway_data_notifier_with_src_addr gw_dn{params.slow_inter_rx_us, params.nof_pdus}; std::unique_ptr gw; - manual_task_worker io_tx_executor{128}; + inline_task_executor io_rx_executor; + manual_task_worker io_tx_executor{128}; - gw = create_udp_network_gateway({gw_cfg, gw_dn, io_tx_executor}); + gw = create_udp_network_gateway({gw_cfg, gw_dn, io_tx_executor, io_rx_executor}); gw->create_and_bind(); std::unique_ptr epoll_broker; diff --git a/tests/benchmarks/gateways/udp_network_gateway_tx_benchmark.cpp b/tests/benchmarks/gateways/udp_network_gateway_tx_benchmark.cpp index 59a512bd7f..a5606e24ef 100644 --- a/tests/benchmarks/gateways/udp_network_gateway_tx_benchmark.cpp +++ b/tests/benchmarks/gateways/udp_network_gateway_tx_benchmark.cpp @@ -1,3 +1,4 @@ + /* * * Copyright 2021-2024 Software Radio Systems Limited @@ -11,10 +12,10 @@ #include "udp_network_gateway_benchmark_helpers.h" #include "srsran/gateways/udp_network_gateway_factory.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include #include -#include using namespace srsran; @@ -72,9 +73,10 @@ int main(int argc, char** argv) std::unique_ptr gw1; std::unique_ptr gw2; - manual_task_worker io_tx_executor{128}; + inline_task_executor io_rx_executor; + manual_task_worker io_tx_executor{128}; - gw1 = create_udp_network_gateway({gw1_cfg, gw1_dn, io_tx_executor}); + gw1 = create_udp_network_gateway({gw1_cfg, gw1_dn, io_tx_executor, io_rx_executor}); gw1->create_and_bind(); diff --git a/tests/integrationtests/e2ap/e2ap_integration_test.cpp b/tests/integrationtests/e2ap/e2ap_integration_test.cpp index ac3bfa712d..3bd409582d 100644 --- a/tests/integrationtests/e2ap/e2ap_integration_test.cpp +++ b/tests/integrationtests/e2ap/e2ap_integration_test.cpp @@ -16,9 +16,8 @@ #include "srsran/e2/gateways/e2_network_client_factory.h" #include "srsran/gateways/sctp_network_gateway_factory.h" #include "srsran/support/async/async_test_utils.h" -#include "srsran/support/executors/manual_task_worker.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/io/io_broker_factory.h" -#include "srsran/support/test_utils.h" #include "srsran/support/timers.h" #include @@ -37,7 +36,7 @@ class dummy_e2ap_network_adapter : public e2_message_notifier, dummy_e2ap_network_adapter(const sctp_network_connector_config& nw_config_) : nw_config(nw_config_), epoll_broker(create_io_broker(io_broker_type::epoll)), - gw(create_sctp_network_gateway({nw_config, *this, *this})), + gw(create_sctp_network_gateway({nw_config, *this, *this, executor})), packer(*gw, *this, pcap) { report_fatal_error_if_not(gw->create_and_connect(), "Failed to connect E2 GW"); @@ -47,8 +46,6 @@ class dummy_e2ap_network_adapter : public e2_message_notifier, } } - ~dummy_e2ap_network_adapter() {} - void connect_e2ap(e2_interface* e2ap_) { e2ap = e2ap_; } e2_message last_e2_msg; @@ -77,6 +74,7 @@ class dummy_e2ap_network_adapter : public e2_message_notifier, /// We require a network gateway and a packer const sctp_network_connector_config& nw_config; + inline_task_executor executor; std::unique_ptr epoll_broker; std::unique_ptr gw; e2ap_asn1_packer packer; @@ -188,18 +186,19 @@ class e2ap_gw_connector_integration_test : public ::testing::Test nw_config.bind_address = "127.0.0.101"; nw_config.bind_port = 0; - epoll_broker = create_io_broker(io_broker_type::epoll); - factory = timer_factory{timers, ctrl_worker}; - pcap = std::make_unique(); - du_metrics = std::make_unique(); - f1ap_ue_id_mapper = std::make_unique(); - e2_client = create_e2_gateway_client(e2_sctp_gateway_config{nw_config, *epoll_broker, *pcap}); + epoll_broker = create_io_broker(io_broker_type::epoll); + factory = timer_factory{timers, ctrl_worker}; + pcap = std::make_unique(); + du_metrics = std::make_unique(); + f1ap_ue_id_mapper = std::make_unique(); + e2_client = create_e2_gateway_client(e2_sctp_gateway_config{nw_config, *epoll_broker, rx_executor, *pcap}); du_param_configurator = std::make_unique(); e2agent = create_e2_du_agent( cfg, *e2_client, &(*du_metrics), &(*f1ap_ue_id_mapper), &(*du_param_configurator), factory, ctrl_worker); } e2ap_configuration cfg; + inline_task_executor rx_executor; std::unique_ptr epoll_broker; timer_manager timers; manual_task_worker ctrl_worker{128}; diff --git a/tests/integrationtests/ngap/ngap_integration_test.cpp b/tests/integrationtests/ngap/ngap_integration_test.cpp index 3e039b3560..4dfe3e85a8 100644 --- a/tests/integrationtests/ngap/ngap_integration_test.cpp +++ b/tests/integrationtests/ngap/ngap_integration_test.cpp @@ -9,7 +9,6 @@ */ #include "lib/cu_cp/ue_manager/ue_manager_impl.h" -#include "lib/ngap/ngap_asn1_helpers.h" #include "lib/ngap/ngap_error_indication_helper.h" #include "tests/unittests/ngap/test_helpers.h" #include "srsran/cu_cp/cu_cp_configuration_helpers.h" @@ -17,6 +16,7 @@ #include "srsran/ngap/ngap_configuration_helpers.h" #include "srsran/ngap/ngap_factory.h" #include "srsran/support/async/async_test_utils.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include "srsran/support/timers.h" @@ -37,7 +37,7 @@ class ngap_network_adapter : public n2_connection_client, ngap_network_adapter(const sctp_network_connector_config& nw_config_) : nw_config(nw_config_), epoll_broker(create_io_broker(io_broker_type::epoll)), - gw(create_sctp_network_gateway({nw_config, *this, *this})) + gw(create_sctp_network_gateway({nw_config, *this, *this, rx_executor})) { report_fatal_error_if_not(gw->create_and_connect(), "Failed to connect NGAP GW"); if (!gw->subscribe_to(*epoll_broker)) { @@ -63,7 +63,7 @@ class ngap_network_adapter : public n2_connection_client, return; } } - parent.gw->handle_pdu(std::move(pdu)); + parent.gw->handle_pdu(pdu); } private: @@ -95,6 +95,7 @@ class ngap_network_adapter : public n2_connection_client, /// We require a network gateway and a packer const sctp_network_connector_config& nw_config; + inline_task_executor rx_executor; std::unique_ptr epoll_broker; std::unique_ptr gw; diff --git a/tests/unittests/cu_up/cu_up_test.cpp b/tests/unittests/cu_up/cu_up_test.cpp index cbae0fd8c8..00b0c5f449 100644 --- a/tests/unittests/cu_up/cu_up_test.cpp +++ b/tests/unittests/cu_up/cu_up_test.cpp @@ -17,10 +17,8 @@ #include "srsran/support/io/io_broker_factory.h" #include #include -#include #include #include -#include #include using namespace srsran; @@ -92,7 +90,7 @@ class cu_up_test : public ::testing::Test srslog::fetch_basic_logger("GTPU").set_level(srslog::basic_levels::debug); srslog::fetch_basic_logger("E1AP").set_level(srslog::basic_levels::debug); - // create worker thread and executer + // create worker thread and executor worker = std::make_unique("thread", 128, os_thread_realtime_priority::no_realtime()); executor = make_task_executor_ptr(*worker); @@ -128,7 +126,7 @@ class cu_up_test : public ::testing::Test deps.exec_mapper = exec_pool.get(); deps.e1_conn_client = &e1ap_client; deps.f1u_gateway = f1u_gw.get(); - ngu_gw = create_udp_gtpu_gateway(cu_up_udp_cfg, *broker, *executor); + ngu_gw = create_udp_gtpu_gateway(cu_up_udp_cfg, *broker, *executor, *executor); deps.ngu_gws.push_back(ngu_gw.get()); deps.timers = app_timers.get(); return deps; diff --git a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp index 517e84180b..bb29463457 100644 --- a/tests/unittests/e1ap/gateways/e1_gateway_test.cpp +++ b/tests/unittests/e1ap/gateways/e1_gateway_test.cpp @@ -15,6 +15,7 @@ #include "srsran/e1ap/common/e1ap_message.h" #include "srsran/e1ap/gateways/e1_local_connector_factory.h" #include "srsran/pcap/dlt_pcap.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/io/io_broker_factory.h" #include #include @@ -66,7 +67,7 @@ class e1_link : public srs_cu_cp::cu_cp_e1_handler if (use_sctp) { broker = create_io_broker(io_broker_type::epoll); - connector = create_e1_local_connector(e1_local_sctp_connector_config{pcap, *broker}); + connector = create_e1_local_connector(e1_local_sctp_connector_config{pcap, *broker, rx_executor}); } else { connector = create_e1_local_connector(e1_local_connector_config{pcap}); } @@ -91,6 +92,7 @@ class e1_link : public srs_cu_cp::cu_cp_e1_handler return std::make_unique("CU-CP", cu_rx_pdus, std::move(eof_signal)); } + inline_task_executor rx_executor; std::unique_ptr broker; dummy_dlt_pcap pcap; std::unique_ptr connector; diff --git a/tests/unittests/e2/dummy_ric.cpp b/tests/unittests/e2/dummy_ric.cpp index 74b4f74cdc..432d13e770 100644 --- a/tests/unittests/e2/dummy_ric.cpp +++ b/tests/unittests/e2/dummy_ric.cpp @@ -98,7 +98,8 @@ class ric_sctp_server final : public e2_connection_server, public sctp_network_a ric_sctp_server(const ric_sctp_gateway_config& params_) : params(params_) { // Create SCTP server. - sctp_server = create_sctp_network_server(sctp_network_server_config{params.sctp, params.broker, *this}); + sctp_server = create_sctp_network_server( + sctp_network_server_config{params.sctp, params.broker, params.io_rx_executor, *this}); } void attach_ric(ric_e2_handler& ric_) override diff --git a/tests/unittests/e2/dummy_ric.h b/tests/unittests/e2/dummy_ric.h index aff086f9bc..a3220c671c 100644 --- a/tests/unittests/e2/dummy_ric.h +++ b/tests/unittests/e2/dummy_ric.h @@ -26,6 +26,8 @@ struct ric_sctp_gateway_config { sctp_network_gateway_config sctp; /// IO broker responsible for handling SCTP Rx data and notifications. io_broker& broker; + /// Execution context used to process received SCTP packets. + task_executor& io_rx_executor; /// PCAP writer for the E2AP messages. dlt_pcap& pcap; /// Sniffer that receives a copy of a received E2 message. @@ -97,4 +99,4 @@ class near_rt_ric e2_agent_repository e2_agents; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/e2/e2ap_network_adapter_test.cpp b/tests/unittests/e2/e2ap_network_adapter_test.cpp index 3b0d7f0997..65238fcad9 100644 --- a/tests/unittests/e2/e2ap_network_adapter_test.cpp +++ b/tests/unittests/e2/e2ap_network_adapter_test.cpp @@ -19,6 +19,7 @@ #include "srsran/gateways/sctp_network_gateway_factory.h" #include "srsran/gateways/sctp_network_server_factory.h" #include "srsran/support/async/async_test_utils.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include "srsran/support/timers.h" @@ -51,7 +52,7 @@ class e2ap_network_adapter_test : public ::testing::Test // simulate RIC side ric_rx_e2_sniffer = std::make_unique(*this); ric_pcap = std::make_unique(); - ric_sctp_gateway_config ric_server_sctp_cfg{{}, *ric_broker, *ric_pcap}; + ric_sctp_gateway_config ric_server_sctp_cfg{{}, *ric_broker, rx_executor, *ric_pcap}; ric_server_sctp_cfg.sctp.if_name = "E2"; ric_server_sctp_cfg.sctp.ppid = NGAP_PPID; ric_server_sctp_cfg.sctp.bind_address = "127.0.0.1"; @@ -78,8 +79,8 @@ class e2ap_network_adapter_test : public ::testing::Test cfg = config_helpers::make_default_e2ap_config(); cfg.e2sm_kpm_enabled = true; - pcap = std::make_unique(); - e2_client = create_e2_gateway_client(e2_sctp_gateway_config{e2agent_config, *agent_broker, *pcap}); + pcap = std::make_unique(); + e2_client = create_e2_gateway_client(e2_sctp_gateway_config{e2agent_config, *agent_broker, rx_executor, *pcap}); e2_client_wrapper = std::make_unique(*e2_client); du_metrics = std::make_unique(); du_meas_provider = std::make_unique(); @@ -125,7 +126,7 @@ class e2ap_network_adapter_test : public ::testing::Test class e2_connection_client_wrapper : public e2_connection_client { public: - e2_connection_client_wrapper(e2_connection_client& e2_client_) : e2_client(e2_client_){}; + e2_connection_client_wrapper(e2_connection_client& e2_client_) : e2_client(e2_client_) {} void on_e2_message_rx(const e2_message& msg) { @@ -170,7 +171,7 @@ class e2ap_network_adapter_test : public ::testing::Test class e2_sniffer : public e2_message_notifier { public: - e2_sniffer(e2ap_network_adapter_test& parent_) : logger(srslog::fetch_basic_logger("E2")){}; + e2_sniffer(e2ap_network_adapter_test& parent_) : logger(srslog::fetch_basic_logger("E2")) {} /// E2 message handler functions. void on_new_message(const e2_message& msg) override @@ -180,7 +181,7 @@ class e2ap_network_adapter_test : public ::testing::Test e2_msg_queue.push_back(msg); } rx_cvar.notify_one(); - }; + } expected get_last_e2_msg(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds(5000)) { @@ -201,6 +202,7 @@ class e2ap_network_adapter_test : public ::testing::Test std::list e2_msg_queue; }; + inline_task_executor rx_executor; std::unique_ptr ric_broker; std::unique_ptr agent_broker; std::unique_ptr assoc_factory; diff --git a/tests/unittests/f1ap/gateways/f1c_gateway_test.cpp b/tests/unittests/f1ap/gateways/f1c_gateway_test.cpp index 3839fb27ca..0ad66be325 100644 --- a/tests/unittests/f1ap/gateways/f1c_gateway_test.cpp +++ b/tests/unittests/f1ap/gateways/f1c_gateway_test.cpp @@ -15,9 +15,11 @@ #include "srsran/f1ap/f1ap_message.h" #include "srsran/f1ap/gateways/f1c_local_connector_factory.h" #include "srsran/pcap/dlt_pcap.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/io/io_broker_factory.h" #include #include +#include using namespace srsran; @@ -28,10 +30,10 @@ class dummy_dlt_pcap final : public dlt_pcap bool closed = false; blocking_queue last_sdus{16}; - void close() override { closed = true; } - bool is_write_enabled() const override { return enabled; } - void push_pdu(const_span pdu) override { last_sdus.push_blocking(byte_buffer::create(pdu).value()); } - virtual void push_pdu(byte_buffer pdu) override { last_sdus.push_blocking(std::move(pdu)); } + void close() override { closed = true; } + bool is_write_enabled() const override { return enabled; } + void push_pdu(const_span pdu) override { last_sdus.push_blocking(byte_buffer::create(pdu).value()); } + void push_pdu(byte_buffer pdu) override { last_sdus.push_blocking(std::move(pdu)); } }; class f1c_link : public srs_cu_cp::cu_cp_f1c_handler @@ -40,13 +42,12 @@ class f1c_link : public srs_cu_cp::cu_cp_f1c_handler class rx_pdu_notifier : public f1ap_message_notifier { public: - rx_pdu_notifier(const std::string& name_, - blocking_queue& rx_pdus_, - std::promise eof_received_) : - name(name_), rx_pdus(rx_pdus_), eof_received(std::move(eof_received_)) + rx_pdu_notifier(std::string name_, blocking_queue& rx_pdus_, std::promise eof_received_) : + name(std::move(name_)), rx_pdus(rx_pdus_), eof_received(std::move(eof_received_)) { } - ~rx_pdu_notifier() + + ~rx_pdu_notifier() override { eof_received.set_value(); logger.info("{}: RX PDU notifier destroyed", name); @@ -66,7 +67,7 @@ class f1c_link : public srs_cu_cp::cu_cp_f1c_handler if (use_sctp) { broker = create_io_broker(io_broker_type::epoll); - connector = create_f1c_local_connector(f1c_local_sctp_connector_config{pcap, *broker}); + connector = create_f1c_local_connector(f1c_local_sctp_connector_config{pcap, *broker, inline_executor}); } else { connector = create_f1c_local_connector(f1c_local_connector_config{pcap}); } @@ -91,6 +92,7 @@ class f1c_link : public srs_cu_cp::cu_cp_f1c_handler return std::make_unique("CU-CP", cu_rx_pdus, std::move(eof_signal)); } + inline_task_executor inline_executor; std::unique_ptr broker; dummy_dlt_pcap pcap; std::unique_ptr connector; diff --git a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp index ef296df8b5..6979342c9d 100644 --- a/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_cu_split_connector_test.cpp @@ -13,6 +13,7 @@ #include "srsran/gateways/udp_network_gateway_factory.h" #include "srsran/gtpu/gtpu_demux_factory.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include @@ -115,7 +116,7 @@ class f1u_cu_split_connector_test : public ::testing::Test tester_config.bind_address = "127.0.0.2"; tester_config.bind_port = 0; tester_config.non_blocking_mode = true; - udp_tester = create_udp_network_gateway({tester_config, server_data_notifier, io_tx_executor}); + udp_tester = create_udp_network_gateway({tester_config, server_data_notifier, io_tx_executor, rx_executor}); ASSERT_TRUE(udp_tester->create_and_bind()); std::optional tester_bind_port = udp_tester->get_bind_port(); ASSERT_TRUE(tester_bind_port.has_value()); @@ -131,7 +132,7 @@ class f1u_cu_split_connector_test : public ::testing::Test nru_gw_config.bind_address = cu_gw_bind_address; nru_gw_config.bind_port = 0; nru_gw_config.reuse_addr = true; - udp_gw = create_udp_gtpu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); + udp_gw = create_udp_gtpu_gateway(nru_gw_config, *epoll_broker, io_tx_executor, rx_executor); f1u_cu_up_split_gateway_creation_msg cu_create_msg{ *udp_gw, *demux, dummy_pcap, tester_bind_port.value(), get_external_bind_address()}; @@ -195,6 +196,7 @@ class f1u_cu_split_connector_test : public ::testing::Test virtual std::string get_external_bind_address() { return "auto"; } + inline_task_executor rx_executor; manual_task_worker ue_worker{128}; std::unique_ptr epoll_broker; manual_task_worker io_tx_executor{128}; diff --git a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp index c3214d6a95..24172d9d58 100644 --- a/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp +++ b/tests/unittests/f1u/common/f1u_du_split_connector_test.cpp @@ -13,6 +13,7 @@ #include "srsran/gateways/udp_network_gateway_factory.h" #include "srsran/gtpu/gtpu_demux_factory.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include @@ -95,7 +96,7 @@ class f1u_du_split_connector_test : public ::testing::Test tester_config.bind_address = "127.0.0.1"; tester_config.bind_port = 0; tester_config.non_blocking_mode = true; - udp_tester = create_udp_network_gateway({tester_config, server_data_notifier, io_tx_executor}); + udp_tester = create_udp_network_gateway({tester_config, server_data_notifier, io_tx_executor, rx_executor}); ASSERT_TRUE(udp_tester->create_and_bind()); std::optional tester_bind_port = udp_tester->get_bind_port(); ASSERT_TRUE(tester_bind_port.has_value()); @@ -111,7 +112,7 @@ class f1u_du_split_connector_test : public ::testing::Test nru_gw_config.bind_address = du_gw_bind_address; nru_gw_config.bind_port = 0; nru_gw_config.reuse_addr = true; - udp_gw = create_udp_gtpu_gateway(nru_gw_config, *epoll_broker, io_tx_executor); + udp_gw = create_udp_gtpu_gateway(nru_gw_config, *epoll_broker, io_tx_executor, rx_executor); f1u_du_split_gateway_creation_msg cu_create_msg{ udp_gw.get(), demux.get(), dummy_pcap, tester_bind_port.value(), get_external_bind_address()}; @@ -182,6 +183,7 @@ class f1u_du_split_connector_test : public ::testing::Test virtual std::string get_external_bind_address() { return "auto"; } timer_manager timer_mng; + inline_task_executor rx_executor; manual_task_worker ue_worker{128}; timer_factory timers; unique_timer ue_inactivity_timer; diff --git a/tests/unittests/gateways/sctp_network_client_test.cpp b/tests/unittests/gateways/sctp_network_client_test.cpp index 87d9e4465f..2eced5054a 100644 --- a/tests/unittests/gateways/sctp_network_client_test.cpp +++ b/tests/unittests/gateways/sctp_network_client_test.cpp @@ -10,6 +10,7 @@ #include "sctp_test_helpers.h" #include "srsran/gateways/sctp_network_client_factory.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/unique_thread.h" #include "srsran/support/io/sctp_socket.h" #include @@ -28,7 +29,7 @@ class sctp_recv_notifier_factory { public: dummy_sctp_recv_notifier(sctp_recv_notifier_factory& parent_) : parent(parent_) {} - ~dummy_sctp_recv_notifier() { parent.destroyed = true; } + ~dummy_sctp_recv_notifier() override { parent.destroyed = true; } bool on_new_sdu(byte_buffer sdu) override { @@ -78,7 +79,7 @@ class sctp_network_client_test : public ::testing::Test client_cfg.sctp.ppid = NGAP_PPID; } - ~sctp_network_client_test() + ~sctp_network_client_test() override { close_client(); srslog::flush(); @@ -122,8 +123,9 @@ class sctp_network_client_test : public ::testing::Test } protected: + inline_task_executor io_rx_executor; dummy_io_broker broker; - sctp_network_client_config client_cfg{{.if_name = "client"}, broker}; + sctp_network_client_config client_cfg{{.if_name = "client"}, broker, io_rx_executor}; sctp_recv_notifier_factory recv_notifier_factory; @@ -162,7 +164,7 @@ TEST_F(sctp_network_client_test, when_server_does_not_exist_then_connection_fail client = create_sctp_network_client(client_cfg); ASSERT_FALSE(connect_to_server("127.0.0.2", server.bind_port)); - ASSERT_EQ(broker.last_registered_fd, -1); + ASSERT_EQ(broker.last_registered_fd.value(), -1); ASSERT_EQ(client_sender, nullptr); ASSERT_EQ(broker.last_unregistered_fd, -1); } @@ -173,7 +175,7 @@ TEST_F(sctp_network_client_test, when_broker_rejects_subscriber_then_connect_fai client = create_sctp_network_client(client_cfg); ASSERT_FALSE(connect_to_server(server.address, server.bind_port)); - ASSERT_GE(broker.last_registered_fd, 0); + ASSERT_GE(broker.last_registered_fd.value(), 0); ASSERT_EQ(broker.last_unregistered_fd, -1) << "If the subscription fails, no deregister should be called"; } @@ -182,7 +184,7 @@ TEST_F(sctp_network_client_test, when_server_exists_then_connection_succeeds) client = create_sctp_network_client(client_cfg); ASSERT_TRUE(connect_to_server(server.address, server.bind_port)); - ASSERT_EQ(broker.last_registered_fd, client->get_socket_fd()); + ASSERT_EQ(broker.last_registered_fd.value(), client->get_socket_fd()); ASSERT_NE(client_sender, nullptr); ASSERT_EQ(broker.last_unregistered_fd, -1); diff --git a/tests/unittests/gateways/sctp_network_gateway_test.cpp b/tests/unittests/gateways/sctp_network_gateway_test.cpp index 8608d8a601..4cab3a3350 100644 --- a/tests/unittests/gateways/sctp_network_gateway_test.cpp +++ b/tests/unittests/gateways/sctp_network_gateway_test.cpp @@ -10,6 +10,7 @@ #include "test_helpers.h" #include "srsran/gateways/sctp_network_gateway_factory.h" +#include "srsran/support/executors/inline_task_executor.h" #include #include #include @@ -42,13 +43,15 @@ class sctp_network_gateway_tester : public ::testing::Test void create_server(const sctp_network_connector_config& server_config) { - server = create_sctp_network_gateway({server_config, server_control_notifier, server_data_notifier}); + server = + create_sctp_network_gateway({server_config, server_control_notifier, server_data_notifier, io_rx_executor}); ASSERT_NE(server, nullptr); } void create_client(const sctp_network_connector_config& client_config) { - client = create_sctp_network_gateway({client_config, client_control_notifier, client_data_notifier}); + client = + create_sctp_network_gateway({client_config, client_control_notifier, client_data_notifier, io_rx_executor}); ASSERT_NE(client, nullptr); } @@ -94,8 +97,9 @@ class sctp_network_gateway_tester : public ::testing::Test std::unique_ptr server, client; private: - std::thread rx_thread; - std::atomic stop_token = {false}; + inline_task_executor io_rx_executor; + std::thread rx_thread; + std::atomic stop_token = {false}; }; TEST_F(sctp_network_gateway_tester, when_binding_on_bogus_address_then_bind_fails) diff --git a/tests/unittests/gateways/sctp_network_link_test.cpp b/tests/unittests/gateways/sctp_network_link_test.cpp index 01cc73c046..5c6d2a94e6 100644 --- a/tests/unittests/gateways/sctp_network_link_test.cpp +++ b/tests/unittests/gateways/sctp_network_link_test.cpp @@ -12,6 +12,7 @@ #include "srsran/gateways/sctp_network_client_factory.h" #include "srsran/gateways/sctp_network_server_factory.h" #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/io/io_broker_factory.h" #include #include @@ -31,7 +32,7 @@ class base_sctp_network_link_test client_broker(create_io_broker(srsran::io_broker_type::epoll)), assoc_factory(std::make_unique(*this)), server_cfg([this]() { - sctp_network_server_config cfg{{}, *server_broker, *assoc_factory}; + sctp_network_server_config cfg{{}, *server_broker, rx_executor, *assoc_factory}; cfg.sctp.if_name = "SERVER"; cfg.sctp.ppid = NGAP_PPID; cfg.sctp.bind_address = "127.0.0.1"; @@ -52,7 +53,7 @@ class base_sctp_network_link_test report_fatal_error_if_not(ret.second, "Failed to insert Client Association"); // Create client. - sctp_network_client_config client_cfg{{}, *client_broker}; + sctp_network_client_config client_cfg{{}, *client_broker, rx_executor}; client_cfg.sctp.if_name = fmt::format("client{}", i); client_cfg.sctp.ppid = NGAP_PPID; ret.first->second->client = create_sctp_network_client(client_cfg); @@ -152,6 +153,7 @@ class base_sctp_network_link_test } srslog::basic_logger& logger; + inline_task_executor rx_executor; std::unique_ptr server_broker; std::unique_ptr client_broker; std::unique_ptr assoc_factory; @@ -183,7 +185,7 @@ class sctp_network_link_test : public base_sctp_network_link_test, public ::test { public: sctp_network_link_test() : base_sctp_network_link_test(GetParam().nof_clients) {} - ~sctp_network_link_test() { srslog::flush(); } + ~sctp_network_link_test() override { srslog::flush(); } }; static byte_buffer create_data(unsigned start_val, unsigned nof_vals) diff --git a/tests/unittests/gateways/sctp_network_server_test.cpp b/tests/unittests/gateways/sctp_network_server_test.cpp index 0a31b86a3a..1ae3663069 100644 --- a/tests/unittests/gateways/sctp_network_server_test.cpp +++ b/tests/unittests/gateways/sctp_network_server_test.cpp @@ -10,6 +10,7 @@ #include "sctp_test_helpers.h" #include "srsran/gateways/sctp_network_server_factory.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/io/sctp_socket.h" #include #include @@ -30,7 +31,8 @@ class association_factory : public sctp_network_association_factory parent(parent_), send_notifier(send_notifier_) { } - ~dummy_sctp_recv_notifier() + + ~dummy_sctp_recv_notifier() override { for (auto& sender : parent.association_senders) { if (sender.get() == send_notifier) { @@ -166,8 +168,9 @@ class sctp_network_server_test : public base_sctp_network_test, public ::testing void trigger_broker() { broker.handle_receive(); } - sctp_network_server_config server_cfg{{}, broker, assoc_factory}; + sctp_network_server_config server_cfg{{}, broker, io_rx_executor, assoc_factory}; + inline_task_executor io_rx_executor; std::unique_ptr server; dummy_sctp_client client; }; @@ -199,7 +202,7 @@ TEST_F(sctp_network_server_test, when_broker_rejects_subscriber_then_listen_fail server = create_sctp_network_server(server_cfg); ASSERT_FALSE(server->listen()); - ASSERT_EQ(broker.last_registered_fd, server->get_socket_fd()); + ASSERT_EQ(broker.last_registered_fd.value(), server->get_socket_fd()); ASSERT_EQ(broker.last_unregistered_fd, -1) << "If the subscription fails, no deregister should be called"; } @@ -208,7 +211,7 @@ TEST_F(sctp_network_server_test, when_broker_accepts_subscriber_then_listen_succ server = create_sctp_network_server(server_cfg); ASSERT_TRUE(server->listen()); - ASSERT_EQ(broker.last_registered_fd, server->get_socket_fd()); + ASSERT_EQ(broker.last_registered_fd.value(), server->get_socket_fd()); } TEST_F(sctp_network_server_test, when_server_is_shutdown_then_fd_is_deregistered_from_broker) @@ -219,7 +222,7 @@ TEST_F(sctp_network_server_test, when_server_is_shutdown_then_fd_is_deregistered int fd = server->get_socket_fd(); ASSERT_EQ(broker.last_unregistered_fd, -1); server.reset(); - ASSERT_EQ(broker.last_registered_fd, fd); + ASSERT_EQ(broker.last_registered_fd.value(), fd); } TEST_F(sctp_network_server_test, when_client_connects_then_server_request_new_sctp_association_handler_creation) @@ -356,4 +359,4 @@ TEST_F(sctp_network_server_test, when_multiple_clients_connect_then_multiple_ass trigger_broker(); // < Client2: SCTP SHUTDOWN EVENT trigger_broker(); // < Client2: SCTP SHUTDOWN COMP ASSERT_TRUE(assoc_factory.association_destroyed) << "Client 2 shutdown was not processed"; -} \ No newline at end of file +} diff --git a/tests/unittests/gateways/sctp_test_helpers.h b/tests/unittests/gateways/sctp_test_helpers.h index 356d80ef47..dbf772cd13 100644 --- a/tests/unittests/gateways/sctp_test_helpers.h +++ b/tests/unittests/gateways/sctp_test_helpers.h @@ -23,31 +23,35 @@ namespace srsran { class dummy_io_broker : public io_broker { public: - bool accept_next_fd = true; - int last_registered_fd = -1; + bool accept_next_fd = true; + unique_fd last_registered_fd; recv_callback_t handle_receive; error_callback_t handle_error; int last_unregistered_fd = -1; [[nodiscard]] subscriber register_fd( - int fd, + unique_fd fd, + task_executor& executor, recv_callback_t handler_, error_callback_t err_handler_ = [](error_code) {}) override { - last_registered_fd = fd; + last_registered_fd = std::move(fd); if (not accept_next_fd) { return {}; } handle_receive = handler_; handle_error = err_handler_; - return subscriber{*this, fd}; + return subscriber{*this, last_registered_fd.value()}; } - [[nodiscard]] bool unregister_fd(int fd) override + [[nodiscard]] bool unregister_fd(int fd, std::promise* complete_notifier) override { last_unregistered_fd = fd; handle_receive = {}; handle_error = {}; + if (complete_notifier) { + complete_notifier->set_value(true); + } return true; } }; diff --git a/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp b/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp index 6e6e889a37..a4371266d3 100644 --- a/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp +++ b/tests/unittests/gateways/udp_network_gateway_pool_depletion_test.cpp @@ -53,7 +53,8 @@ class udp_pool_network_gateway_tester : public ::testing::Test void set_config(udp_network_gateway_config server_config) { - server = create_udp_network_gateway({std::move(server_config), server_data_notifier, io_tx_executor}); + server = + create_udp_network_gateway({std::move(server_config), server_data_notifier, io_tx_executor, io_tx_executor}); ASSERT_NE(server, nullptr); } diff --git a/tests/unittests/gateways/udp_network_gateway_test.cpp b/tests/unittests/gateways/udp_network_gateway_test.cpp index cfe505e28b..11abf4778c 100644 --- a/tests/unittests/gateways/udp_network_gateway_test.cpp +++ b/tests/unittests/gateways/udp_network_gateway_test.cpp @@ -41,9 +41,11 @@ class udp_network_gateway_tester : public ::testing::Test void set_config(udp_network_gateway_config server_config, udp_network_gateway_config client_config) { - server = create_udp_network_gateway({std::move(server_config), server_data_notifier, io_tx_executor}); + server = + create_udp_network_gateway({std::move(server_config), server_data_notifier, io_tx_executor, io_tx_executor}); ASSERT_NE(server, nullptr); - client = create_udp_network_gateway({std::move(client_config), client_data_notifier, io_tx_executor}); + client = + create_udp_network_gateway({std::move(client_config), client_data_notifier, io_tx_executor, io_tx_executor}); ASSERT_NE(client, nullptr); } diff --git a/tests/unittests/support/network/io_broker_epoll_test.cpp b/tests/unittests/support/network/io_broker_epoll_test.cpp index d619ecface..27a8646afb 100644 --- a/tests/unittests/support/network/io_broker_epoll_test.cpp +++ b/tests/unittests/support/network/io_broker_epoll_test.cpp @@ -9,6 +9,7 @@ */ #include "srsran/srslog/srslog.h" +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/io/io_broker_factory.h" #include "srsran/support/io/unique_fd.h" #include @@ -30,13 +31,14 @@ class io_broker_epoll : public ::testing::Test srslog::init(); epoll_broker = create_io_broker(io_broker_type::epoll); } - ~io_broker_epoll() { srslog::flush(); } + + ~io_broker_epoll() override { srslog::flush(); } void data_receive_callback() { - // receive data on provided fd + // Receive data on provided fd. char rx_buf[1024]; - int bytes = read(socket_fd.value(), rx_buf, sizeof(rx_buf)); + int bytes = ::read(raw_socket_fd, rx_buf, sizeof(rx_buf)); std::lock_guard lock(rx_mutex); total_rx_bytes += bytes; @@ -47,71 +49,66 @@ class io_broker_epoll : public ::testing::Test rx_cvar.notify_one(); } - void error_callback(io_broker::error_code code) { error_count++; } + void error_callback(io_broker::error_code code) { ++error_count; } void create_unix_sockets() { - // check temporary files for IPC + // Check temporary files for IPC. std::string socket_filename = "/tmp/io_broker_server"; ASSERT_LE(socket_filename.size(), sizeof(sockaddr_un::sun_path)); - // delete exsiting file (if any) - int ret = remove(socket_filename.c_str()); + // Delete existing file (if any). + int ret = ::remove(socket_filename.c_str()); if (ret == -1 && errno != ENOENT) { - // allow ENOENT, i.e. file not found + // Allow ENOENT, i.e. file not found. ASSERT_NE(ret, -1); } - // create server socket - socket_fd = unique_fd{socket(AF_UNIX, SOCK_DGRAM, 0)}; + // Create server socket. + socket_fd = unique_fd{::socket(AF_UNIX, SOCK_DGRAM, 0)}; socket_type = SOCK_DGRAM; ASSERT_TRUE(socket_fd.is_open()); + raw_socket_fd = socket_fd.value(); - // prepare server address - // memset(&server_addr, 0, sizeof(struct sockaddr_un)); + // Prepare server address. server_addr_un.sun_family = AF_UNIX; - strncpy(server_addr_un.sun_path, socket_filename.c_str(), socket_filename.length()); + std::strncpy(server_addr_un.sun_path, socket_filename.c_str(), socket_filename.length()); - // bind server - ret = bind(socket_fd.value(), (struct sockaddr*)&server_addr_un, sizeof(server_addr_un)); + // Bind server. + ret = ::bind(raw_socket_fd, reinterpret_cast<::sockaddr*>(&server_addr_un), sizeof(server_addr_un)); ASSERT_NE(ret, -1); - // listen+accept? - // ret = listen(socket_fd,1); - // ASSERT_NE(ret, -1); - - // prepare client address + // Prepare client address. client_addr_un.sun_family = AF_UNIX; - strncpy(client_addr_un.sun_path, socket_filename.c_str(), socket_filename.length()); + std::strncpy(client_addr_un.sun_path, socket_filename.c_str(), socket_filename.length()); - // connect client to server_filename - ret = connect(socket_fd.value(), (struct sockaddr*)&client_addr_un, sizeof(client_addr_un)); - // perror("socket failed"); + // Connect client to server_filename. + ret = ::connect(raw_socket_fd, reinterpret_cast<::sockaddr*>(&client_addr_un), sizeof(client_addr_un)); ASSERT_NE(ret, -1); } std::optional get_bind_port(int sock_fd) { if (sock_fd == -1) { - return {}; + return std::nullopt; } - sockaddr_storage gw_addr_storage; - sockaddr* gw_addr = (sockaddr*)&gw_addr_storage; - socklen_t gw_addr_len = sizeof(gw_addr_storage); + ::sockaddr_storage gw_addr_storage; + auto* gw_addr = reinterpret_cast<::sockaddr*>(&gw_addr_storage); + ::socklen_t gw_addr_len = sizeof(gw_addr_storage); - int ret = getsockname(sock_fd, gw_addr, &gw_addr_len); + int ret = ::getsockname(sock_fd, gw_addr, &gw_addr_len); if (ret != 0) { - return {}; + return std::nullopt; } uint16_t bind_port; if (gw_addr->sa_family == AF_INET) { - bind_port = ntohs(((sockaddr_in*)gw_addr)->sin_port); + bind_port = ntohs(reinterpret_cast<::sockaddr_in*>(gw_addr)->sin_port); } else if (gw_addr->sa_family == AF_INET6) { - bind_port = ntohs(((sockaddr_in6*)gw_addr)->sin6_port); + bind_port = ntohs(reinterpret_cast<::sockaddr_in6*>(gw_addr)->sin6_port); } else { - return {}; + return std::nullopt; } return bind_port; @@ -119,72 +116,67 @@ class io_broker_epoll : public ::testing::Test void create_af_init_sockets(int type) { - // create server socket + // Create server socket. socket_fd = unique_fd{socket(AF_INET, type, 0)}; socket_type = type; ASSERT_TRUE(socket_fd.is_open()); + raw_socket_fd = socket_fd.value(); - // configure socket as reusable to allow multiple runs + // Configure socket as reusable to allow multiple runs. int enable = 1; - ASSERT_NE(setsockopt(socket_fd.value(), SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)), -1); + ASSERT_NE(setsockopt(raw_socket_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)), -1); // prepare server address - memset(&server_addr_in, 0, sizeof(struct sockaddr_in)); + std::memset(&server_addr_in, 0, sizeof(::sockaddr_in)); server_addr_in.sin_family = AF_INET; server_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); server_addr_in.sin_port = htons(0); - // bind server - int ret = bind(socket_fd.value(), (struct sockaddr*)&server_addr_in, sizeof(server_addr_in)); - // perror("socket failed"); + // Bind server. + int ret = ::bind(raw_socket_fd, reinterpret_cast<::sockaddr*>(&server_addr_in), sizeof(server_addr_in)); ASSERT_NE(ret, -1); - // get bind port - std::optional port = get_bind_port(socket_fd.value()); + // Get bind port. + std::optional port = get_bind_port(raw_socket_fd); ASSERT_TRUE(port.has_value()); ASSERT_NE(port.value(), 0); - // update server address + // Update server address. server_addr_in.sin_port = htons(port.value()); - // prepare client address - memset(&client_addr_in, 0, sizeof(struct sockaddr_in)); + // Prepare client address. + std::memset(&client_addr_in, 0, sizeof(::sockaddr_in)); client_addr_in.sin_family = AF_INET; client_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); client_addr_in.sin_port = htons(port.value()); - // connect client to server - ret = connect(socket_fd.value(), (struct sockaddr*)&server_addr_in, sizeof(server_addr_in)); + // Connect client to server + ret = ::connect(raw_socket_fd, reinterpret_cast<::sockaddr*>(&server_addr_in), sizeof(server_addr_in)); ASSERT_NE(ret, -1); } void add_socket_to_epoll() { fd_handle = epoll_broker->register_fd( - socket_fd.value(), + std::move(socket_fd), + executor, [this]() { data_receive_callback(); }, [this](io_broker::error_code code) { error_callback(code); }); ASSERT_TRUE(fd_handle.registered()); } - void rem_socket_from_epoll() - { - if (socket_fd.is_open()) { - EXPECT_TRUE(fd_handle.reset()); - ASSERT_TRUE(socket_fd.close()); - } - } + void rem_socket_from_epoll() { EXPECT_TRUE(fd_handle.reset()); } void send_on_socket() const { - // send text - int ret = send(socket_fd.value(), tx_buf.c_str(), tx_buf.length(), 0); + // Send text. + int ret = ::send(raw_socket_fd, tx_buf.c_str(), tx_buf.length(), 0); ASSERT_EQ(ret, tx_buf.length()); } void run_tx_rx_test() { - const int count = 5; - int run = count; + const unsigned count = 5; + int run = count; while (run-- > 0) { send_on_socket(); } @@ -195,19 +187,21 @@ class io_broker_epoll : public ::testing::Test ASSERT_EQ(total_rx_bytes, tx_buf.length() * count); } + inline_task_executor executor; std::unique_ptr epoll_broker; + int raw_socket_fd = -1; unique_fd socket_fd; int socket_type = 0; io_broker::subscriber fd_handle; - // unix domain socket addresses (used by unix sockets only) - struct sockaddr_un server_addr_un = {}; - struct sockaddr_un client_addr_un = {}; + // Unix domain socket addresses (used by unix sockets only). + ::sockaddr_un server_addr_un = {}; + ::sockaddr_un client_addr_un = {}; - // inet socket addresses (used by all other protocols) - struct sockaddr_in server_addr_in = {}; - struct sockaddr_in client_addr_in = {}; + // Inet socket addresses (used by all other protocols) + ::sockaddr_in server_addr_in = {}; + ::sockaddr_in client_addr_in = {}; std::mutex rx_mutex; std::condition_variable rx_cvar; @@ -249,7 +243,7 @@ TEST_F(io_broker_epoll, reentrant_handle_and_deregistration) std::future fut = p.get_future(); io_broker::subscriber handle; - handle = this->epoll_broker->register_fd(socket_fd.value(), [&]() { + handle = this->epoll_broker->register_fd(std::move(socket_fd), executor, [&]() { auto* p_copy = &p; bool ret = handle.reset(); p_copy->set_value(ret); @@ -266,24 +260,25 @@ TEST_F(io_broker_epoll, error_callback_called_when_epollhup) { // Create pipe int pipefd[2]; - ASSERT_EQ(pipe(pipefd), 0); + ASSERT_EQ(::pipe(pipefd), 0); std::promise p; std::future f = p.get_future(); // Subscribe pipe fd. auto sub = this->epoll_broker->register_fd( - pipefd[0], + unique_fd(pipefd[0]), + executor, []() {}, [this, &p](io_broker::error_code code) { - this->error_count++; + ++this->error_count; p.set_value(); }); ASSERT_TRUE(sub.registered()); // Close pipe, while subscribed. This will cause an EPOLLHUP event. ASSERT_EQ(this->error_count, 0); - close(pipefd[1]); + ::close(pipefd[1]); // Check if the error handler was called. The error can take some time to trigger the epoll. f.wait(); diff --git a/tests/unittests/support/network/io_timer_source_test.cpp b/tests/unittests/support/network/io_timer_source_test.cpp index b257227fd5..5fa045eb63 100644 --- a/tests/unittests/support/network/io_timer_source_test.cpp +++ b/tests/unittests/support/network/io_timer_source_test.cpp @@ -8,6 +8,7 @@ * */ +#include "srsran/support/executors/inline_task_executor.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/io/io_broker_factory.h" #include "srsran/support/io/io_timer_source.h" @@ -20,11 +21,12 @@ using namespace srsran; class io_timer_source_test : public ::testing::Test { public: + inline_task_executor executor; manual_task_worker worker{16}; timer_manager timers{16}; std::unique_ptr broker = create_io_broker(srsran::io_broker_type::epoll); - void start() { source.emplace(timers, *broker, std::chrono::milliseconds{1}); } + void start() { source.emplace(timers, *broker, executor, std::chrono::milliseconds{1}); } void stop() { source.reset(); } @@ -63,4 +65,4 @@ TEST_F(io_timer_source_test, timer_gets_ticked_when_source_starts) std::this_thread::sleep_for(std::chrono::milliseconds{10}); worker.run_pending_tasks(); ASSERT_EQ(count, 0); -} \ No newline at end of file +} From 134a57ce323fbb83493adb73e7045d2dbf10a70d Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Wed, 11 Dec 2024 12:02:03 +0100 Subject: [PATCH 153/227] mac: support pucch f3/f4 in du_pucch_resource_manager and pucch_resource_manager --- .../srsran/scheduler/scheduler_pucch_format.h | 8 +--- .../du_pucch_resource_manager.cpp | 24 ++++++------ lib/fapi_adaptor/mac/messages/pucch.cpp | 4 +- .../pucch_resource_manager.cpp | 25 ++++++------ .../pucch_scheduling/pucch_resource_manager.h | 38 +++++++++---------- .../uci_and_pucch/uci_test_utils.cpp | 37 ++++++++++++++---- 6 files changed, 80 insertions(+), 56 deletions(-) diff --git a/include/srsran/scheduler/scheduler_pucch_format.h b/include/srsran/scheduler/scheduler_pucch_format.h index f00963213d..7a507ecb07 100644 --- a/include/srsran/scheduler/scheduler_pucch_format.h +++ b/include/srsran/scheduler/scheduler_pucch_format.h @@ -90,9 +90,7 @@ struct pucch_format_3 { /// \c pucch-GroupHopping, as per TS 38.331 pucch_group_hopping group_hopping; /// \f$n_{ID}\f$ as per Section 6.3.2.2.1, TS 38.211. - unsigned n_id_hopping; - /// \c initialCyclicShift, as per TS 38.331, or Section 9.2.1, TS 38.211. - uint8_t initial_cyclic_shift; + unsigned n_id_hopping; sr_nof_bits sr_bits; unsigned harq_ack_nof_bits; unsigned csi_part1_bits; @@ -111,9 +109,7 @@ struct pucch_format_4 { /// \c pucch-GroupHopping, as per TS 38.331 pucch_group_hopping group_hopping; /// \f$n_{ID}\f$ as per Section 6.3.2.2.1, TS 38.211. - unsigned n_id_hopping; - /// \c initialCyclicShift, as per TS 38.331, or Section 9.2.1, TS 38.211. - uint8_t initial_cyclic_shift; + unsigned n_id_hopping; sr_nof_bits sr_bits; unsigned harq_ack_nof_bits; unsigned csi_part1_bits; diff --git a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index d8a7155c5b..8ef0b569fd 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -170,18 +170,20 @@ du_pucch_resource_manager::find_optimal_csi_report_slot_offset( (csi_rs_period + csi_res_offset_candidate.second - csi_rs_offset - MINIMUM_CSI_RS_REPORT_DISTANCE) % csi_rs_period; - if (sr_res_cfg.format == pucch_format::FORMAT_0) { - const pucch_resource& candidate_csi_res_cfg = - default_pucch_res_list[csi_du_res_idx_to_pucch_res_idx(csi_res_offset_candidate.first)]; + const pucch_resource& candidate_csi_res_cfg = + default_pucch_res_list[csi_du_res_idx_to_pucch_res_idx(csi_res_offset_candidate.first)]; + if (sr_res_cfg.format == pucch_format::FORMAT_0 and candidate_csi_res_cfg.format == pucch_format::FORMAT_2) { srsran_assert(std::holds_alternative(candidate_csi_res_cfg.format_params), - "PUCCH resource for CSI must be of format 2 or 3"); - const ofdm_symbol_range csi_symbols = { - std::get(candidate_csi_res_cfg.format_params).starting_sym_idx, - std::get(candidate_csi_res_cfg.format_params).starting_sym_idx + - std::get(candidate_csi_res_cfg.format_params).nof_symbols}; - const ofdm_symbol_range sr_symbols = {std::get(sr_res_cfg.format_params).starting_sym_idx, - std::get(sr_res_cfg.format_params).starting_sym_idx + - std::get(sr_res_cfg.format_params).nof_symbols}; + "PUCCH resource for CSI must be of format 2"); + + const auto& csi_params = std::get(candidate_csi_res_cfg.format_params); + const ofdm_symbol_range csi_symbols = {csi_params.starting_sym_idx, + csi_params.starting_sym_idx + csi_params.nof_symbols}; + + const auto& sr_params = std::get(sr_res_cfg.format_params); + const ofdm_symbol_range sr_symbols = {sr_params.starting_sym_idx, + sr_params.starting_sym_idx + sr_params.nof_symbols}; + if (not csi_symbols.overlaps(sr_symbols)) { weight += 2 * csi_rs_period; return weight; diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index e7f0258b4a..a649233fea 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -120,7 +120,7 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; builder.set_hopping_information_parameters( - intra_slot_freq_hop, hop_prbs.start(), f3.group_hopping, f3.n_id_hopping, f3.initial_cyclic_shift); + intra_slot_freq_hop, hop_prbs.start(), f3.group_hopping, f3.n_id_hopping, 0); // Common parameters. builder.set_common_parameters(mac_pdu.format, f3.slot_repetition, f3.pi_2_bpsk); @@ -147,7 +147,7 @@ static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const p const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; builder.set_hopping_information_parameters( - intra_slot_freq_hop, hop_prbs.start(), f4.group_hopping, f4.n_id_hopping, f4.initial_cyclic_shift); + intra_slot_freq_hop, hop_prbs.start(), f4.group_hopping, f4.n_id_hopping, 0); // Common parameters. builder.set_common_parameters(mac_pdu.format, f4.slot_repetition, f4.pi_2_bpsk); diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp index d283f4c04d..1feb5834ce 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp @@ -23,7 +23,7 @@ static int get_pucch_res_idx_for_csi(const ue_cell_configuration& ue_cell_cfg) const unsigned csi_report_cfg_idx = 0; // We assume we use the First BWP. // TODO: extend by passing the BWP id. - const bwp_id_t bwp_id = srsran::MIN_BWP_ID; + const bwp_id_t bwp_id = MIN_BWP_ID; const auto& csi_report_cfg = ue_cell_cfg.cfg_dedicated().csi_meas_cfg.value().csi_report_cfg_list[csi_report_cfg_idx]; span csi_pucch_res_list = std::get(csi_report_cfg.report_cfg_type) @@ -367,13 +367,14 @@ pucch_harq_resource_alloc_record pucch_resource_manager::reserve_next_harq_res_a unsigned ue_first_res_id = ue_res_id_set_for_harq.front().cell_res_id; const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; + const bool is_format2 = pucch_cfg.pucch_res_list.back().format == pucch_format::FORMAT_2; srsran_assert(ue_first_res_id + ue_res_id_set_for_harq.size() <= slot_res_array.size(), "Indexing of PUCCH resource set exceeds the size of the cell resource array"); - // For PUCCH format 0, we don't use the last 2 resources of the PUCCH resource set; these are reserved the UE for CSI - // and SR slots and should only be picked for through the specific PUCCH resource indicator. + // For PUCCH format 0 and format 2, we don't use the last 2 resources of the PUCCH resource set; these are reserved + // the UE for CSI and SR slots and should only be picked for through the specific PUCCH resource indicator. const unsigned nof_eligible_resource = - is_format0 ? ue_res_id_set_for_harq.size() - 2U : ue_res_id_set_for_harq.size(); + is_format0 and is_format2 ? ue_res_id_set_for_harq.size() - 2U : ue_res_id_set_for_harq.size(); srsran_assert(nof_eligible_resource >= 1U, "rnti={}: Not enough eligible resources from PUCCH resource set={}", crnti, @@ -443,10 +444,11 @@ const pucch_resource* pucch_resource_manager::reserve_harq_res_by_res_indicator( const auto pucch_res_id = ue_res_id_set_for_harq[res_indicator]; const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; - // For Format 0, the resources indexed by PUCCH res. indicators >= ue_res_id_set_for_harq.size() - 2 are reserved for - // CSI and SR slots. In the case, we don't need to reserve these in the PUCCH resource manager, we only need to return - // the resouces. - if (is_format0 and res_indicator >= ue_res_id_set_for_harq.size() - 2U) { + const bool is_format2 = pucch_cfg.pucch_res_list.back().format == pucch_format::FORMAT_2; + // For Format 0 and Format 2, the resources indexed by PUCCH res. indicators >= ue_res_id_set_for_harq.size() - 2 are + // reserved for CSI and SR slots. In the case, we don't need to reserve these in the PUCCH resource manager, we only + // need to return the resouces. + if (is_format0 and is_format2 and res_indicator >= ue_res_id_set_for_harq.size() - 2U) { const auto* res_cfg = std::find_if( pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), [pucch_res_id](const pucch_resource& res) { return res.res_id.ue_res_id == pucch_res_id.ue_res_id; @@ -507,6 +509,7 @@ bool pucch_resource_manager::release_harq_resource(slot_point slot_harq res_set_idx == pucch_res_set_idx::set_0 ? pucch_resource_usage::HARQ_SET_0 : pucch_resource_usage::HARQ_SET_1; const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; + const bool is_format2 = pucch_cfg.pucch_res_list.back().format == pucch_format::FORMAT_2; // Get the span over the array of resources for the specific UE. const auto& ue_res_id_set_for_harq = @@ -514,10 +517,10 @@ bool pucch_resource_manager::release_harq_resource(slot_point slot_harq unsigned ue_first_res_id = ue_res_id_set_for_harq.front().cell_res_id; srsran_assert(ue_first_res_id + ue_res_id_set_for_harq.size() <= slot_res_array.size(), "Indexing of PUCCH resource set exceeds the size of the cell resource array"); - // For PUCCH format 0, we don't use the last 2 resources of the PUCCH resource set; these are reserved the UE for CSI - // and SR slots and should only be picked for through the specific PUCCH resource indicator. + // For PUCCH format 0 and format 2, we don't use the last 2 resources of the PUCCH resource set; these are reserved + // the UE for CSI and SR slots and should only be picked for through the specific PUCCH resource indicator. const unsigned nof_eligible_resource = - is_format0 ? ue_res_id_set_for_harq.size() - 2U : ue_res_id_set_for_harq.size(); + is_format0 and is_format2 ? ue_res_id_set_for_harq.size() - 2U : ue_res_id_set_for_harq.size(); srsran_assert(nof_eligible_resource >= 1U, "rnti={}: Not enough eligible resources from PUCCH resource set={}", crnti, diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.h b/lib/scheduler/pucch_scheduling/pucch_resource_manager.h index 29631c3b53..95e60daff9 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.h +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.h @@ -28,17 +28,19 @@ enum class pucch_resource_usage { NOT_USED = 0, HARQ_SET_0, HARQ_SET_1, SR, CSI /// \brief Class that manages the cell allocation of PUCCH resources across UEs. /// The correct functioning of pucch_resource_manager is based on the following assumptions: -/// (i) Each UE has max 8 PUCCH F0/F1 and max 8 PUCCH F2 dedicated to HARQ-ACK reporting. -/// (ii) Each UE has max 1 SR-dedicated PUCCH F0/F1 resource and max 1 CSI-dedicated PUCCH F2 resource. +/// (i) Each UE has max 8 PUCCH F0/F1 and max 8 PUCCH F2/F3/F4 dedicated to HARQ-ACK reporting. +/// (ii) Each UE has max 1 SR-dedicated PUCCH F0/F1 resource and max 1 CSI-dedicated PUCCH F2/F3/F4 resource. /// (iii) The cell PUCCH resource list can have max \c MAX_NOF_CELL_PUCCH_RESOURCES PUCCH resource, including all -/// formats; at cell level, there is no constraint on how many resource must be F0/F1, F2, or for SR or for CSI. +/// formats; at cell level, there is no constraint on how many resource must be F0/F1, F2/F3/F4, or for SR or for +/// CSI. /// (vi) UEs can have different PUCCH resource lists; however the PUCCH resource ID is unique with the cell. This /// implies that if two UEs have the same PUCCH resource within their lists, their PUCCH resource ID must be the /// same. -/// (v) Indexing of the PUCCH F0/F1 and PUCCH F2 resources for HARQ-ACK reporting must be contiguous within the F0/F1 -/// group and with F2 group. However, the last PUCCH F0/F1 group resource's and the first PUCCH F2 group -/// resource's indices need not be contiguous. E.g., PUCCH F0/F1 indices (for HARQ-ACK reporting) = {0, ..., 7}, -/// and PUCCH F2 indices (for HARQ-ACK reporting) = {10, ..., 17}. +/// (v) Indexing of the PUCCH F0/F1 and PUCCH F2/F3/F4 resources for HARQ-ACK reporting must be contiguous within the +/// F0/F1 +/// group and with F2/F3/F4 group. However, the last PUCCH F0/F1 group resource's and the first PUCCH F2/F3/F4 +/// group resource's indices need not be contiguous. E.g., PUCCH F0/F1 indices (for HARQ-ACK reporting) = {0, ..., +/// 7}, and PUCCH F2/F3/F4 indices (for HARQ-ACK reporting) = {10, ..., 17}. class pucch_resource_manager { public: @@ -61,8 +63,7 @@ class pucch_resource_manager pucch_harq_resource_alloc_record reserve_next_set_0_harq_res_available(slot_point slot_harq, rnti_t crnti, const pucch_config& pucch_cfg); - /// \brief Returns the next PUCCH format 2 resource available to be used for HARQ-ACK. - /// \remark Format 2 is the only format currently supported for PUCCH resource set 1. + /// \brief Returns the next PUCCH resource available to be used for HARQ-ACK (format 2, 3 or 4). /// \remark If SR and CSI multiplexing is enabled, this resource can be used for HARQ-ACK + SR and/or CSI. /// \return If any PUCCH resource available, it returns (i) the pointer to the configuration and (ii) the PUCCH /// resource indicator corresponding to the PUCCH resource that will be used by the UE. If there are no PUCCH @@ -79,8 +80,8 @@ class pucch_resource_manager unsigned res_indicator, const pucch_config& pucch_cfg); - /// \brief Returns a specific PUCCH format 2 resource (identified by the res. indicator) to be used for HARQ-ACK. - /// \remark Format 2 is the only format currently supported for PUCCH resource set 1. + /// \brief Returns a specific PUCCH format 2, 3 or 4 resource (identified by the res. indicator) to be used for + /// HARQ-ACK. /// \remark If SR and CSI multiplexing is enabled, this resource can be used for HARQ-ACK + SR and/or CSI. /// \return If the specific PUCCH resource is available, it returns the pointer to the configuration. Else, it returns /// \c nullptr. @@ -89,7 +90,7 @@ class pucch_resource_manager unsigned res_indicator, const pucch_config& pucch_cfg); - /// \brief Returns the specific PUCCH format 2 resource config to be used for CSI, if available. + /// \brief Returns the specific PUCCH resource config to be used for CSI, if available. /// \remark If SR multiplexing is enabled, this resource can be used for CSI + SR. /// \return If the specific PUCCH resource is available, it returns (i) the pointer to the configuration and (ii) the /// PUCCH resource indicator corresponding to the PUCCH resource that will be used by the UE. Else, the pointer passed @@ -111,8 +112,7 @@ class pucch_resource_manager /// \return True if the resource for the UE was found in the allocation records for the given slot. bool release_harq_set_0_resource(slot_point slot_harq, rnti_t crnti, const pucch_config& pucch_cfg); - /// \brief Release PUCCH (format 2) resource from being allocated to a given UE. - /// \remark Format 2 is the only format currently supported for PUCCH resource set 1. + /// \brief Release PUCCH (format 2, 3 or 4) resource from being allocated to a given UE. /// \param[in] slot_harq slot for which the PUCCH resource was scheduled. /// \param[in] crnti UE from which the resource needs to be released. /// \param[in] pucch_cfg UE's PUCCH config. @@ -120,18 +120,18 @@ class pucch_resource_manager bool release_harq_set_1_resource(slot_point slot_harq, rnti_t crnti, const pucch_config& pucch_cfg); /// \brief Release PUCCH (format 0 or 1) resource used for SR from being allocated to a given UE. - /// \param[in] slot_harq slot for which the PUCCH resource was scheduled. + /// \param[in] slot_sr slot for which the PUCCH resource was scheduled. /// \param[in] crnti UE from which the resource needs to be released. /// \param[in] pucch_cfg UE's PUCCH config. /// \return True if the resource for the UE was found in the allocation records for the given slot. bool release_sr_resource(slot_point slot_sr, rnti_t crnti, const pucch_config& pucch_cfg); - /// \brief Release PUCCH (format 2) resource used for CSI from being allocated to a given UE. - /// \param[in] slot_harq slot for which the PUCCH resource was scheduled. + /// \brief Release PUCCH (format 2, 3 or 4) resource used for CSI from being allocated to a given UE. + /// \param[in] slot_csi slot for which the PUCCH resource was scheduled. /// \param[in] crnti UE from which the resource needs to be released. - /// \param[in] pucch_cfg UE's PUCCH config. + /// \param[in] ue_cell_cfg UE's dedicated cell configuration. /// \return True if the resource for the UE was found in the allocation records for the given slot. - bool release_csi_resource(slot_point slot_sr, rnti_t crnti, const ue_cell_configuration& ue_cell_cfg); + bool release_csi_resource(slot_point slot_csi, rnti_t crnti, const ue_cell_configuration& ue_cell_cfg); /// \brief Reset the record of the PUCCH resources reserved to UE at the current slot. /// \remark This function doesn't release the resources, it only resets the record of which resources have been diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 761593c78e..65ee1975ca 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -73,9 +73,7 @@ bool srsran::pucch_info_match(const pucch_info& expected, const pucch_info& test expected_f.n_id_hopping == test_f.n_id_hopping && expected_f.initial_cyclic_shift == test_f.initial_cyclic_shift && expected_f.sr_bits == test_f.sr_bits && expected_f.harq_ack_nof_bits == test_f.harq_ack_nof_bits; - - break; - } + } break; case pucch_format::FORMAT_1: { const pucch_format_1& expected_f = expected.format_1; const pucch_format_1& test_f = test.format_1; @@ -85,8 +83,7 @@ bool srsran::pucch_info_match(const pucch_info& expected, const pucch_info& test expected_f.sr_bits == test_f.sr_bits && expected_f.harq_ack_nof_bits == test_f.harq_ack_nof_bits && expected_f.slot_repetition == test_f.slot_repetition && expected_f.time_domain_occ == test_f.time_domain_occ; - break; - } + } break; case pucch_format::FORMAT_2: { const pucch_format_2& expected_f = expected.format_2; const pucch_format_2& test_f = test.format_2; @@ -95,8 +92,34 @@ bool srsran::pucch_info_match(const pucch_info& expected, const pucch_info& test expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling && expected_f.sr_bits == test_f.sr_bits && expected_f.harq_ack_nof_bits == test_f.harq_ack_nof_bits && expected_f.csi_part1_bits == test_f.csi_part1_bits; - break; - } + } break; + case pucch_format::FORMAT_3: { + const pucch_format_3& expected_f = expected.format_3; + const pucch_format_3& test_f = test.format_3; + is_equal = + is_equal && expected_f.group_hopping == test_f.group_hopping && + expected_f.n_id_hopping == test_f.n_id_hopping && expected_f.sr_bits == test_f.sr_bits && + expected_f.harq_ack_nof_bits == test_f.harq_ack_nof_bits && + expected_f.csi_part1_bits == test_f.csi_part1_bits && expected_f.slot_repetition == test_f.slot_repetition && + expected_f.n_id_scrambling == test_f.n_id_scrambling && expected_f.pi_2_bpsk == test_f.pi_2_bpsk && + expected_f.max_code_rate == test_f.max_code_rate && expected_f.additional_dmrs == test_f.additional_dmrs && + expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling && + expected_f.m_0_cyclic_shift == test_f.m_0_cyclic_shift; + } break; + case pucch_format::FORMAT_4: { + const pucch_format_4& expected_f = expected.format_4; + const pucch_format_4& test_f = test.format_4; + is_equal = + is_equal && expected_f.group_hopping == test_f.group_hopping && + expected_f.n_id_hopping == test_f.n_id_hopping && expected_f.sr_bits == test_f.sr_bits && + expected_f.harq_ack_nof_bits == test_f.harq_ack_nof_bits && + expected_f.csi_part1_bits == test_f.csi_part1_bits && expected_f.slot_repetition == test_f.slot_repetition && + expected_f.n_id_scrambling == test_f.n_id_scrambling && expected_f.pi_2_bpsk == test_f.pi_2_bpsk && + expected_f.max_code_rate == test_f.max_code_rate && expected_f.orthog_seq_idx == test_f.orthog_seq_idx && + expected_f.n_sf_pucch_f4 == test_f.n_sf_pucch_f4 && expected_f.additional_dmrs == test_f.additional_dmrs && + expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling && + expected_f.m_0_cyclic_shift == test_f.m_0_cyclic_shift; + } break; default: { return false; }; From 7f506ddb775c4246bf4e82348f916b1cf808271f Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Wed, 11 Dec 2024 18:54:43 +0100 Subject: [PATCH 154/227] mac: review pucch f3/f4 in du_pucch_resource_manager and pucch_resource_manager --- .../srsran/scheduler/scheduler_pucch_format.h | 2 - lib/fapi_adaptor/mac/messages/pucch.cpp | 37 ++++++++++++++++--- .../pucch_resource_manager.cpp | 4 ++ .../du_ran_resource_manager_test.cpp | 10 ++--- .../uci_and_pucch/uci_test_utils.cpp | 6 +-- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/include/srsran/scheduler/scheduler_pucch_format.h b/include/srsran/scheduler/scheduler_pucch_format.h index 7a507ecb07..e6bd76d097 100644 --- a/include/srsran/scheduler/scheduler_pucch_format.h +++ b/include/srsran/scheduler/scheduler_pucch_format.h @@ -101,7 +101,6 @@ struct pucch_format_3 { /// DMRS parameters. bool additional_dmrs; uint16_t n_id_0_scrambling; - uint16_t m_0_cyclic_shift; }; /// Scheduler output for PUCCH Format 4. @@ -127,7 +126,6 @@ struct pucch_format_4 { /// DMRS parameters. bool additional_dmrs; uint16_t n_id_0_scrambling; - uint16_t m_0_cyclic_shift; }; } // namespace srsran diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index a649233fea..1a3bd67262 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -119,8 +119,13 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p // Hopping parameters. const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; + + // Cyclic shift index (m0) is always 0 for PUCCH Format 3, as per TS 38.211 6.4.1.3.3.1. + constexpr unsigned m0 = 0; + + // Parameter initial_cyclic_shift is not applicable to PUCCH Format 3. builder.set_hopping_information_parameters( - intra_slot_freq_hop, hop_prbs.start(), f3.group_hopping, f3.n_id_hopping, 0); + intra_slot_freq_hop, hop_prbs.start(), f3.group_hopping, f3.n_id_hopping, m0); // Common parameters. builder.set_common_parameters(mac_pdu.format, f3.slot_repetition, f3.pi_2_bpsk); @@ -129,7 +134,7 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_scrambling_parameters(f3.n_id_scrambling); // DM-RS. - builder.set_dmrs_parameters(f3.additional_dmrs, f3.n_id_0_scrambling, f3.m_0_cyclic_shift); + builder.set_dmrs_parameters(f3.additional_dmrs, f3.n_id_0_scrambling, m0); // Max coding rate. builder.set_maintenance_v3_basic_parameters({static_cast(f3.max_code_rate)}, {}); @@ -138,6 +143,23 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_bit_length_parameters(convert_sr_bits_to_unsigned(f3.sr_bits), f3.harq_ack_nof_bits, f3.csi_part1_bits); } +/// Gets the cyclic shift index (m0) for PUCCH Format 4, as per TS38.211 Table 6.4.1.3.3.1-1. +static unsigned get_pucch_format4_m0(unsigned occ_index) +{ + switch (occ_index) { + case 0: + return 0; + case 1: + return 6; + case 2: + return 3; + case 3: + return 9; + default: + return 0; + } +} + /// Fills the Format 4 parameters. static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const pucch_info& mac_pdu) { @@ -146,8 +168,12 @@ static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const p // Hopping parameters. const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; - builder.set_hopping_information_parameters( - intra_slot_freq_hop, hop_prbs.start(), f4.group_hopping, f4.n_id_hopping, 0); + // Parameter initial_cyclic_shift is not applicable to PUCCH Format 4. + builder.set_hopping_information_parameters(intra_slot_freq_hop, + hop_prbs.start(), + f4.group_hopping, + f4.n_id_hopping, + get_pucch_format4_m0(mac_pdu.format_4.orthog_seq_idx)); // Common parameters. builder.set_common_parameters(mac_pdu.format, f4.slot_repetition, f4.pi_2_bpsk); @@ -156,7 +182,8 @@ static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_scrambling_parameters(f4.n_id_scrambling); // DM-RS. - builder.set_dmrs_parameters(f4.additional_dmrs, f4.n_id_0_scrambling, f4.m_0_cyclic_shift); + builder.set_dmrs_parameters( + f4.additional_dmrs, f4.n_id_0_scrambling, get_pucch_format4_m0(mac_pdu.format_4.orthog_seq_idx)); // Specific format 4 parameters. builder.set_format4_parameters(f4.orthog_seq_idx, static_cast(f4.n_sf_pucch_f4)); diff --git a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp index 1feb5834ce..cd2fe6c9f0 100644 --- a/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_resource_manager.cpp @@ -366,6 +366,7 @@ pucch_harq_resource_alloc_record pucch_resource_manager::reserve_next_harq_res_a pucch_cfg.pucch_res_set[pucch_res_set_idx_to_uint(res_set_idx)].pucch_res_id_list; unsigned ue_first_res_id = ue_res_id_set_for_harq.front().cell_res_id; + // [Implementation-defined] Format 0/1 resources are at the beginning of the list, while Format 2/3/4 are at the end. const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; const bool is_format2 = pucch_cfg.pucch_res_list.back().format == pucch_format::FORMAT_2; @@ -443,8 +444,10 @@ const pucch_resource* pucch_resource_manager::reserve_harq_res_by_res_indicator( // Get PUCCH resource ID from the PUCCH resource set. const auto pucch_res_id = ue_res_id_set_for_harq[res_indicator]; + // [Implementation-defined] Format 0/1 resources are at the beginning of the list, while Format 2/3/4 are at the end. const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; const bool is_format2 = pucch_cfg.pucch_res_list.back().format == pucch_format::FORMAT_2; + // For Format 0 and Format 2, the resources indexed by PUCCH res. indicators >= ue_res_id_set_for_harq.size() - 2 are // reserved for CSI and SR slots. In the case, we don't need to reserve these in the PUCCH resource manager, we only // need to return the resouces. @@ -508,6 +511,7 @@ bool pucch_resource_manager::release_harq_resource(slot_point slot_harq const pucch_resource_usage res_usage = res_set_idx == pucch_res_set_idx::set_0 ? pucch_resource_usage::HARQ_SET_0 : pucch_resource_usage::HARQ_SET_1; + // [Implementation-defined] Format 0/1 resources are at the beginning of the list, while Format 2/3/4 are at the end. const bool is_format0 = pucch_cfg.pucch_res_list.front().format == pucch_format::FORMAT_0; const bool is_format2 = pucch_cfg.pucch_res_list.back().format == pucch_format::FORMAT_2; diff --git a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp index 505ab82888..ab15277d7f 100644 --- a/tests/unittests/du_manager/du_ran_resource_manager_test.cpp +++ b/tests/unittests/du_manager/du_ran_resource_manager_test.cpp @@ -114,8 +114,8 @@ class du_ran_resource_manager_tester_base bool verify_pucch_cfg(const pucch_config& pucch_cfg, std::optional csi_pucch_res) { const du_cell_config& du_cfg = cell_cfg_list[0]; - const unsigned nof_sr_f1_res_per_ue = 1U; - const unsigned nof_csi_f2_res_per_ue = 1U; + constexpr unsigned nof_sr_f1_res_per_ue = 1U; + constexpr unsigned nof_csi_f2_res_per_ue = 1U; bool pucch_checker = pucch_cfg.pucch_res_list.size() == du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + du_cfg.pucch_cfg.nof_ue_pucch_f2_or_f3_or_f4_res_harq.to_uint() + @@ -129,7 +129,7 @@ class du_ran_resource_manager_tester_base pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id < du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + du_cfg.pucch_cfg.nof_sr_resources; - // We always put the CSI PUCCH resource is always at the end of the list. + // We always put the CSI PUCCH resource at the end of the list. if (csi_pucch_res.has_value()) { pucch_checker = pucch_checker and csi_pucch_res.value() >= du_cfg.pucch_cfg.nof_ue_pucch_f0_or_f1_res_harq.to_uint() + @@ -302,8 +302,8 @@ struct pucch_cnt_builder_params { unsigned nof_res_sr = 2; unsigned nof_res_csi = 1; unsigned max_allowed_pucch_grants = 4; - sr_periodicity sr_period = srsran::sr_periodicity::sl_40; - csi_report_periodicity csi_period = srsran::csi_report_periodicity::slots80; + sr_periodicity sr_period = sr_periodicity::sl_40; + csi_report_periodicity csi_period = csi_report_periodicity::slots80; }; std::ostream& operator<<(std::ostream& out, const pucch_cnt_builder_params& params) diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 65ee1975ca..91ea1c2bb1 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -103,8 +103,7 @@ bool srsran::pucch_info_match(const pucch_info& expected, const pucch_info& test expected_f.csi_part1_bits == test_f.csi_part1_bits && expected_f.slot_repetition == test_f.slot_repetition && expected_f.n_id_scrambling == test_f.n_id_scrambling && expected_f.pi_2_bpsk == test_f.pi_2_bpsk && expected_f.max_code_rate == test_f.max_code_rate && expected_f.additional_dmrs == test_f.additional_dmrs && - expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling && - expected_f.m_0_cyclic_shift == test_f.m_0_cyclic_shift; + expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling; } break; case pucch_format::FORMAT_4: { const pucch_format_4& expected_f = expected.format_4; @@ -117,8 +116,7 @@ bool srsran::pucch_info_match(const pucch_info& expected, const pucch_info& test expected_f.n_id_scrambling == test_f.n_id_scrambling && expected_f.pi_2_bpsk == test_f.pi_2_bpsk && expected_f.max_code_rate == test_f.max_code_rate && expected_f.orthog_seq_idx == test_f.orthog_seq_idx && expected_f.n_sf_pucch_f4 == test_f.n_sf_pucch_f4 && expected_f.additional_dmrs == test_f.additional_dmrs && - expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling && - expected_f.m_0_cyclic_shift == test_f.m_0_cyclic_shift; + expected_f.n_id_0_scrambling == test_f.n_id_0_scrambling; } break; default: { return false; From 11290bc7937714d5075cf7c82ac467154a151322 Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Fri, 13 Dec 2024 14:05:54 +0100 Subject: [PATCH 155/227] fapi: document fapi parameters for pucch format 3 and 4 --- lib/fapi_adaptor/mac/messages/pucch.cpp | 27 ++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index 1a3bd67262..7331270f05 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -119,13 +119,13 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p // Hopping parameters. const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; - - // Cyclic shift index (m0) is always 0 for PUCCH Format 3, as per TS 38.211 6.4.1.3.3.1. - constexpr unsigned m0 = 0; + // Both FAPI parameters initialCyclicShift (ref. TS 38.211 6.3.2.2.2) and m0PucchDmrsCyclicShift (ref. + // TS 38.211 6.4.1.3.3.1) map to the same value, which is always 0 for PUCCH Format 3. + constexpr unsigned m0_format3 = 0; // Parameter initial_cyclic_shift is not applicable to PUCCH Format 3. builder.set_hopping_information_parameters( - intra_slot_freq_hop, hop_prbs.start(), f3.group_hopping, f3.n_id_hopping, m0); + intra_slot_freq_hop, hop_prbs.start(), f3.group_hopping, f3.n_id_hopping, m0_format3); // Common parameters. builder.set_common_parameters(mac_pdu.format, f3.slot_repetition, f3.pi_2_bpsk); @@ -134,7 +134,7 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_scrambling_parameters(f3.n_id_scrambling); // DM-RS. - builder.set_dmrs_parameters(f3.additional_dmrs, f3.n_id_0_scrambling, m0); + builder.set_dmrs_parameters(f3.additional_dmrs, f3.n_id_0_scrambling, m0_format3); // Max coding rate. builder.set_maintenance_v3_basic_parameters({static_cast(f3.max_code_rate)}, {}); @@ -143,7 +143,7 @@ static void fill_format3_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_bit_length_parameters(convert_sr_bits_to_unsigned(f3.sr_bits), f3.harq_ack_nof_bits, f3.csi_part1_bits); } -/// Gets the cyclic shift index (m0) for PUCCH Format 4, as per TS38.211 Table 6.4.1.3.3.1-1. +/// Gets the cyclic shift index (m0) for PUCCH Format 4, as per TS 38.211 Table 6.4.1.3.3.1-1. static unsigned get_pucch_format4_m0(unsigned occ_index) { switch (occ_index) { @@ -168,12 +168,12 @@ static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const p // Hopping parameters. const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; - // Parameter initial_cyclic_shift is not applicable to PUCCH Format 4. - builder.set_hopping_information_parameters(intra_slot_freq_hop, - hop_prbs.start(), - f4.group_hopping, - f4.n_id_hopping, - get_pucch_format4_m0(mac_pdu.format_4.orthog_seq_idx)); + // Both FAPI parameters initialCyclicShift (ref. TS 38.211 6.3.2.2.2) and m0PucchDmrsCyclicShift + // (ref. TS 38.211 6.4.1.3.3.1) map to the same value. + const unsigned m0_format4 = get_pucch_format4_m0(mac_pdu.format_4.orthog_seq_idx); + + builder.set_hopping_information_parameters( + intra_slot_freq_hop, hop_prbs.start(), f4.group_hopping, f4.n_id_hopping, m0_format4); // Common parameters. builder.set_common_parameters(mac_pdu.format, f4.slot_repetition, f4.pi_2_bpsk); @@ -182,8 +182,7 @@ static void fill_format4_parameters(fapi::ul_pucch_pdu_builder& builder, const p builder.set_scrambling_parameters(f4.n_id_scrambling); // DM-RS. - builder.set_dmrs_parameters( - f4.additional_dmrs, f4.n_id_0_scrambling, get_pucch_format4_m0(mac_pdu.format_4.orthog_seq_idx)); + builder.set_dmrs_parameters(f4.additional_dmrs, f4.n_id_0_scrambling, m0_format4); // Specific format 4 parameters. builder.set_format4_parameters(f4.orthog_seq_idx, static_cast(f4.n_sf_pucch_f4)); From 95befa6c1745a5de026176c6a6ff9a3a5ff048ec Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 18:55:25 +0100 Subject: [PATCH 156/227] sched: use average assignment of RBs to perform RR between slices --- lib/scheduler/slicing/ran_slice_instance.cpp | 11 +++++++++-- lib/scheduler/slicing/ran_slice_instance.h | 7 +++++++ lib/scheduler/slicing/slice_scheduler.cpp | 4 +++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index dde039ce72..7cdfc7f20c 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -25,12 +25,19 @@ ran_slice_instance::ran_slice_instance(ran_slice_id_t id_, void ran_slice_instance::slot_indication(slot_point slot_tx) { + static constexpr float exp_avg_coeff = 0.1; + avg_pdsch_rbs_per_slot += exp_avg_coeff * (static_cast(pdsch_rb_count) - avg_pdsch_rbs_per_slot); pdsch_rb_count = 0; - // Clear RB count in previous slots. + + // Clear PUSCH RB count in previous slots. // NOTE: RB count in \c nof_slots_to_clear number of slots are cleared because \c slot_indication() is called only // during DL slots. for (unsigned count = 0; count < nof_slots_to_clear; ++count) { - pusch_rb_count_per_slot[(slot_tx - 1 - count).to_uint() % pusch_rb_count_per_slot.size()] = 0; + slot_point old_slot = slot_tx - (nof_slots_to_clear - count); + unsigned idx = old_slot.to_uint() % pusch_rb_count_per_slot.size(); + avg_pusch_rbs_per_slot += + exp_avg_coeff * (static_cast(pusch_rb_count_per_slot[idx]) - avg_pusch_rbs_per_slot); + pusch_rb_count_per_slot[idx] = 0; } // Reset last alloc slot if the difference becomes too large, to avoid ambiguity. diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 7d7b1efab1..2aa3c33803 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -94,6 +94,9 @@ class ran_slice_instance : MAX_SLOTS_SINCE_LAST_PXSCH; } + float average_pdsch_rbs_per_slot() const { return avg_pdsch_rbs_per_slot; } + float average_pusch_rbs_per_slot() const { return avg_pusch_rbs_per_slot; } + ran_slice_id_t id; const cell_configuration* cell_cfg; slice_rrm_policy_config cfg; @@ -116,6 +119,10 @@ class ran_slice_instance // Last slot that the PUSCH was allocated. slot_point last_pusch_alloc_slot; + // Track average number of RBs scheduler per slice. + float avg_pdsch_rbs_per_slot = 0; + float avg_pusch_rbs_per_slot = 0; + slice_ue_repository slice_ues; }; diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index bdb3643d61..9bf41234c4 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -325,7 +325,9 @@ slice_scheduler::priority_type slice_scheduler::ran_slice_sched_context::get_pri delay_prio = std::min(delay_prio, delay_prio_bitmask); // Round-robin across slices with the same slice and delay priorities. - priority_type rr_prio = ((inst.id.value() + current_slot_count) % nof_slices) & ((1U << rr_bitsize) - 1U); + float rbs_per_slot = is_dl ? inst.average_pdsch_rbs_per_slot() : inst.average_pusch_rbs_per_slot(); + const unsigned rr_prio_max = (1U << rr_bitsize) - 1U; + priority_type rr_prio = rr_prio_max - std::min((unsigned)std::round(rbs_per_slot), rr_prio_max); return (slot_dist << (delay_prio_bitsize + rr_bitsize + slice_prio_bitsize)) + (slice_prio << (delay_prio_bitsize + rr_bitsize)) + (delay_prio << rr_bitsize) + rr_prio; From 8b3b220f9dd515400f703e229f92c5ccd46cedc2 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 9 Dec 2024 19:08:54 +0100 Subject: [PATCH 157/227] sched: fix failing unit test for inter slice scheduling --- .../scheduler/slicing/slice_scheduler_test.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index 798ac3dc63..cfe5173c26 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -383,11 +383,14 @@ TEST_F(rb_ratio_slice_scheduler_test, run_slot(); // High priority slices - auto next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), drb1_slice_id); - next_dl_slice->store_grant(MIN_SLICE_RB); - next_dl_slice = slice_sched.get_next_dl_candidate(); - ASSERT_EQ(next_dl_slice->id(), default_srb_slice_id); + std::optional next_dl_slice; + for (unsigned i = 0; i != 2; ++i) { + next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_TRUE(next_dl_slice->id() == drb1_slice_id or next_dl_slice->id() == default_srb_slice_id); + if (next_dl_slice->id() == drb1_slice_id) { + next_dl_slice->store_grant(MIN_SLICE_RB); + } + } // Lower priority candidates. next_dl_slice = slice_sched.get_next_dl_candidate(); From 2a2e1df40c66220567eed4dfbd6c075ba50a6e15 Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 12 Dec 2024 15:32:22 +0100 Subject: [PATCH 158/227] du-high: enable 256QAM if the UE supports it --- apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h | 2 +- .../o_du_high/du_high/du_high_config_cli11_schema.cpp | 2 +- .../ran_resource_management/ue_capability_manager.cpp | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index 85ace11aa8..e9821fff71 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -135,7 +135,7 @@ struct du_high_unit_pdsch_config { /// Redundancy version sequence to use. Each element can have one of the following values: {0, 1, 2, 3}. std::vector rv_sequence = {0, 2, 3, 1}; /// MCS table to use for PDSCH - pdsch_mcs_table mcs_table = pdsch_mcs_table::qam64; + pdsch_mcs_table mcs_table = pdsch_mcs_table::qam256; /// Minimum number of RBs for resource allocation of UE PDSCHs. unsigned min_rb_size = 1; /// Maximum number of RBs for resource allocation of UE PDSCHs. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 68c3a8380c..c2925b9d6a 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -255,7 +255,7 @@ static void configure_cli11_pdsch_args(CLI::App& app, du_high_unit_pdsch_config& } }, "MCS table to use PDSCH") - ->default_str("qam64") + ->default_str("qam256") ->check(CLI::IsMember({"qam64", "qam256"}, CLI::ignore_case)); add_option(app, "--min_rb_size", pdsch_params.min_rb_size, "Minimum RB size for UE PDSCH resource allocation") ->capture_default_str() 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 686693cfef..9b2b8a012e 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 @@ -212,12 +212,11 @@ pdsch_mcs_table ue_capability_manager::select_pdsch_mcs_table(du_cell_index_t ce { const auto& init_dl_bwp = base_cell_cfg_list[cell_idx].ue_ded_serv_cell_cfg.init_dl_bwp; - if (not init_dl_bwp.pdsch_cfg.has_value()) { + if (not init_dl_bwp.pdsch_cfg.has_value() or not ue_caps.has_value() or not ue_caps->pdsch_qam256_supported) { // No base cell PDSCH config. Default to QAM64. return pdsch_mcs_table::qam64; } - // TODO: Support dynamic change of the DL MCS table based on the UE capabilities. This requires changes in the - // scheduler. + return init_dl_bwp.pdsch_cfg->mcs_table; } From 3d05decc89d2289195d658cbb3cc9cb47cbfb4a7 Mon Sep 17 00:00:00 2001 From: frankist Date: Thu, 12 Dec 2024 18:09:03 +0100 Subject: [PATCH 159/227] sched: fix crash during rrc reconf if the PUCCH config changed --- .../uci_scheduling/uci_scheduler_impl.cpp | 14 ++++++++++++-- lib/scheduler/uci_scheduling/uci_scheduler_impl.h | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp index 7b176ac543..5f91b5fb99 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.cpp @@ -108,6 +108,11 @@ void uci_scheduler_impl::rem_resource(rnti_t crnti, unsigned res_offset, unsigne } void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) +{ + add_ue_to_grid(ue_cfg, false); +} + +void uci_scheduler_impl::add_ue_to_grid(const ue_cell_configuration& ue_cfg, bool is_reconf) { if (not ue_cfg.cfg_dedicated().ul_config.has_value() or not ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.has_value()) { @@ -136,7 +141,12 @@ void uci_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) } // Register the UE in the list of recently configured UEs. - updated_ues.push_back(ue_cfg.crnti); + // Note: We skip this step during RRC Reconfiguration because it would involve cancelling already scheduled UCIs + // in the grid. While we don't fully support this feature, we leave the old SR/CSI UCIs in the grid. The worst that + // can happen is some missed SRs or CSI in a short period of time. + if (not is_reconf) { + updated_ues.push_back(ue_cfg.crnti); + } } void uci_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, const ue_cell_configuration& old_ue_cfg) @@ -157,7 +167,7 @@ void uci_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, cons } rem_ue(old_ue_cfg); - add_ue(new_ue_cfg); + add_ue_to_grid(new_ue_cfg, true); } void uci_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) diff --git a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h index d22a9fc1d6..38bb4d6a05 100644 --- a/lib/scheduler/uci_scheduling/uci_scheduler_impl.h +++ b/lib/scheduler/uci_scheduling/uci_scheduler_impl.h @@ -12,7 +12,6 @@ #include "../ue_scheduling/ue_repository.h" #include "uci_scheduler.h" -#include "srsran/scheduler/resource_grid_util.h" namespace srsran { @@ -49,6 +48,8 @@ class uci_scheduler_impl final : public uci_scheduler // Helper that schedules the SR and CSI for UEs that were recently updated. void schedule_updated_ues_ucis(cell_resource_allocator& res_alloc); + void add_ue_to_grid(const ue_cell_configuration& ue_cfg, bool is_reconf); + void add_resource(rnti_t crnti, unsigned offset, unsigned period, bool is_sr); void rem_resource(rnti_t crnti, unsigned offset, unsigned period, bool is_sr); From a639475633059ec9c5a7b08b10e81439633f36b2 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 10:15:11 +0100 Subject: [PATCH 160/227] sched: avoid repeated SRSs during rrc reconfiguration --- lib/scheduler/srs/srs_scheduler_impl.cpp | 14 ++++++++++++-- lib/scheduler/srs/srs_scheduler_impl.h | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/srs/srs_scheduler_impl.cpp b/lib/scheduler/srs/srs_scheduler_impl.cpp index fe7c3d8dc5..596ace11ab 100644 --- a/lib/scheduler/srs/srs_scheduler_impl.cpp +++ b/lib/scheduler/srs/srs_scheduler_impl.cpp @@ -41,6 +41,11 @@ void srs_scheduler_impl::run_slot(cell_resource_allocator& cell_alloc) } void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) +{ + add_ue_to_grid(ue_cfg, false); +} + +void srs_scheduler_impl::add_ue_to_grid(const ue_cell_configuration& ue_cfg, bool is_reconf) { if (not ue_cfg.cfg_dedicated().ul_config.has_value() or not ue_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.srs_cfg.has_value()) { @@ -86,7 +91,12 @@ void srs_scheduler_impl::add_ue(const ue_cell_configuration& ue_cfg) } // Register the UE in the list of recently configured UEs. - updated_ues.push_back(ue_cfg.crnti); + // Note: We skip this step during RRC Reconfiguration because it would involve cancelling already scheduled SRSs + // in the grid. While we don't fully support this feature, we leave the old SRSs in the grid. The worst that + // can happen is some misdetected SRSs for a short period of time. + if (not is_reconf) { + updated_ues.push_back(ue_cfg.crnti); + } } void srs_scheduler_impl::rem_ue(const ue_cell_configuration& ue_cfg) @@ -151,7 +161,7 @@ void srs_scheduler_impl::reconf_ue(const ue_cell_configuration& new_ue_cfg, cons } rem_ue(old_ue_cfg); - add_ue(new_ue_cfg); + add_ue_to_grid(new_ue_cfg, true); } ///////////////////// Private functions //////////////////////////// diff --git a/lib/scheduler/srs/srs_scheduler_impl.h b/lib/scheduler/srs/srs_scheduler_impl.h index cf724809d2..e48f4db356 100644 --- a/lib/scheduler/srs/srs_scheduler_impl.h +++ b/lib/scheduler/srs/srs_scheduler_impl.h @@ -52,6 +52,8 @@ class srs_scheduler_impl : public srs_scheduler // Helper that fills the SRS PDU fields. void fill_srs_pdu(srs_info& pdu, const srs_config::srs_resource& srs_res_cfg, const ue_cell_configuration& ue_cfg); + void add_ue_to_grid(const ue_cell_configuration& ue_cfg, bool is_reconf); + void add_resource(rnti_t crnti, srs_periodicity period, unsigned offset, srs_config::srs_res_id res_id); void rem_resource(rnti_t crnti, srs_periodicity period, unsigned offset, srs_config::srs_res_id res_id); From 115df1204fd1c1159a7ab522ce9c4516c2f3e85c Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 12 Dec 2024 19:16:50 +0100 Subject: [PATCH 161/227] fapi: added FAPI decorator interface. FAPI logging and buffered now implement this interface --- include/srsran/du/du_high/o_du_high_config.h | 2 +- include/srsran/fapi/buffered_decorator.h | 36 --- .../fapi/buffered_decorator_factories.h | 32 --- include/srsran/fapi/decorator.h | 94 ++++++++ include/srsran/fapi/decorator_factory.h | 50 +++++ .../srsran/fapi/logging_decorator_factories.h | 35 --- .../fapi_adaptor/mac/mac_fapi_adaptor.h | 6 +- lib/du/du_high/o_du_high_factory.cpp | 208 ++++++------------ lib/du/du_high/o_du_high_impl.cpp | 6 +- lib/fapi/CMakeLists.txt | 7 +- lib/fapi/decorator_factory.cpp | 47 ++++ lib/fapi/decorator_helpers/CMakeLists.txt | 19 ++ .../slot_data_message_notifier_dispatcher.cpp | 49 +++++ .../slot_data_message_notifier_dispatcher.h | 46 ++++ .../slot_data_message_notifier_dummy.cpp | 40 ++++ .../slot_data_message_notifier_dummy.h | 39 ++++ .../slot_error_notifier_dispatcher.cpp | 30 +++ .../slot_error_notifier_dispatcher.h | 34 +++ .../slot_error_notifier_dummy.cpp | 19 ++ .../slot_error_notifier_dummy.h | 27 +++ .../slot_last_message_notifier_dispatcher.cpp | 30 +++ .../slot_last_message_notifier_dispatcher.h | 34 +++ .../slot_last_message_notifier_dummy.cpp | 20 ++ .../slot_last_message_notifier_dummy.h | 27 +++ .../slot_time_notifier_dummy.cpp | 20 ++ .../slot_time_notifier_dummy.h | 27 +++ lib/fapi/loggers/CMakeLists.txt | 9 +- .../loggers/logging_decorator_factories.cpp | 54 ----- lib/fapi/loggers/logging_decorator_impl.cpp | 74 +++++++ lib/fapi/loggers/logging_decorator_impl.h | 66 ++++++ .../logging_slot_data_notifier_decorator.cpp | 23 +- .../logging_slot_data_notifier_decorator.h | 10 +- .../logging_slot_error_notifier_decorator.cpp | 15 +- .../logging_slot_error_notifier_decorator.h | 10 +- .../logging_slot_time_notifier_decorator.cpp | 15 +- .../logging_slot_time_notifier_decorator.h | 10 +- lib/fapi/message_buffering/CMakeLists.txt | 11 +- .../buffered_decorator_factories.cpp | 23 -- .../buffered_decorator_impl.cpp | 29 --- .../buffered_decorator_impl.h | 46 ---- .../buffered_slot_gateway_task_dispatcher.cpp | 68 ------ .../message_bufferer_decorator_impl.cpp | 54 +++++ .../message_bufferer_decorator_impl.h | 76 +++++++ ...=> message_bufferer_slot_gateway_impl.cpp} | 30 +-- ...h => message_bufferer_slot_gateway_impl.h} | 6 +- ..._bufferer_slot_gateway_task_dispatcher.cpp | 69 ++++++ ...e_bufferer_slot_gateway_task_dispatcher.h} | 22 +- ...bufferer_slot_time_notifier_decorator.cpp} | 14 +- ...e_bufferer_slot_time_notifier_decorator.h} | 15 +- .../mac/mac_fapi_adaptor_impl.cpp | 6 +- lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.h | 6 +- .../fapi/message_buffering/CMakeLists.txt | 6 +- ...ssage_bufferer_slot_gateway_impl_test.cpp} | 16 +- 53 files changed, 1204 insertions(+), 563 deletions(-) delete mode 100644 include/srsran/fapi/buffered_decorator.h delete mode 100644 include/srsran/fapi/buffered_decorator_factories.h create mode 100644 include/srsran/fapi/decorator.h create mode 100644 include/srsran/fapi/decorator_factory.h delete mode 100644 include/srsran/fapi/logging_decorator_factories.h create mode 100644 lib/fapi/decorator_factory.cpp create mode 100644 lib/fapi/decorator_helpers/CMakeLists.txt create mode 100644 lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.cpp create mode 100644 lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.h create mode 100644 lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.cpp create mode 100644 lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.h create mode 100644 lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.cpp create mode 100644 lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.h create mode 100644 lib/fapi/decorator_helpers/slot_error_notifier_dummy.cpp create mode 100644 lib/fapi/decorator_helpers/slot_error_notifier_dummy.h create mode 100644 lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.cpp create mode 100644 lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.h create mode 100644 lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.cpp create mode 100644 lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.h create mode 100644 lib/fapi/decorator_helpers/slot_time_notifier_dummy.cpp create mode 100644 lib/fapi/decorator_helpers/slot_time_notifier_dummy.h delete mode 100644 lib/fapi/loggers/logging_decorator_factories.cpp create mode 100644 lib/fapi/loggers/logging_decorator_impl.cpp create mode 100644 lib/fapi/loggers/logging_decorator_impl.h delete mode 100644 lib/fapi/message_buffering/buffered_decorator_factories.cpp delete mode 100644 lib/fapi/message_buffering/buffered_decorator_impl.cpp delete mode 100644 lib/fapi/message_buffering/buffered_decorator_impl.h delete mode 100644 lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.cpp create mode 100644 lib/fapi/message_buffering/message_bufferer_decorator_impl.cpp create mode 100644 lib/fapi/message_buffering/message_bufferer_decorator_impl.h rename lib/fapi/message_buffering/{buffered_slot_gateway_impl.cpp => message_bufferer_slot_gateway_impl.cpp} (77%) rename lib/fapi/message_buffering/{buffered_slot_gateway_impl.h => message_bufferer_slot_gateway_impl.h} (93%) create mode 100644 lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.cpp rename lib/fapi/message_buffering/{buffered_slot_gateway_task_dispatcher.h => message_bufferer_slot_gateway_task_dispatcher.h} (58%) rename lib/fapi/message_buffering/{buffered_slot_time_notifier_decorator.cpp => message_bufferer_slot_time_notifier_decorator.cpp} (71%) rename lib/fapi/message_buffering/{buffered_slot_time_notifier_decorator.h => message_bufferer_slot_time_notifier_decorator.h} (64%) rename tests/unittests/fapi/message_buffering/{buffered_slot_gateway_impl_test.cpp => message_bufferer_slot_gateway_impl_test.cpp} (95%) diff --git a/include/srsran/du/du_high/o_du_high_config.h b/include/srsran/du/du_high/o_du_high_config.h index 0e05dbb104..06273bf5c7 100644 --- a/include/srsran/du/du_high/o_du_high_config.h +++ b/include/srsran/du/du_high/o_du_high_config.h @@ -45,7 +45,7 @@ struct o_du_high_config { struct o_du_high_sector_dependencies { fapi::slot_message_gateway* gateway = nullptr; fapi::slot_last_message_notifier* last_msg_notifier = nullptr; - /// FAPI buffered executor. + /// FAPI message bufferer executor. std::optional fapi_executor; }; diff --git a/include/srsran/fapi/buffered_decorator.h b/include/srsran/fapi/buffered_decorator.h deleted file mode 100644 index 5f7ac8fb39..0000000000 --- a/include/srsran/fapi/buffered_decorator.h +++ /dev/null @@ -1,36 +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 - -namespace srsran { -namespace fapi { - -class slot_time_message_notifier; -class slot_message_gateway; - -/// Buffered decorator interface. -class buffered_decorator -{ -public: - virtual ~buffered_decorator() = default; - - /// Returns the slot message gateway of this decorator. - virtual slot_message_gateway& get_slot_message_gateway() = 0; - - /// Returns the slot time message notifier of this decorator. - virtual slot_time_message_notifier& get_slot_time_message_notifier() = 0; - - /// Configures the slot time notifier this buffered decorator will forward time message notifications. - virtual void set_slot_time_notifier(slot_time_message_notifier& notifier) = 0; -}; - -} // namespace fapi -} // namespace srsran diff --git a/include/srsran/fapi/buffered_decorator_factories.h b/include/srsran/fapi/buffered_decorator_factories.h deleted file mode 100644 index 128ce788ec..0000000000 --- a/include/srsran/fapi/buffered_decorator_factories.h +++ /dev/null @@ -1,32 +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/fapi/buffered_decorator.h" -#include "srsran/ran/subcarrier_spacing.h" -#include - -namespace srsran { - -class task_executor; - -namespace fapi { - -class slot_message_gateway; - -/// Creates a buffered decorator. -std::unique_ptr create_buffered_decorator(unsigned l2_nof_slots_ahead, - subcarrier_spacing scs, - slot_message_gateway& gateway, - task_executor& executor); - -} // namespace fapi -} // namespace srsran diff --git a/include/srsran/fapi/decorator.h b/include/srsran/fapi/decorator.h new file mode 100644 index 0000000000..fed1a1c1f9 --- /dev/null +++ b/include/srsran/fapi/decorator.h @@ -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. + * + */ + +#pragma once + +#include + +namespace srsran { +namespace fapi { + +class slot_data_message_notifier; +class slot_error_message_notifier; +class slot_last_message_notifier; +class slot_message_gateway; +class slot_time_message_notifier; + +/// FAPI decorator interface. +class fapi_decorator +{ +public: + explicit fapi_decorator(std::unique_ptr next_decorator_) : next_decorator(std::move(next_decorator_)) + { + } + + virtual ~fapi_decorator() = default; + + /// Returns the slot last message notifier of this FAPI decorator. + virtual slot_last_message_notifier& get_slot_last_message_notifier() = 0; + + /// Returns the slot message gateway of this FAPI decorator. + virtual slot_message_gateway& get_slot_message_gateway() = 0; + + /// Returns the slot data message notifier of this FAPI decorator. + slot_data_message_notifier& get_slot_data_message_notifier() + { + return next_decorator ? next_decorator->get_slot_data_message_notifier() + : get_slot_data_message_notifier_from_this_decorator(); + } + + /// Returns the slot error message notifier of this FAPI decorator. + slot_error_message_notifier& get_slot_error_message_notifier() + { + return next_decorator ? next_decorator->get_slot_error_message_notifier() + : get_slot_error_message_notifier_from_this_decorator(); + } + + /// Returns the slot time message notifier of this FAPI decorator. + slot_time_message_notifier& get_slot_time_message_notifier() + { + return next_decorator ? next_decorator->get_slot_time_message_notifier() + : get_slot_time_message_notifier_from_this_decorator(); + } + + /// Sets the slot data message notifier of this FAPI decorator. + virtual void set_slot_data_message_notifier(slot_data_message_notifier& notifier) = 0; + + /// Sets the slot error message notifier of this FAPI decorator. + virtual void set_slot_error_message_notifier(slot_error_message_notifier& notifier) = 0; + + /// Sets the slot time message notifier of this FAPI decorator. + virtual void set_slot_time_message_notifier(slot_time_message_notifier& notifier) = 0; + +protected: + /// Connects the next decorator notifiers to this FAPI decorator. + void connect_notifiers() + { + next_decorator->set_slot_data_message_notifier(get_slot_data_message_notifier_from_this_decorator()); + next_decorator->set_slot_error_message_notifier(get_slot_error_message_notifier_from_this_decorator()); + next_decorator->set_slot_time_message_notifier(get_slot_time_message_notifier_from_this_decorator()); + } + +private: + /// Returns the slot data message notifier of this FAPI decorator. + virtual slot_data_message_notifier& get_slot_data_message_notifier_from_this_decorator() = 0; + + /// Returns the slot error message notifier of this FAPI decorator. + virtual slot_error_message_notifier& get_slot_error_message_notifier_from_this_decorator() = 0; + + /// Returns the slot time message notifier of this FAPI decorator. + virtual slot_time_message_notifier& get_slot_time_message_notifier_from_this_decorator() = 0; + +protected: + std::unique_ptr next_decorator = nullptr; +}; + +} // namespace fapi +} // namespace srsran diff --git a/include/srsran/fapi/decorator_factory.h b/include/srsran/fapi/decorator_factory.h new file mode 100644 index 0000000000..7a1e9a3a97 --- /dev/null +++ b/include/srsran/fapi/decorator_factory.h @@ -0,0 +1,50 @@ +/* + * + * 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/fapi/decorator.h" +#include "srsran/ran/subcarrier_spacing.h" +#include "srsran/srslog/logger.h" +#include + +namespace srsran { + +class task_executor; + +namespace fapi { + +/// FAPI message bufferer decorator configuration. +struct message_bufferer_decorator_config { + unsigned l2_nof_slots_ahead; + subcarrier_spacing scs; + task_executor& executor; + slot_message_gateway& gateway; + slot_last_message_notifier& last_msg_notifier; +}; + +/// FAPI logging decorator configuration. +struct logging_decorator_config { + srslog::basic_logger& logger; + slot_message_gateway& gateway; + slot_last_message_notifier& last_msg_notifier; +}; + +/// FAPI decorator configurations. +struct decorator_config { + std::optional bufferer_cfg; + std::optional logging_cfg; +}; + +/// Creates and returns FAPI decorators using the given configuration or nullptr if no decorators are requested. +std::unique_ptr create_decorators(const decorator_config& config); + +} // namespace fapi +} // namespace srsran diff --git a/include/srsran/fapi/logging_decorator_factories.h b/include/srsran/fapi/logging_decorator_factories.h deleted file mode 100644 index 564dcfb8df..0000000000 --- a/include/srsran/fapi/logging_decorator_factories.h +++ /dev/null @@ -1,35 +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/fapi/slot_data_message_notifier.h" -#include "srsran/fapi/slot_error_message_notifier.h" -#include "srsran/fapi/slot_message_gateway.h" -#include "srsran/fapi/slot_time_message_notifier.h" -#include - -namespace srsran { -namespace fapi { - -/// Decorates the given slot message gateway with logging capabilities. -std::unique_ptr create_logging_slot_gateway(slot_message_gateway& gateway); - -/// Decorates the given slot time notifier with logging capabilities. -std::unique_ptr create_logging_slot_time_notifier(slot_time_message_notifier& notifier); - -/// Decorates the given slot error notifier with logging capabilities. -std::unique_ptr create_logging_slot_error_notifier(slot_error_message_notifier& notifier); - -/// Decorates the given slot data notifier with logging capabilities. -std::unique_ptr create_logging_slot_data_notifier(slot_data_message_notifier& notifier); - -} // namespace fapi -} // namespace srsran diff --git a/include/srsran/fapi_adaptor/mac/mac_fapi_adaptor.h b/include/srsran/fapi_adaptor/mac/mac_fapi_adaptor.h index cf4f6950ce..f5015b6dfe 100644 --- a/include/srsran/fapi_adaptor/mac/mac_fapi_adaptor.h +++ b/include/srsran/fapi_adaptor/mac/mac_fapi_adaptor.h @@ -38,13 +38,13 @@ class mac_fapi_adaptor virtual ~mac_fapi_adaptor() = default; /// \brief Returns a reference to the slot time notifier used by the adaptor. - virtual fapi::slot_time_message_notifier& get_slot_time_notifier() = 0; + virtual fapi::slot_time_message_notifier& get_slot_time_message_notifier() = 0; /// \brief Returns a reference to the slot error notifier used by the adaptor. - virtual fapi::slot_error_message_notifier& get_slot_error_notifier() = 0; + virtual fapi::slot_error_message_notifier& get_slot_error_message_notifier() = 0; /// \brief Returns a reference to the slot data notifier used by the adaptor. - virtual fapi::slot_data_message_notifier& get_slot_data_notifier() = 0; + virtual fapi::slot_data_message_notifier& get_slot_data_message_notifier() = 0; /// \brief Returns a reference to the MAC cell results notifier used by the adaptor. virtual mac_cell_result_notifier& get_cell_result_notifier() = 0; diff --git a/lib/du/du_high/o_du_high_factory.cpp b/lib/du/du_high/o_du_high_factory.cpp index 382171c279..f0665aa886 100644 --- a/lib/du/du_high/o_du_high_factory.cpp +++ b/lib/du/du_high/o_du_high_factory.cpp @@ -12,8 +12,7 @@ #include "o_du_high_impl.h" #include "srsran/du/du_high/du_high_factory.h" #include "srsran/e2/e2_du_factory.h" -#include "srsran/fapi/buffered_decorator_factories.h" -#include "srsran/fapi/logging_decorator_factories.h" +#include "srsran/fapi/decorator_factory.h" #include "srsran/fapi/messages.h" #include "srsran/fapi_adaptor/mac/mac_fapi_adaptor_factory.h" #include "srsran/fapi_adaptor/precoding_matrix_table_generator.h" @@ -50,7 +49,7 @@ build_mac_fapi_adaptor(unsigned } static std::unique_ptr -build_fapi_adaptors(const du_cell_config& du_cell, const o_du_high_sector_dependencies& dependencies, unsigned sector) +build_fapi_adaptor(const du_cell_config& du_cell, const o_du_high_sector_dependencies& dependencies, unsigned sector) { srsran_assert(dependencies.gateway, "Invalid gateway"); srsran_assert(dependencies.last_msg_notifier, "Invalid last message notifier"); @@ -71,158 +70,80 @@ build_fapi_adaptors(const du_cell_config& du_cell, const o_du_high_sector_depend namespace { -/// MAC-FAPI adaptor with logging decorator. -class mac_fapi_adaptor_with_logger_impl : public fapi_adaptor::mac_fapi_adaptor +/// MAC-FAPI adaptor wrapper that wraps an adaptor and a FAPI decorator. +class mac_fapi_adaptor_wrapper : public fapi_adaptor::mac_fapi_adaptor { public: - mac_fapi_adaptor_with_logger_impl(const du_cell_config& du_cell, - const o_du_high_sector_dependencies& dependencies, - unsigned sector) : - logging_slot_gateway(fapi::create_logging_slot_gateway(*dependencies.gateway)), - adaptor([](const du_cell_config& du_cell_adapt, - const o_du_high_sector_dependencies& dependencies_adapt, - unsigned sector_id, - fapi::slot_message_gateway& gateway) { + mac_fapi_adaptor_wrapper(const du_cell_config& du_cell, + const o_du_high_sector_dependencies& dependencies, + unsigned sector, + std::unique_ptr decorator_) : + decorator(std::move(decorator_)), + adaptor([](const du_cell_config& du_cell_adapt, + unsigned sector_id, + fapi::slot_message_gateway& gateway, + fapi::slot_last_message_notifier& last_msg_notifier) { o_du_high_sector_dependencies adaptor_dependencies; - adaptor_dependencies.last_msg_notifier = dependencies_adapt.last_msg_notifier; + adaptor_dependencies.last_msg_notifier = &last_msg_notifier; adaptor_dependencies.gateway = &gateway; - return build_fapi_adaptors(du_cell_adapt, adaptor_dependencies, sector_id); - }(du_cell, dependencies, sector, *logging_slot_gateway)), - logging_slot_time_notifier(fapi::create_logging_slot_time_notifier(adaptor->get_slot_time_notifier())), - logging_slot_error_notifier(fapi::create_logging_slot_error_notifier(adaptor->get_slot_error_notifier())), - logging_slot_data_notifier(fapi::create_logging_slot_data_notifier(adaptor->get_slot_data_notifier())) + return build_fapi_adaptor(du_cell_adapt, adaptor_dependencies, sector_id); + }(du_cell, + sector, + decorator ? decorator->get_slot_message_gateway() : *dependencies.gateway, + decorator ? decorator->get_slot_last_message_notifier() : *dependencies.last_msg_notifier)) { - } - fapi::slot_time_message_notifier& get_slot_time_notifier() override { return *logging_slot_time_notifier; } - fapi::slot_error_message_notifier& get_slot_error_notifier() override { return *logging_slot_error_notifier; } - fapi::slot_data_message_notifier& get_slot_data_notifier() override { return *logging_slot_data_notifier; } - mac_cell_result_notifier& get_cell_result_notifier() override { return adaptor->get_cell_result_notifier(); } - void set_cell_slot_handler(mac_cell_slot_handler& mac_slot_handler) override - { - adaptor->set_cell_slot_handler(mac_slot_handler); - } - void set_cell_rach_handler(mac_cell_rach_handler& mac_rach_handler) override - { - adaptor->set_cell_rach_handler(mac_rach_handler); - } - void set_cell_pdu_handler(mac_pdu_handler& handler) override { adaptor->set_cell_pdu_handler(handler); } - void set_cell_crc_handler(mac_cell_control_information_handler& handler) override - { - adaptor->set_cell_crc_handler(handler); + if (decorator) { + decorator->set_slot_data_message_notifier(adaptor->get_slot_data_message_notifier()); + decorator->set_slot_error_message_notifier(adaptor->get_slot_error_message_notifier()); + decorator->set_slot_time_message_notifier(adaptor->get_slot_time_message_notifier()); + } } -private: - std::unique_ptr logging_slot_gateway; - std::unique_ptr adaptor; - std::unique_ptr logging_slot_time_notifier; - std::unique_ptr logging_slot_error_notifier; - std::unique_ptr logging_slot_data_notifier; -}; - -/// MAC-FAPI adaptor with message buffering decorator. -class mac_fapi_adaptor_with_message_buffering_impl : public fapi_adaptor::mac_fapi_adaptor -{ -public: - mac_fapi_adaptor_with_message_buffering_impl(const du_cell_config& du_cell, - const o_du_high_sector_dependencies& dependencies, - unsigned sector, - unsigned l2_nof_slots_ahead) : - buffered_modules(fapi::create_buffered_decorator(l2_nof_slots_ahead, - du_cell.scs_common, - *dependencies.gateway, - *dependencies.fapi_executor.value())), - adaptor([](const du_cell_config& du_cell_adapt, - const o_du_high_sector_dependencies& dependencies_adapt, - unsigned sector_id, - fapi::slot_message_gateway& gateway) { - o_du_high_sector_dependencies adaptor_dependencies; - adaptor_dependencies.last_msg_notifier = dependencies_adapt.last_msg_notifier; - adaptor_dependencies.gateway = &gateway; - return build_fapi_adaptors(du_cell_adapt, adaptor_dependencies, sector_id); - }(du_cell, dependencies, sector, buffered_modules->get_slot_message_gateway())) - { - buffered_modules->set_slot_time_notifier(adaptor->get_slot_time_notifier()); - } - fapi::slot_time_message_notifier& get_slot_time_notifier() override + // See interface for documentation. + fapi::slot_time_message_notifier& get_slot_time_message_notifier() override { - return buffered_modules->get_slot_time_message_notifier(); - } - fapi::slot_error_message_notifier& get_slot_error_notifier() override { return adaptor->get_slot_error_notifier(); } - fapi::slot_data_message_notifier& get_slot_data_notifier() override { return adaptor->get_slot_data_notifier(); } - mac_cell_result_notifier& get_cell_result_notifier() override { return adaptor->get_cell_result_notifier(); } - void set_cell_slot_handler(mac_cell_slot_handler& mac_slot_handler) override - { - adaptor->set_cell_slot_handler(mac_slot_handler); + return decorator ? decorator->get_slot_time_message_notifier() : adaptor->get_slot_time_message_notifier(); } - void set_cell_rach_handler(mac_cell_rach_handler& mac_rach_handler) override + + // See interface for documentation. + fapi::slot_error_message_notifier& get_slot_error_message_notifier() override { - adaptor->set_cell_rach_handler(mac_rach_handler); + return decorator ? decorator->get_slot_error_message_notifier() : adaptor->get_slot_error_message_notifier(); } - void set_cell_pdu_handler(mac_pdu_handler& handler) override { adaptor->set_cell_pdu_handler(handler); } - void set_cell_crc_handler(mac_cell_control_information_handler& handler) override + + // See interface for documentation. + fapi::slot_data_message_notifier& get_slot_data_message_notifier() override { - adaptor->set_cell_crc_handler(handler); + return decorator ? decorator->get_slot_data_message_notifier() : adaptor->get_slot_data_message_notifier(); } -private: - std::unique_ptr buffered_modules; - std::unique_ptr adaptor; -}; + // See interface for documentation. + mac_cell_result_notifier& get_cell_result_notifier() override { return adaptor->get_cell_result_notifier(); } -/// MAC-FAPI adaptor with logging and message buffering decorators. -class mac_fapi_adaptor_with_logger_and_message_buffering_impl : public fapi_adaptor::mac_fapi_adaptor -{ -public: - mac_fapi_adaptor_with_logger_and_message_buffering_impl(const du_cell_config& du_cell, - const o_du_high_sector_dependencies& dependencies, - unsigned sector, - unsigned l2_nof_slots_ahead) : - logging_slot_gateway(fapi::create_logging_slot_gateway(*dependencies.gateway)), - buffered_modules(fapi::create_buffered_decorator(l2_nof_slots_ahead, - du_cell.scs_common, - *logging_slot_gateway, - *dependencies.fapi_executor.value())), - adaptor([](const du_cell_config& du_cell_adapt, - const o_du_high_sector_dependencies& dependencies_adapt, - unsigned sector_id, - fapi::slot_message_gateway& gateway) { - o_du_high_sector_dependencies adaptor_dependencies; - adaptor_dependencies.last_msg_notifier = dependencies_adapt.last_msg_notifier; - adaptor_dependencies.gateway = &gateway; - return build_fapi_adaptors(du_cell_adapt, adaptor_dependencies, sector_id); - }(du_cell, dependencies, sector, buffered_modules->get_slot_message_gateway())), - logging_slot_time_notifier( - fapi::create_logging_slot_time_notifier(buffered_modules->get_slot_time_message_notifier())), - logging_slot_error_notifier(fapi::create_logging_slot_error_notifier(adaptor->get_slot_error_notifier())), - logging_slot_data_notifier(fapi::create_logging_slot_data_notifier(adaptor->get_slot_data_notifier())) - { - buffered_modules->set_slot_time_notifier(adaptor->get_slot_time_notifier()); - } - fapi::slot_time_message_notifier& get_slot_time_notifier() override { return *logging_slot_time_notifier; } - fapi::slot_error_message_notifier& get_slot_error_notifier() override { return *logging_slot_error_notifier; } - fapi::slot_data_message_notifier& get_slot_data_notifier() override { return *logging_slot_data_notifier; } - mac_cell_result_notifier& get_cell_result_notifier() override { return adaptor->get_cell_result_notifier(); } - void set_cell_slot_handler(mac_cell_slot_handler& mac_slot_handler) override + // See interface for documentation. + void set_cell_slot_handler(mac_cell_slot_handler& mac_slot_handler) override { adaptor->set_cell_slot_handler(mac_slot_handler); } + + // See interface for documentation. void set_cell_rach_handler(mac_cell_rach_handler& mac_rach_handler) override { adaptor->set_cell_rach_handler(mac_rach_handler); } + + // See interface for documentation. void set_cell_pdu_handler(mac_pdu_handler& handler) override { adaptor->set_cell_pdu_handler(handler); } + + // See interface for documentation. void set_cell_crc_handler(mac_cell_control_information_handler& handler) override { adaptor->set_cell_crc_handler(handler); } private: - std::unique_ptr logging_slot_gateway; - std::unique_ptr buffered_modules; - std::unique_ptr adaptor; - std::unique_ptr logging_slot_time_notifier; - std::unique_ptr logging_slot_error_notifier; - std::unique_ptr logging_slot_data_notifier; + std::unique_ptr decorator; + std::unique_ptr adaptor; }; } // namespace @@ -240,25 +161,26 @@ resolve_o_du_high_impl_dependencies(const o_du_high_config& config, dependencies.logger = &srslog::fetch_basic_logger("DU"); for (unsigned i = 0, e = odu_dependencies.size(); i != e; ++i) { + fapi::decorator_config decorator_cfg; + if (config.fapi.log_level == srslog::basic_levels::debug) { - if (config.fapi.l2_nof_slots_ahead == 0) { - dependencies.du_high_adaptor.push_back( - std::make_unique(config.du_hi.ran.cells[i], odu_dependencies[i], i)); - } else { - srsran_assert(odu_dependencies[i].fapi_executor, "Invalid executor for the FAPI buffered decorator"); - dependencies.du_high_adaptor.push_back( - std::make_unique( - config.du_hi.ran.cells[i], odu_dependencies[i], i, config.fapi.l2_nof_slots_ahead)); - } - } else { - if (config.fapi.l2_nof_slots_ahead == 0) { - dependencies.du_high_adaptor.push_back(build_fapi_adaptors(config.du_hi.ran.cells[i], odu_dependencies[i], i)); - } else { - srsran_assert(odu_dependencies[i].fapi_executor, "Invalid executor for the FAPI buffered decorator"); - dependencies.du_high_adaptor.push_back(std::make_unique( - config.du_hi.ran.cells[i], odu_dependencies[i], i, config.fapi.l2_nof_slots_ahead)); - } + decorator_cfg.logging_cfg.emplace(fapi::logging_decorator_config{srslog::fetch_basic_logger("FAPI", true), + *odu_dependencies[i].gateway, + *odu_dependencies[i].last_msg_notifier}); } + + if (config.fapi.l2_nof_slots_ahead != 0) { + srsran_assert(odu_dependencies[i].fapi_executor, "Invalid executor for the FAPI message bufferer decorator"); + decorator_cfg.bufferer_cfg.emplace( + fapi::message_bufferer_decorator_config{config.fapi.l2_nof_slots_ahead, + config.du_hi.ran.cells[i].scs_common, + *odu_dependencies[i].fapi_executor.value(), + *odu_dependencies[i].gateway, + *odu_dependencies[i].last_msg_notifier}); + } + + dependencies.du_high_adaptor.push_back(std::make_unique( + config.du_hi.ran.cells[i], odu_dependencies[i], i, fapi::create_decorators(decorator_cfg))); } return dependencies; diff --git a/lib/du/du_high/o_du_high_impl.cpp b/lib/du/du_high/o_du_high_impl.cpp index c5c37169d4..3af508901b 100644 --- a/lib/du/du_high/o_du_high_impl.cpp +++ b/lib/du/du_high/o_du_high_impl.cpp @@ -105,7 +105,7 @@ fapi::slot_data_message_notifier& o_du_high_impl::get_slot_data_message_notifier cell_id, du_high_adaptor.size()); - return du_high_adaptor[cell_id]->get_slot_data_notifier(); + return du_high_adaptor[cell_id]->get_slot_data_message_notifier(); } fapi::slot_error_message_notifier& o_du_high_impl::get_slot_error_message_notifier(unsigned cell_id) @@ -115,7 +115,7 @@ fapi::slot_error_message_notifier& o_du_high_impl::get_slot_error_message_notifi cell_id, du_high_adaptor.size()); - return du_high_adaptor[cell_id]->get_slot_error_notifier(); + return du_high_adaptor[cell_id]->get_slot_error_message_notifier(); } fapi::slot_time_message_notifier& o_du_high_impl::get_slot_time_message_notifier(unsigned cell_id) @@ -125,5 +125,5 @@ fapi::slot_time_message_notifier& o_du_high_impl::get_slot_time_message_notifier cell_id, du_high_adaptor.size()); - return du_high_adaptor[cell_id]->get_slot_time_notifier(); + return du_high_adaptor[cell_id]->get_slot_time_message_notifier(); } diff --git a/lib/fapi/CMakeLists.txt b/lib/fapi/CMakeLists.txt index 82a6677e71..81b19a9667 100644 --- a/lib/fapi/CMakeLists.txt +++ b/lib/fapi/CMakeLists.txt @@ -6,9 +6,14 @@ # the distribution. # +add_subdirectory(decorator_helpers) add_subdirectory(message_buffering) add_subdirectory(loggers) add_subdirectory(validators) +add_library(srsran_fapi_decorators STATIC decorator_factory.cpp) +target_link_libraries(srsran_fapi_decorators PRIVATE srsran_fapi_message_buffering srsran_fapi_loggers) +target_include_directories(srsran_fapi_decorators PRIVATE ${CMAKE_SOURCE_DIR}/lib/fapi) + add_library(srsran_fapi INTERFACE) -target_link_libraries(srsran_fapi INTERFACE srsran_fapi_message_buffering srsran_fapi_loggers srsran_fapi_validators) +target_link_libraries(srsran_fapi INTERFACE srsran_fapi_decorators srsran_fapi_validators) diff --git a/lib/fapi/decorator_factory.cpp b/lib/fapi/decorator_factory.cpp new file mode 100644 index 0000000000..e0683eb45f --- /dev/null +++ b/lib/fapi/decorator_factory.cpp @@ -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. + * + */ + +#include "srsran/fapi/decorator_factory.h" +#include "loggers/logging_decorator_impl.h" +#include "message_buffering/message_bufferer_decorator_impl.h" + +using namespace srsran; +using namespace fapi; + +std::unique_ptr fapi::create_decorators(const decorator_config& config) +{ + // Nothing to create. + if (!config.bufferer_cfg && !config.logging_cfg) { + return nullptr; + } + + // Create message bufferer decorator. + if (config.bufferer_cfg && !config.logging_cfg) { + const message_bufferer_decorator_config& cfg = config.bufferer_cfg.value(); + return std::make_unique( + cfg.l2_nof_slots_ahead, cfg.scs, cfg.gateway, cfg.last_msg_notifier, cfg.executor); + } + + // Create logging decorator. + if (!config.bufferer_cfg && config.logging_cfg) { + const logging_decorator_config& cfg = config.logging_cfg.value(); + return std::make_unique(cfg.logger, cfg.gateway, cfg.last_msg_notifier); + } + + // Create message bufferer and logging decorators. + const message_bufferer_decorator_config& bufferer_cfg = config.bufferer_cfg.value(); + auto bufferer_decorator = std::make_unique(bufferer_cfg.l2_nof_slots_ahead, + bufferer_cfg.scs, + bufferer_cfg.gateway, + bufferer_cfg.last_msg_notifier, + bufferer_cfg.executor); + + return std::make_unique(config.logging_cfg.value().logger, std::move(bufferer_decorator)); +} diff --git a/lib/fapi/decorator_helpers/CMakeLists.txt b/lib/fapi/decorator_helpers/CMakeLists.txt new file mode 100644 index 0000000000..4075e2f00d --- /dev/null +++ b/lib/fapi/decorator_helpers/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# 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 + slot_data_message_notifier_dummy.cpp + slot_error_notifier_dummy.cpp + slot_last_message_notifier_dummy.cpp + slot_time_notifier_dummy.cpp + slot_data_message_notifier_dispatcher.cpp + slot_error_notifier_dispatcher.cpp + slot_last_message_notifier_dispatcher.cpp +) + +add_library(srsran_fapi_decorator_helpers STATIC ${SOURCES}) diff --git a/lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.cpp b/lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.cpp new file mode 100644 index 0000000000..e33187410e --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.cpp @@ -0,0 +1,49 @@ +/* + * + * 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 "slot_data_message_notifier_dispatcher.h" +#include "slot_data_message_notifier_dummy.h" + +using namespace srsran; +using namespace fapi; + +static slot_data_message_notifier_dummy dummy_notifier; + +slot_data_message_notifier_dispatcher::slot_data_message_notifier_dispatcher() : notifier(&dummy_notifier) {} + +void slot_data_message_notifier_dispatcher::on_rx_data_indication(const rx_data_indication_message& msg) +{ + notifier->on_rx_data_indication(msg); +} + +void slot_data_message_notifier_dispatcher::on_crc_indication(const crc_indication_message& msg) +{ + notifier->on_crc_indication(msg); +} + +void slot_data_message_notifier_dispatcher::on_uci_indication(const uci_indication_message& msg) +{ + notifier->on_uci_indication(msg); +} + +void slot_data_message_notifier_dispatcher::on_srs_indication(const srs_indication_message& msg) +{ + notifier->on_srs_indication(msg); +} + +void slot_data_message_notifier_dispatcher::on_rach_indication(const rach_indication_message& msg) +{ + notifier->on_rach_indication(msg); +} + +void slot_data_message_notifier_dispatcher::set_slot_data_message_notifier(slot_data_message_notifier& data_notifier) +{ + notifier = &data_notifier; +} diff --git a/lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.h b/lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.h new file mode 100644 index 0000000000..35bd9f69e7 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_data_message_notifier_dispatcher.h @@ -0,0 +1,46 @@ +/* + * + * 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/fapi/slot_data_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Slot data message notifier dispatcher that forwards data messages to the configured notifier. +class slot_data_message_notifier_dispatcher : public slot_data_message_notifier +{ + slot_data_message_notifier* notifier = nullptr; + +public: + slot_data_message_notifier_dispatcher(); + + // See interface for documentation. + void on_rx_data_indication(const rx_data_indication_message& msg) override; + + // See interface for documentation. + void on_crc_indication(const crc_indication_message& msg) override; + + // See interface for documentation. + void on_uci_indication(const uci_indication_message& msg) override; + + // See interface for documentation. + void on_srs_indication(const srs_indication_message& msg) override; + + // See interface for documentation. + void on_rach_indication(const rach_indication_message& msg) override; + + /// Sets the slot data message notifier to the given one. + void set_slot_data_message_notifier(slot_data_message_notifier& data_notifier); +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.cpp b/lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.cpp new file mode 100644 index 0000000000..b7a2d20f79 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.cpp @@ -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. + * + */ + +#include "slot_data_message_notifier_dummy.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; +using namespace fapi; + +void slot_data_message_notifier_dummy::on_rx_data_indication(const rx_data_indication_message& msg) +{ + report_error("Dummy FAPI slot data message notifier cannot handle given rx data indication"); +} + +void slot_data_message_notifier_dummy::on_crc_indication(const crc_indication_message& msg) +{ + report_error("Dummy FAPI slot data message notifier cannot handle given CRC indication"); +} + +void slot_data_message_notifier_dummy::on_uci_indication(const uci_indication_message& msg) +{ + report_error("Dummy FAPI slot data message notifier cannot handle given UCI indication"); +} + +void slot_data_message_notifier_dummy::on_srs_indication(const srs_indication_message& msg) +{ + report_error("Dummy FAPI slot data message notifier cannot handle given SRS indication"); +} + +void slot_data_message_notifier_dummy::on_rach_indication(const rach_indication_message& msg) +{ + report_error("Dummy FAPI slot data message notifier cannot handle given RACH indication"); +} diff --git a/lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.h b/lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.h new file mode 100644 index 0000000000..cdf79eebe2 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_data_message_notifier_dummy.h @@ -0,0 +1,39 @@ +/* + * + * 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/fapi/slot_data_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Dummy slot data message notifier implementation that will terminate the application if its methods are called. +class slot_data_message_notifier_dummy : public slot_data_message_notifier +{ +public: + // See interface for documentation. + void on_rx_data_indication(const rx_data_indication_message& msg) override; + + // See interface for documentation. + void on_crc_indication(const crc_indication_message& msg) override; + + // See interface for documentation. + void on_uci_indication(const uci_indication_message& msg) override; + + // See interface for documentation. + void on_srs_indication(const srs_indication_message& msg) override; + + // See interface for documentation. + void on_rach_indication(const rach_indication_message& msg) override; +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.cpp b/lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.cpp new file mode 100644 index 0000000000..f66711d09d --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.cpp @@ -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. + * + */ + +#include "slot_error_notifier_dispatcher.h" +#include "slot_error_notifier_dummy.h" + +using namespace srsran; +using namespace fapi; + +static slot_error_message_notifier_dummy dummy_notifier; + +slot_error_message_notifier_dispatcher::slot_error_message_notifier_dispatcher() : notifier(&dummy_notifier) {} + +void slot_error_message_notifier_dispatcher::on_error_indication(const error_indication_message& msg) +{ + notifier->on_error_indication(msg); +} + +void slot_error_message_notifier_dispatcher::set_slot_error_message_notifier( + slot_error_message_notifier& error_notifier) +{ + notifier = &error_notifier; +} diff --git a/lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.h b/lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.h new file mode 100644 index 0000000000..f39a55b754 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_error_notifier_dispatcher.h @@ -0,0 +1,34 @@ +/* + * + * 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/fapi//slot_error_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Slot error message notifier dispatcher that forwards wrror messages to the configured notifier. +class slot_error_message_notifier_dispatcher : public slot_error_message_notifier +{ + slot_error_message_notifier* notifier = nullptr; + +public: + slot_error_message_notifier_dispatcher(); + + // See interface for documentation. + void on_error_indication(const error_indication_message& msg) override; + + /// Sets the slot error message notifier to the given one. + void set_slot_error_message_notifier(slot_error_message_notifier& error_notifier); +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/decorator_helpers/slot_error_notifier_dummy.cpp b/lib/fapi/decorator_helpers/slot_error_notifier_dummy.cpp new file mode 100644 index 0000000000..583ffd632f --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_error_notifier_dummy.cpp @@ -0,0 +1,19 @@ +/* + * + * 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 "slot_error_notifier_dummy.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; + +void fapi::slot_error_message_notifier_dummy::on_error_indication(const error_indication_message& msg) +{ + report_error("Dummy FAPI slot error message notifier cannot handle given error indication"); +} diff --git a/lib/fapi/decorator_helpers/slot_error_notifier_dummy.h b/lib/fapi/decorator_helpers/slot_error_notifier_dummy.h new file mode 100644 index 0000000000..c840f619f3 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_error_notifier_dummy.h @@ -0,0 +1,27 @@ +/* + * + * 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/fapi//slot_error_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Dummy FAPI slot error message notifier that will close the application if its methods are called. +class slot_error_message_notifier_dummy : public slot_error_message_notifier +{ +public: + // See interface for documentation. + void on_error_indication(const error_indication_message& msg) override; +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.cpp b/lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.cpp new file mode 100644 index 0000000000..ffa5ed679a --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.cpp @@ -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. + * + */ + +#include "slot_last_message_notifier_dispatcher.h" +#include "slot_last_message_notifier_dummy.h" + +using namespace srsran; +using namespace fapi; + +static slot_last_message_notifier_dummy dummy_notifier; + +slot_last_message_notifier_dispatcher::slot_last_message_notifier_dispatcher() : notifier(&dummy_notifier) {} + +void slot_last_message_notifier_dispatcher::on_last_message(slot_point slot) +{ + notifier->on_last_message(slot); +} + +void slot_last_message_notifier_dispatcher::set_slot_last_message_notifier( + slot_last_message_notifier& last_msg_notifier) +{ + notifier = &last_msg_notifier; +} diff --git a/lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.h b/lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.h new file mode 100644 index 0000000000..d177b51543 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_last_message_notifier_dispatcher.h @@ -0,0 +1,34 @@ +/* + * + * 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/fapi/slot_last_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Slot last message notifier dispatcher that forwards last message notifications to the configured notifier. +class slot_last_message_notifier_dispatcher : public slot_last_message_notifier +{ + slot_last_message_notifier* notifier = nullptr; + +public: + slot_last_message_notifier_dispatcher(); + + // See interface for documentation. + void on_last_message(slot_point slot) override; + + /// Sets the slot last message notifier to the given one. + void set_slot_last_message_notifier(slot_last_message_notifier& last_msg_notifier); +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.cpp b/lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.cpp new file mode 100644 index 0000000000..2f9466910d --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.cpp @@ -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. + * + */ + +#include "slot_last_message_notifier_dummy.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; +using namespace fapi; + +void slot_last_message_notifier_dummy::on_last_message(slot_point slot) +{ + report_error("Dummy FAPI slot last message notifier cannot handle given last message notification"); +} diff --git a/lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.h b/lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.h new file mode 100644 index 0000000000..4c718dda7b --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_last_message_notifier_dummy.h @@ -0,0 +1,27 @@ +/* + * + * 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/fapi/slot_last_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Dummy FAPI slot last message notifier that will close the application if its methods are called. +class slot_last_message_notifier_dummy : public slot_last_message_notifier +{ +public: + // See interface for documentation. + void on_last_message(slot_point slot) override; +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/decorator_helpers/slot_time_notifier_dummy.cpp b/lib/fapi/decorator_helpers/slot_time_notifier_dummy.cpp new file mode 100644 index 0000000000..091f2aa486 --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_time_notifier_dummy.cpp @@ -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. + * + */ + +#include "slot_time_notifier_dummy.h" +#include "srsran/support/error_handling.h" + +using namespace srsran; +using namespace fapi; + +void slot_time_message_notifier_dummy::on_slot_indication(const slot_indication_message& msg) +{ + report_error("Dummy FAPI slot time message notifier cannot handle given slot indication"); +} diff --git a/lib/fapi/decorator_helpers/slot_time_notifier_dummy.h b/lib/fapi/decorator_helpers/slot_time_notifier_dummy.h new file mode 100644 index 0000000000..fac1915dbc --- /dev/null +++ b/lib/fapi/decorator_helpers/slot_time_notifier_dummy.h @@ -0,0 +1,27 @@ +/* + * + * 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/fapi/slot_time_message_notifier.h" + +namespace srsran { +namespace fapi { + +/// Dummy FAPI slot time message notifier that will close the application if its methods are called. +class slot_time_message_notifier_dummy : public slot_time_message_notifier +{ +public: + // See interface for documentation. + void on_slot_indication(const slot_indication_message& msg) override; +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/loggers/CMakeLists.txt b/lib/fapi/loggers/CMakeLists.txt index ab87f1af24..e12c286da4 100644 --- a/lib/fapi/loggers/CMakeLists.txt +++ b/lib/fapi/loggers/CMakeLists.txt @@ -7,12 +7,13 @@ # set(SOURCES - message_loggers.cpp - logging_decorator_factories.cpp + logging_decorator_impl.cpp logging_slot_data_notifier_decorator.cpp logging_slot_error_notifier_decorator.cpp logging_slot_gateway_decorator.cpp - logging_slot_time_notifier_decorator.cpp) + logging_slot_time_notifier_decorator.cpp + message_loggers.cpp) add_library(srsran_fapi_loggers STATIC ${SOURCES}) -target_link_libraries(srsran_fapi_loggers srslog) +target_include_directories(srsran_fapi_loggers PRIVATE ${CMAKE_SOURCE_DIR}/lib/fapi) +target_link_libraries(srsran_fapi_loggers srslog srsran_fapi_decorator_helpers) diff --git a/lib/fapi/loggers/logging_decorator_factories.cpp b/lib/fapi/loggers/logging_decorator_factories.cpp deleted file mode 100644 index 14c3e7d1da..0000000000 --- a/lib/fapi/loggers/logging_decorator_factories.cpp +++ /dev/null @@ -1,54 +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/fapi/logging_decorator_factories.h" -#include "logging_slot_data_notifier_decorator.h" -#include "logging_slot_error_notifier_decorator.h" -#include "logging_slot_gateway_decorator.h" -#include "logging_slot_time_notifier_decorator.h" -#include "srsran/srslog/srslog.h" - -using namespace srsran; -using namespace fapi; - -std::unique_ptr srsran::fapi::create_logging_slot_gateway(slot_message_gateway& gateway) -{ - srslog::basic_logger& logger = srslog::fetch_basic_logger("FAPI", true); - logger.set_level(srslog::basic_levels::debug); - - return std::make_unique(logger, gateway); -} - -std::unique_ptr -srsran::fapi::create_logging_slot_time_notifier(slot_time_message_notifier& notifier) -{ - srslog::basic_logger& logger = srslog::fetch_basic_logger("FAPI", true); - logger.set_level(srslog::basic_levels::debug); - - return std::make_unique(logger, notifier); -} - -std::unique_ptr -srsran::fapi::create_logging_slot_error_notifier(slot_error_message_notifier& notifier) -{ - srslog::basic_logger& logger = srslog::fetch_basic_logger("FAPI", true); - logger.set_level(srslog::basic_levels::debug); - - return std::make_unique(logger, notifier); -} - -std::unique_ptr -srsran::fapi::create_logging_slot_data_notifier(slot_data_message_notifier& notifier) -{ - srslog::basic_logger& logger = srslog::fetch_basic_logger("FAPI", true); - logger.set_level(srslog::basic_levels::debug); - - return std::make_unique(logger, notifier); -} diff --git a/lib/fapi/loggers/logging_decorator_impl.cpp b/lib/fapi/loggers/logging_decorator_impl.cpp new file mode 100644 index 0000000000..f941493d1b --- /dev/null +++ b/lib/fapi/loggers/logging_decorator_impl.cpp @@ -0,0 +1,74 @@ +/* + * + * 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 "logging_decorator_impl.h" + +using namespace srsran; +using namespace fapi; + +logging_decorator_impl::logging_decorator_impl(srslog::basic_logger& logger, + slot_message_gateway& gateway_, + slot_last_message_notifier& last_msg_notifier_) : + fapi_decorator({}), data_notifier(logger), error_notifier(logger), time_notifier(logger), gateway(logger, gateway_) +{ + last_msg_notifier.set_slot_last_message_notifier(last_msg_notifier_); +} + +logging_decorator_impl::logging_decorator_impl(srslog::basic_logger& logger, + std::unique_ptr next_decorator_) : + fapi_decorator({std::move(next_decorator_)}), + data_notifier(logger), + error_notifier(logger), + time_notifier(logger), + gateway(logger, next_decorator->get_slot_message_gateway()) +{ + last_msg_notifier.set_slot_last_message_notifier(next_decorator->get_slot_last_message_notifier()); + connect_notifiers(); +} + +slot_data_message_notifier& logging_decorator_impl::get_slot_data_message_notifier_from_this_decorator() +{ + return data_notifier; +} + +slot_last_message_notifier& logging_decorator_impl::get_slot_last_message_notifier() +{ + return last_msg_notifier; +} + +slot_message_gateway& logging_decorator_impl::get_slot_message_gateway() +{ + return gateway; +} + +slot_error_message_notifier& logging_decorator_impl::get_slot_error_message_notifier_from_this_decorator() +{ + return error_notifier; +} + +slot_time_message_notifier& logging_decorator_impl::get_slot_time_message_notifier_from_this_decorator() +{ + return time_notifier; +} + +void logging_decorator_impl::set_slot_data_message_notifier(slot_data_message_notifier& notifier) +{ + data_notifier.set_slot_data_message_notifier(notifier); +} + +void logging_decorator_impl::set_slot_error_message_notifier(slot_error_message_notifier& notifier) +{ + error_notifier.set_slot_error_message_notifier(notifier); +} + +void logging_decorator_impl::set_slot_time_message_notifier(slot_time_message_notifier& notifier) +{ + time_notifier.set_slot_time_message_notifier(notifier); +} diff --git a/lib/fapi/loggers/logging_decorator_impl.h b/lib/fapi/loggers/logging_decorator_impl.h new file mode 100644 index 0000000000..49e305999e --- /dev/null +++ b/lib/fapi/loggers/logging_decorator_impl.h @@ -0,0 +1,66 @@ +/* + * + * 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 "decorator_helpers/slot_last_message_notifier_dispatcher.h" +#include "logging_slot_data_notifier_decorator.h" +#include "logging_slot_error_notifier_decorator.h" +#include "logging_slot_gateway_decorator.h" +#include "logging_slot_time_notifier_decorator.h" +#include "srsran/fapi/decorator.h" + +namespace srsran { +namespace fapi { + +class logging_decorator_impl : public fapi_decorator +{ +public: + logging_decorator_impl(srslog::basic_logger& logger, + slot_message_gateway& gateway_, + slot_last_message_notifier& last_msg_notifier_); + + logging_decorator_impl(srslog::basic_logger& logger, std::unique_ptr next_decorator_); + + // See interface for documentation. + slot_last_message_notifier& get_slot_last_message_notifier() override; + + // See interface for documentation. + slot_message_gateway& get_slot_message_gateway() override; + + // See interface for documentation. + void set_slot_data_message_notifier(slot_data_message_notifier& notifier) override; + + // See interface for documentation. + void set_slot_error_message_notifier(slot_error_message_notifier& notifier) override; + + // See interface for documentation. + void set_slot_time_message_notifier(slot_time_message_notifier& notifier) override; + +private: + // See interface for documentation. + slot_data_message_notifier& get_slot_data_message_notifier_from_this_decorator() override; + + // See interface for documentation. + slot_error_message_notifier& get_slot_error_message_notifier_from_this_decorator() override; + + // See interface for documentation. + slot_time_message_notifier& get_slot_time_message_notifier_from_this_decorator() override; + +private: + logging_slot_data_notifier_decorator data_notifier; + logging_slot_error_notifier_decorator error_notifier; + logging_slot_time_notifier_decorator time_notifier; + slot_last_message_notifier_dispatcher last_msg_notifier; + logging_slot_gateway_decorator gateway; +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/loggers/logging_slot_data_notifier_decorator.cpp b/lib/fapi/loggers/logging_slot_data_notifier_decorator.cpp index 8f6e126110..0c1408c37f 100644 --- a/lib/fapi/loggers/logging_slot_data_notifier_decorator.cpp +++ b/lib/fapi/loggers/logging_slot_data_notifier_decorator.cpp @@ -9,40 +9,53 @@ */ #include "logging_slot_data_notifier_decorator.h" +#include "decorator_helpers/slot_data_message_notifier_dummy.h" #include "message_loggers.h" using namespace srsran; using namespace fapi; +static slot_data_message_notifier_dummy dummy_notifier; + +logging_slot_data_notifier_decorator::logging_slot_data_notifier_decorator(srslog::basic_logger& logger_) : + logger(logger_), notifier(&dummy_notifier) +{ +} + void logging_slot_data_notifier_decorator::on_rx_data_indication(const rx_data_indication_message& msg) { log_rx_data_indication(msg, logger); - notifier.on_rx_data_indication(msg); + notifier->on_rx_data_indication(msg); } void logging_slot_data_notifier_decorator::on_crc_indication(const crc_indication_message& msg) { log_crc_indication(msg, logger); - notifier.on_crc_indication(msg); + notifier->on_crc_indication(msg); } void logging_slot_data_notifier_decorator::on_uci_indication(const uci_indication_message& msg) { log_uci_indication(msg, logger); - notifier.on_uci_indication(msg); + notifier->on_uci_indication(msg); } void logging_slot_data_notifier_decorator::on_srs_indication(const srs_indication_message& msg) { - notifier.on_srs_indication(msg); + notifier->on_srs_indication(msg); } void logging_slot_data_notifier_decorator::on_rach_indication(const rach_indication_message& msg) { log_rach_indication(msg, logger); - notifier.on_rach_indication(msg); + notifier->on_rach_indication(msg); +} + +void logging_slot_data_notifier_decorator::set_slot_data_message_notifier(slot_data_message_notifier& data_notifier) +{ + notifier = &data_notifier; } diff --git a/lib/fapi/loggers/logging_slot_data_notifier_decorator.h b/lib/fapi/loggers/logging_slot_data_notifier_decorator.h index 64f8c0cd0e..dfaf97f6ea 100644 --- a/lib/fapi/loggers/logging_slot_data_notifier_decorator.h +++ b/lib/fapi/loggers/logging_slot_data_notifier_decorator.h @@ -20,10 +20,7 @@ namespace fapi { class logging_slot_data_notifier_decorator : public slot_data_message_notifier { public: - logging_slot_data_notifier_decorator(srslog::basic_logger& logger_, slot_data_message_notifier& notifier_) : - logger(logger_), notifier(notifier_) - { - } + explicit logging_slot_data_notifier_decorator(srslog::basic_logger& logger_); // See interface for documentation. void on_rx_data_indication(const rx_data_indication_message& msg) override; @@ -40,10 +37,13 @@ class logging_slot_data_notifier_decorator : public slot_data_message_notifier // See interface for documentation. void on_rach_indication(const rach_indication_message& msg) override; + /// Sets the slot data message notifier to the given one. + void set_slot_data_message_notifier(slot_data_message_notifier& data_notifier); + private: /// FAPI logger. srslog::basic_logger& logger; - slot_data_message_notifier& notifier; + slot_data_message_notifier* notifier; }; } // namespace fapi diff --git a/lib/fapi/loggers/logging_slot_error_notifier_decorator.cpp b/lib/fapi/loggers/logging_slot_error_notifier_decorator.cpp index 8b4acb8f1c..6c7c61d948 100644 --- a/lib/fapi/loggers/logging_slot_error_notifier_decorator.cpp +++ b/lib/fapi/loggers/logging_slot_error_notifier_decorator.cpp @@ -9,14 +9,27 @@ */ #include "logging_slot_error_notifier_decorator.h" +#include "decorator_helpers/slot_error_notifier_dummy.h" #include "message_loggers.h" using namespace srsran; using namespace fapi; +static slot_error_message_notifier_dummy dummy_notifier; + +logging_slot_error_notifier_decorator::logging_slot_error_notifier_decorator(srslog::basic_logger& logger_) : + logger(logger_), notifier(&dummy_notifier) +{ +} + void logging_slot_error_notifier_decorator::on_error_indication(const error_indication_message& msg) { log_error_indication(msg, logger); - notifier.on_error_indication(msg); + notifier->on_error_indication(msg); +} + +void logging_slot_error_notifier_decorator::set_slot_error_message_notifier(slot_error_message_notifier& error_notifier) +{ + notifier = &error_notifier; } diff --git a/lib/fapi/loggers/logging_slot_error_notifier_decorator.h b/lib/fapi/loggers/logging_slot_error_notifier_decorator.h index febe1b3ee8..5bef8eaecb 100644 --- a/lib/fapi/loggers/logging_slot_error_notifier_decorator.h +++ b/lib/fapi/loggers/logging_slot_error_notifier_decorator.h @@ -20,19 +20,19 @@ namespace fapi { class logging_slot_error_notifier_decorator : public slot_error_message_notifier { public: - logging_slot_error_notifier_decorator(srslog::basic_logger& logger_, slot_error_message_notifier& notifier_) : - logger(logger_), notifier(notifier_) - { - } + explicit logging_slot_error_notifier_decorator(srslog::basic_logger& logger_); // See interface for documentation. void on_error_indication(const error_indication_message& msg) override; + /// Sets the slot error message notifier to the given one. + void set_slot_error_message_notifier(slot_error_message_notifier& error_notifier); + private: /// FAPI logger. srslog::basic_logger& logger; /// Error notifier. - slot_error_message_notifier& notifier; + slot_error_message_notifier* notifier; }; } // namespace fapi diff --git a/lib/fapi/loggers/logging_slot_time_notifier_decorator.cpp b/lib/fapi/loggers/logging_slot_time_notifier_decorator.cpp index 148f194795..5629b17873 100644 --- a/lib/fapi/loggers/logging_slot_time_notifier_decorator.cpp +++ b/lib/fapi/loggers/logging_slot_time_notifier_decorator.cpp @@ -9,14 +9,27 @@ */ #include "logging_slot_time_notifier_decorator.h" +#include "decorator_helpers/slot_time_notifier_dummy.h" #include "message_loggers.h" using namespace srsran; using namespace fapi; +static slot_time_message_notifier_dummy dummy_notifier; + +logging_slot_time_notifier_decorator::logging_slot_time_notifier_decorator(srslog::basic_logger& logger_) : + logger(logger_), notifier(&dummy_notifier) +{ +} + void logging_slot_time_notifier_decorator::on_slot_indication(const slot_indication_message& msg) { log_slot_indication(msg, logger); - notifier.on_slot_indication(msg); + notifier->on_slot_indication(msg); +} + +void logging_slot_time_notifier_decorator::set_slot_time_message_notifier(slot_time_message_notifier& time_notifier) +{ + notifier = &time_notifier; } diff --git a/lib/fapi/loggers/logging_slot_time_notifier_decorator.h b/lib/fapi/loggers/logging_slot_time_notifier_decorator.h index 3744e9a7ef..81bf850a94 100644 --- a/lib/fapi/loggers/logging_slot_time_notifier_decorator.h +++ b/lib/fapi/loggers/logging_slot_time_notifier_decorator.h @@ -20,18 +20,18 @@ namespace fapi { class logging_slot_time_notifier_decorator : public slot_time_message_notifier { public: - logging_slot_time_notifier_decorator(srslog::basic_logger& logger_, slot_time_message_notifier& notifier_) : - logger(logger_), notifier(notifier_) - { - } + explicit logging_slot_time_notifier_decorator(srslog::basic_logger& logger_); // See interface for documentation. void on_slot_indication(const slot_indication_message& msg) override; + /// Sets the slot time message notifier to the given one. + void set_slot_time_message_notifier(slot_time_message_notifier& time_notifier); + private: /// FAPI logger. srslog::basic_logger& logger; - slot_time_message_notifier& notifier; + slot_time_message_notifier* notifier; }; } // namespace fapi diff --git a/lib/fapi/message_buffering/CMakeLists.txt b/lib/fapi/message_buffering/CMakeLists.txt index 83d580a1be..69276cb781 100644 --- a/lib/fapi/message_buffering/CMakeLists.txt +++ b/lib/fapi/message_buffering/CMakeLists.txt @@ -7,10 +7,11 @@ # set(SOURCES - buffered_decorator_factories.cpp - buffered_decorator_impl.cpp - buffered_slot_gateway_impl.cpp - buffered_slot_gateway_task_dispatcher.cpp - buffered_slot_time_notifier_decorator.cpp) + message_bufferer_decorator_impl.cpp + message_bufferer_slot_gateway_impl.cpp + message_bufferer_slot_gateway_task_dispatcher.cpp + message_bufferer_slot_time_notifier_decorator.cpp) add_library(srsran_fapi_message_buffering STATIC ${SOURCES}) +target_include_directories(srsran_fapi_message_buffering PRIVATE ${CMAKE_SOURCE_DIR}/lib/fapi) +target_link_libraries(srsran_fapi_message_buffering PRIVATE srsran_fapi_decorator_helpers) diff --git a/lib/fapi/message_buffering/buffered_decorator_factories.cpp b/lib/fapi/message_buffering/buffered_decorator_factories.cpp deleted file mode 100644 index f8d620fa71..0000000000 --- a/lib/fapi/message_buffering/buffered_decorator_factories.cpp +++ /dev/null @@ -1,23 +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/fapi/buffered_decorator_factories.h" -#include "buffered_decorator_impl.h" - -using namespace srsran; -using namespace fapi; - -std::unique_ptr srsran::fapi::create_buffered_decorator(unsigned l2_nof_slots_ahead, - subcarrier_spacing scs, - slot_message_gateway& gateway, - task_executor& executor) -{ - return std::make_unique(l2_nof_slots_ahead, scs, gateway, executor); -} diff --git a/lib/fapi/message_buffering/buffered_decorator_impl.cpp b/lib/fapi/message_buffering/buffered_decorator_impl.cpp deleted file mode 100644 index 9759e48e51..0000000000 --- a/lib/fapi/message_buffering/buffered_decorator_impl.cpp +++ /dev/null @@ -1,29 +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 "buffered_decorator_impl.h" - -using namespace srsran; -using namespace fapi; - -slot_message_gateway& buffered_decorator_impl::get_slot_message_gateway() -{ - return dispatcher; -} - -slot_time_message_notifier& buffered_decorator_impl::get_slot_time_message_notifier() -{ - return time_notifier; -} - -void buffered_decorator_impl::set_slot_time_notifier(slot_time_message_notifier& notifier) -{ - time_notifier.set_slot_time_notifier(notifier); -} diff --git a/lib/fapi/message_buffering/buffered_decorator_impl.h b/lib/fapi/message_buffering/buffered_decorator_impl.h deleted file mode 100644 index 2b048b78b3..0000000000 --- a/lib/fapi/message_buffering/buffered_decorator_impl.h +++ /dev/null @@ -1,46 +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 "buffered_slot_gateway_task_dispatcher.h" -#include "buffered_slot_time_notifier_decorator.h" -#include "srsran/fapi/buffered_decorator.h" - -namespace srsran { -namespace fapi { - -class buffered_decorator_impl : public buffered_decorator -{ -public: - buffered_decorator_impl(unsigned l2_nof_slots_ahead, - subcarrier_spacing scs, - slot_message_gateway& gateway, - task_executor& executor) : - dispatcher(l2_nof_slots_ahead, scs, gateway, executor), time_notifier(l2_nof_slots_ahead, scs, dispatcher) - { - } - - // See interface for documentation. - slot_message_gateway& get_slot_message_gateway() override; - - // See interface for documentation. - slot_time_message_notifier& get_slot_time_message_notifier() override; - - // See interface for documentation. - void set_slot_time_notifier(slot_time_message_notifier& notifier) override; - -private: - buffered_slot_gateway_task_dispatcher dispatcher; - buffered_slot_time_notifier_decorator time_notifier; -}; - -} // namespace fapi -} // namespace srsran diff --git a/lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.cpp b/lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.cpp deleted file mode 100644 index 40b99bf666..0000000000 --- a/lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.cpp +++ /dev/null @@ -1,68 +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 "buffered_slot_gateway_task_dispatcher.h" -#include "srsran/fapi/messages.h" -#include "srsran/srslog/srslog.h" -#include "srsran/support/executors/task_executor.h" - -using namespace srsran; -using namespace fapi; - -buffered_slot_gateway_task_dispatcher::buffered_slot_gateway_task_dispatcher(unsigned l2_nof_slots_ahead, - subcarrier_spacing scs_, - fapi::slot_message_gateway& gateway, - task_executor& executor_) : - scs(scs_), - logger(srslog::fetch_basic_logger("FAPI")), - executor(executor_), - buffered_gateway(l2_nof_slots_ahead, scs_, gateway) -{ -} - -void buffered_slot_gateway_task_dispatcher::dl_tti_request(const dl_tti_request_message& msg) -{ - if (!executor.defer([this, msg]() { buffered_gateway.handle_dl_tti_request(msg); })) { - logger.warning("Failed to cache DL_TTI.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); - } -} - -void buffered_slot_gateway_task_dispatcher::ul_tti_request(const ul_tti_request_message& msg) -{ - if (!executor.defer([this, msg]() { buffered_gateway.handle_ul_tti_request(msg); })) { - logger.warning("Failed to cache UL_TTI.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); - } -} - -void buffered_slot_gateway_task_dispatcher::ul_dci_request(const ul_dci_request_message& msg) -{ - if (!executor.defer([this, msg]() { buffered_gateway.handle_ul_dci_request(msg); })) { - logger.warning("Failed to cache UL_DCI.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); - } -} - -void buffered_slot_gateway_task_dispatcher::tx_data_request(const tx_data_request_message& msg) -{ - if (!executor.defer([this, msg]() { buffered_gateway.handle_tx_data_request(msg); })) { - logger.warning("Failed to cache TX_Data.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); - } -} - -void buffered_slot_gateway_task_dispatcher::update_current_slot(slot_point slot) -{ - buffered_gateway.update_current_slot(slot); -} - -void buffered_slot_gateway_task_dispatcher::forward_cached_messages(slot_point slot) -{ - if (!executor.defer([this, slot]() { buffered_gateway.forward_cached_messages(slot); })) { - logger.warning("Failed to dispatch cached messages for slot '{}'", slot); - } -} diff --git a/lib/fapi/message_buffering/message_bufferer_decorator_impl.cpp b/lib/fapi/message_buffering/message_bufferer_decorator_impl.cpp new file mode 100644 index 0000000000..5241dd4b5d --- /dev/null +++ b/lib/fapi/message_buffering/message_bufferer_decorator_impl.cpp @@ -0,0 +1,54 @@ +/* + * + * 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 "message_bufferer_decorator_impl.h" + +using namespace srsran; +using namespace fapi; + +slot_message_gateway& message_bufferer_decorator_impl::get_slot_message_gateway() +{ + return dispatcher; +} + +slot_time_message_notifier& message_bufferer_decorator_impl::get_slot_time_message_notifier_from_this_decorator() +{ + return time_notifier; +} + +slot_data_message_notifier& message_bufferer_decorator_impl::get_slot_data_message_notifier_from_this_decorator() +{ + return data_notifier; +} + +slot_last_message_notifier& message_bufferer_decorator_impl::get_slot_last_message_notifier() +{ + return last_msg_notifier; +} + +slot_error_message_notifier& message_bufferer_decorator_impl::get_slot_error_message_notifier_from_this_decorator() +{ + return error_notifier; +} + +void message_bufferer_decorator_impl::set_slot_time_message_notifier(slot_time_message_notifier& notifier) +{ + time_notifier.set_slot_time_notifier(notifier); +} + +void message_bufferer_decorator_impl::set_slot_data_message_notifier(slot_data_message_notifier& notifier) +{ + data_notifier.set_slot_data_message_notifier(notifier); +} + +void message_bufferer_decorator_impl::set_slot_error_message_notifier(slot_error_message_notifier& notifier) +{ + error_notifier.set_slot_error_message_notifier(notifier); +} diff --git a/lib/fapi/message_buffering/message_bufferer_decorator_impl.h b/lib/fapi/message_buffering/message_bufferer_decorator_impl.h new file mode 100644 index 0000000000..8ffbf1a780 --- /dev/null +++ b/lib/fapi/message_buffering/message_bufferer_decorator_impl.h @@ -0,0 +1,76 @@ +/* + * + * 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 "decorator_helpers/slot_data_message_notifier_dispatcher.h" +#include "decorator_helpers/slot_error_notifier_dispatcher.h" +#include "decorator_helpers/slot_last_message_notifier_dispatcher.h" +#include "message_bufferer_slot_gateway_task_dispatcher.h" +#include "message_bufferer_slot_time_notifier_decorator.h" +#include "srsran/fapi/decorator.h" + +namespace srsran { +namespace fapi { + +/// \brief FAPI message bufferer decorator. +/// +/// The message bufferer caches FAPI messages that are send by the L2 and forwards them to the L1 when the +/// SLOT.indication that matches the FAPI message arrives. +class message_bufferer_decorator_impl : public fapi_decorator +{ +public: + message_bufferer_decorator_impl(unsigned l2_nof_slots_ahead, + subcarrier_spacing scs, + slot_message_gateway& gateway, + slot_last_message_notifier& last_msg_notifier_, + task_executor& executor) : + fapi_decorator({}), + dispatcher(l2_nof_slots_ahead, scs, gateway, executor), + time_notifier(l2_nof_slots_ahead, scs, dispatcher) + { + last_msg_notifier.set_slot_last_message_notifier(last_msg_notifier_); + } + + // See interface for documentation. + slot_message_gateway& get_slot_message_gateway() override; + + // See interface for documentation. + slot_last_message_notifier& get_slot_last_message_notifier() override; + + // See interface for documentation. + void set_slot_time_message_notifier(slot_time_message_notifier& notifier) override; + + // See interface for documentation. + void set_slot_data_message_notifier(slot_data_message_notifier& notifier) override; + + // See interface for documentation. + void set_slot_error_message_notifier(slot_error_message_notifier& notifier) override; + +private: + // See interface for documentation. + slot_time_message_notifier& get_slot_time_message_notifier_from_this_decorator() override; + + // See interface for documentation. + slot_data_message_notifier& get_slot_data_message_notifier_from_this_decorator() override; + + // See interface for documentation. + slot_error_message_notifier& get_slot_error_message_notifier_from_this_decorator() override; + +private: + message_bufferer_slot_gateway_task_dispatcher dispatcher; + message_bufferer_slot_time_notifier_decorator time_notifier; + slot_last_message_notifier_dispatcher last_msg_notifier; + slot_data_message_notifier_dispatcher data_notifier; + slot_error_message_notifier_dispatcher error_notifier; +}; + +} // namespace fapi +} // namespace srsran diff --git a/lib/fapi/message_buffering/buffered_slot_gateway_impl.cpp b/lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.cpp similarity index 77% rename from lib/fapi/message_buffering/buffered_slot_gateway_impl.cpp rename to lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.cpp index 9a1261d55c..6d7e780c7c 100644 --- a/lib/fapi/message_buffering/buffered_slot_gateway_impl.cpp +++ b/lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.cpp @@ -8,15 +8,15 @@ * */ -#include "buffered_slot_gateway_impl.h" +#include "message_bufferer_slot_gateway_impl.h" #include "srsran/srslog/srslog.h" using namespace srsran; using namespace fapi; -buffered_slot_gateway_impl::buffered_slot_gateway_impl(unsigned l2_nof_slots_ahead_, - subcarrier_spacing scs_, - slot_message_gateway& gateway_) : +message_bufferer_slot_gateway_impl::message_bufferer_slot_gateway_impl(unsigned l2_nof_slots_ahead_, + subcarrier_spacing scs_, + slot_message_gateway& gateway_) : l2_nof_slots_ahead(l2_nof_slots_ahead_), scs(scs_), gateway(gateway_), logger(srslog::fetch_basic_logger("FAPI")) { // Pool size is 1 unit bigger than the number of slots the L2 is ahead of the L1, in case that an incoming message @@ -35,7 +35,7 @@ buffered_slot_gateway_impl::buffered_slot_gateway_impl(unsigned l2_ } template -void buffered_slot_gateway_impl::handle_message(T&& msg, P pool, Function func) +void message_bufferer_slot_gateway_impl::handle_message(T&& msg, P pool, Function func) { slot_point msg_slot(scs, msg.sfn, msg.slot); slot_point current_slot = get_current_slot(); @@ -43,10 +43,12 @@ void buffered_slot_gateway_impl::handle_message(T&& msg, P pool, Function func) int difference = msg_slot - current_slot; if (difference > int(l2_nof_slots_ahead)) { - logger.warning("Skipping FAPI message as the difference between the slot of the message and the current slot '{}' " - "is bigger than the configured delay '{}'", - difference, - l2_nof_slots_ahead); + logger.warning( + "Skipping FAPI message as the difference '{}' between the slot of the message and the current slot '{}' " + "is bigger than the configured delay '{}'", + difference, + current_slot, + l2_nof_slots_ahead); return; } @@ -93,7 +95,7 @@ static void send_message(slot_point slot, pool_entry.reset(); } -void buffered_slot_gateway_impl::forward_cached_messages(slot_point slot) +void message_bufferer_slot_gateway_impl::forward_cached_messages(slot_point slot) { send_message( slot, scs, logger, dl_tti_pool, [this](const dl_tti_request_message& msg) { gateway.dl_tti_request(msg); }); @@ -108,28 +110,28 @@ void buffered_slot_gateway_impl::forward_cached_messages(slot_point slot) slot, scs, logger, tx_data_pool, [this](const tx_data_request_message& msg) { gateway.tx_data_request(msg); }); } -void buffered_slot_gateway_impl::handle_dl_tti_request(const dl_tti_request_message& msg) +void message_bufferer_slot_gateway_impl::handle_dl_tti_request(const dl_tti_request_message& msg) { handle_message(msg, span>(dl_tti_pool), [this](const dl_tti_request_message& message) { gateway.dl_tti_request(message); }); } -void buffered_slot_gateway_impl::handle_ul_tti_request(const ul_tti_request_message& msg) +void message_bufferer_slot_gateway_impl::handle_ul_tti_request(const ul_tti_request_message& msg) { handle_message(msg, span>(ul_tti_pool), [this](const ul_tti_request_message& message) { gateway.ul_tti_request(message); }); } -void buffered_slot_gateway_impl::handle_ul_dci_request(const ul_dci_request_message& msg) +void message_bufferer_slot_gateway_impl::handle_ul_dci_request(const ul_dci_request_message& msg) { handle_message(msg, span>(ul_dci_pool), [this](const ul_dci_request_message& message) { gateway.ul_dci_request(message); }); } -void buffered_slot_gateway_impl::handle_tx_data_request(const tx_data_request_message& msg) +void message_bufferer_slot_gateway_impl::handle_tx_data_request(const tx_data_request_message& msg) { handle_message(msg, span>(tx_data_pool), diff --git a/lib/fapi/message_buffering/buffered_slot_gateway_impl.h b/lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.h similarity index 93% rename from lib/fapi/message_buffering/buffered_slot_gateway_impl.h rename to lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.h index 16c5d71f08..6668dd7303 100644 --- a/lib/fapi/message_buffering/buffered_slot_gateway_impl.h +++ b/lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.h @@ -35,10 +35,12 @@ constexpr unsigned MAX_NUM_BUFFERED_MESSAGES = 8U; /// message is forwarded. /// - In the rest of the cases, the incoming message is stored in a buffer, waiting to be forwarded when the current /// slot matches the message slot. -class buffered_slot_gateway_impl +class message_bufferer_slot_gateway_impl { public: - buffered_slot_gateway_impl(unsigned l2_nof_slots_ahead_, subcarrier_spacing scs_, slot_message_gateway& gateway_); + message_bufferer_slot_gateway_impl(unsigned l2_nof_slots_ahead_, + subcarrier_spacing scs_, + slot_message_gateway& gateway_); /// Handles a DL_TTI.request message. void handle_dl_tti_request(const dl_tti_request_message& msg); diff --git a/lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.cpp b/lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.cpp new file mode 100644 index 0000000000..5a4e03a17b --- /dev/null +++ b/lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.cpp @@ -0,0 +1,69 @@ +/* + * + * 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 "message_bufferer_slot_gateway_task_dispatcher.h" +#include "srsran/fapi/messages.h" +#include "srsran/srslog/srslog.h" +#include "srsran/support/executors/task_executor.h" + +using namespace srsran; +using namespace fapi; + +message_bufferer_slot_gateway_task_dispatcher::message_bufferer_slot_gateway_task_dispatcher( + unsigned l2_nof_slots_ahead, + subcarrier_spacing scs_, + fapi::slot_message_gateway& gateway, + task_executor& executor_) : + scs(scs_), + logger(srslog::fetch_basic_logger("FAPI")), + executor(executor_), + message_bufferer_gateway(l2_nof_slots_ahead, scs_, gateway) +{ +} + +void message_bufferer_slot_gateway_task_dispatcher::dl_tti_request(const dl_tti_request_message& msg) +{ + if (!executor.defer([this, msg]() { message_bufferer_gateway.handle_dl_tti_request(msg); })) { + logger.warning("Failed to cache DL_TTI.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); + } +} + +void message_bufferer_slot_gateway_task_dispatcher::ul_tti_request(const ul_tti_request_message& msg) +{ + if (!executor.defer([this, msg]() { message_bufferer_gateway.handle_ul_tti_request(msg); })) { + logger.warning("Failed to cache UL_TTI.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); + } +} + +void message_bufferer_slot_gateway_task_dispatcher::ul_dci_request(const ul_dci_request_message& msg) +{ + if (!executor.defer([this, msg]() { message_bufferer_gateway.handle_ul_dci_request(msg); })) { + logger.warning("Failed to cache UL_DCI.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); + } +} + +void message_bufferer_slot_gateway_task_dispatcher::tx_data_request(const tx_data_request_message& msg) +{ + if (!executor.defer([this, msg]() { message_bufferer_gateway.handle_tx_data_request(msg); })) { + logger.warning("Failed to cache TX_Data.request message for slot '{}'", slot_point(scs, msg.sfn, msg.slot)); + } +} + +void message_bufferer_slot_gateway_task_dispatcher::update_current_slot(slot_point slot) +{ + message_bufferer_gateway.update_current_slot(slot); +} + +void message_bufferer_slot_gateway_task_dispatcher::forward_cached_messages(slot_point slot) +{ + if (!executor.defer([this, slot]() { message_bufferer_gateway.forward_cached_messages(slot); })) { + logger.warning("Failed to dispatch cached messages for slot '{}'", slot); + } +} diff --git a/lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.h b/lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.h similarity index 58% rename from lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.h rename to lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.h index f3094d473e..bda52d6f27 100644 --- a/lib/fapi/message_buffering/buffered_slot_gateway_task_dispatcher.h +++ b/lib/fapi/message_buffering/message_bufferer_slot_gateway_task_dispatcher.h @@ -10,7 +10,7 @@ #pragma once -#include "buffered_slot_gateway_impl.h" +#include "message_bufferer_slot_gateway_impl.h" #include "srsran/fapi/slot_time_message_notifier.h" namespace srsran { @@ -20,15 +20,15 @@ class task_executor; namespace fapi { /// Buffered slot gateway task dispatcher. -class buffered_slot_gateway_task_dispatcher : public slot_message_gateway +class message_bufferer_slot_gateway_task_dispatcher : public slot_message_gateway { public: - buffered_slot_gateway_task_dispatcher(unsigned l2_nof_slots_ahead, - subcarrier_spacing scs_, - slot_message_gateway& gateway, - task_executor& executor_); + message_bufferer_slot_gateway_task_dispatcher(unsigned l2_nof_slots_ahead, + subcarrier_spacing scs_, + slot_message_gateway& gateway, + task_executor& executor_); - /// Updates the current slot of the buffered slot gateway. + /// Updates the current slot of the message bufferer slot gateway. void update_current_slot(slot_point slot); /// Forwards cached messages for the given slot. @@ -47,10 +47,10 @@ class buffered_slot_gateway_task_dispatcher : public slot_message_gateway void tx_data_request(const tx_data_request_message& msg) override; private: - const subcarrier_spacing scs; - srslog::basic_logger& logger; - task_executor& executor; - buffered_slot_gateway_impl buffered_gateway; + const subcarrier_spacing scs; + srslog::basic_logger& logger; + task_executor& executor; + message_bufferer_slot_gateway_impl message_bufferer_gateway; }; } // namespace fapi diff --git a/lib/fapi/message_buffering/buffered_slot_time_notifier_decorator.cpp b/lib/fapi/message_buffering/message_bufferer_slot_time_notifier_decorator.cpp similarity index 71% rename from lib/fapi/message_buffering/buffered_slot_time_notifier_decorator.cpp rename to lib/fapi/message_buffering/message_bufferer_slot_time_notifier_decorator.cpp index dda70276e6..a21c76b4a9 100644 --- a/lib/fapi/message_buffering/buffered_slot_time_notifier_decorator.cpp +++ b/lib/fapi/message_buffering/message_bufferer_slot_time_notifier_decorator.cpp @@ -8,8 +8,8 @@ * */ -#include "buffered_slot_time_notifier_decorator.h" -#include "buffered_slot_gateway_task_dispatcher.h" +#include "message_bufferer_slot_time_notifier_decorator.h" +#include "message_bufferer_slot_gateway_task_dispatcher.h" #include "srsran/fapi/message_builders.h" #include "srsran/fapi/messages.h" #include "srsran/ran/slot_point.h" @@ -31,10 +31,10 @@ class slot_time_message_notifier_dummy : public slot_time_message_notifier static slot_time_message_notifier_dummy dummy_notifier; -buffered_slot_time_notifier_decorator::buffered_slot_time_notifier_decorator( - unsigned l2_nof_slots_ahead_, - subcarrier_spacing scs_, - buffered_slot_gateway_task_dispatcher& gateway_task_dispatcher_) : +message_bufferer_slot_time_notifier_decorator::message_bufferer_slot_time_notifier_decorator( + unsigned l2_nof_slots_ahead_, + subcarrier_spacing scs_, + message_bufferer_slot_gateway_task_dispatcher& gateway_task_dispatcher_) : l2_nof_slots_ahead(l2_nof_slots_ahead_), scs(scs_), gateway_task_dispatcher(gateway_task_dispatcher_), @@ -42,7 +42,7 @@ buffered_slot_time_notifier_decorator::buffered_slot_time_notifier_decorator( { } -void buffered_slot_time_notifier_decorator::on_slot_indication(const slot_indication_message& msg) +void message_bufferer_slot_time_notifier_decorator::on_slot_indication(const slot_indication_message& msg) { slot_point slot(scs, msg.sfn, msg.slot); diff --git a/lib/fapi/message_buffering/buffered_slot_time_notifier_decorator.h b/lib/fapi/message_buffering/message_bufferer_slot_time_notifier_decorator.h similarity index 64% rename from lib/fapi/message_buffering/buffered_slot_time_notifier_decorator.h rename to lib/fapi/message_buffering/message_bufferer_slot_time_notifier_decorator.h index 7ad0d333b9..9e872f7764 100644 --- a/lib/fapi/message_buffering/buffered_slot_time_notifier_decorator.h +++ b/lib/fapi/message_buffering/message_bufferer_slot_time_notifier_decorator.h @@ -15,26 +15,27 @@ namespace srsran { namespace fapi { -class buffered_slot_gateway_task_dispatcher; +class message_bufferer_slot_gateway_task_dispatcher; /// Advances the slot indication message by the value configured in construction. -class buffered_slot_time_notifier_decorator : public slot_time_message_notifier +class message_bufferer_slot_time_notifier_decorator : public slot_time_message_notifier { public: - buffered_slot_time_notifier_decorator(unsigned l2_nof_slots_ahead_, - subcarrier_spacing scs_, - buffered_slot_gateway_task_dispatcher& gateway_task_dispatcher_); + message_bufferer_slot_time_notifier_decorator( + unsigned l2_nof_slots_ahead_, + subcarrier_spacing scs_, + message_bufferer_slot_gateway_task_dispatcher& gateway_task_dispatcher_); // See interface for documentation. void on_slot_indication(const slot_indication_message& msg) override; - // Configures the buffered notifier to the given one. + // Configures the message bufferer notifier to the given one. void set_slot_time_notifier(slot_time_message_notifier& time_notifier) { notifier = std::ref(time_notifier); } private: const unsigned l2_nof_slots_ahead; const subcarrier_spacing scs; - buffered_slot_gateway_task_dispatcher& gateway_task_dispatcher; + message_bufferer_slot_gateway_task_dispatcher& gateway_task_dispatcher; std::reference_wrapper notifier; }; diff --git a/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.cpp b/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.cpp index 930f4255f6..a8d493636c 100644 --- a/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.cpp +++ b/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.cpp @@ -28,17 +28,17 @@ mac_fapi_adaptor_impl::mac_fapi_adaptor_impl(const mac_fapi_adaptor_config& con { } -fapi::slot_time_message_notifier& mac_fapi_adaptor_impl::get_slot_time_notifier() +fapi::slot_time_message_notifier& mac_fapi_adaptor_impl::get_slot_time_message_notifier() { return fapi_time_translator; } -fapi::slot_error_message_notifier& mac_fapi_adaptor_impl::get_slot_error_notifier() +fapi::slot_error_message_notifier& mac_fapi_adaptor_impl::get_slot_error_message_notifier() { return fapi_error_translator; } -fapi::slot_data_message_notifier& mac_fapi_adaptor_impl::get_slot_data_notifier() +fapi::slot_data_message_notifier& mac_fapi_adaptor_impl::get_slot_data_message_notifier() { return fapi_data_translator; } diff --git a/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.h b/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.h index 0cbbe16380..6d130fd04e 100644 --- a/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.h +++ b/lib/fapi_adaptor/mac/mac_fapi_adaptor_impl.h @@ -28,13 +28,13 @@ class mac_fapi_adaptor_impl : public mac_fapi_adaptor mac_fapi_adaptor_impl(const mac_fapi_adaptor_config& config, mac_fapi_adaptor_dependencies&& dependencies); // See interface for documentation. - fapi::slot_time_message_notifier& get_slot_time_notifier() override; + fapi::slot_time_message_notifier& get_slot_time_message_notifier() override; // See interface for documentation. - fapi::slot_error_message_notifier& get_slot_error_notifier() override; + fapi::slot_error_message_notifier& get_slot_error_message_notifier() override; // See interface for documentation. - fapi::slot_data_message_notifier& get_slot_data_notifier() override; + fapi::slot_data_message_notifier& get_slot_data_message_notifier() override; // See interface for documentation. mac_cell_result_notifier& get_cell_result_notifier() override; diff --git a/tests/unittests/fapi/message_buffering/CMakeLists.txt b/tests/unittests/fapi/message_buffering/CMakeLists.txt index 01c4aded78..ef405d44e4 100644 --- a/tests/unittests/fapi/message_buffering/CMakeLists.txt +++ b/tests/unittests/fapi/message_buffering/CMakeLists.txt @@ -8,6 +8,6 @@ set_directory_properties(PROPERTIES LABELS "fapi") -add_executable(buffered_slot_gateway_impl_test buffered_slot_gateway_impl_test.cpp) -target_link_libraries(buffered_slot_gateway_impl_test srsran_support srsran_fapi_message_builder_test_helpers srslog srsran_fapi gtest gtest_main) -gtest_discover_tests(buffered_slot_gateway_impl_test) +add_executable(message_bufferer_slot_gateway_impl_test message_bufferer_slot_gateway_impl_test.cpp) +target_link_libraries(message_bufferer_slot_gateway_impl_test srsran_support srsran_fapi_message_builder_test_helpers srslog srsran_fapi gtest gtest_main) +gtest_discover_tests(message_bufferer_slot_gateway_impl_test) diff --git a/tests/unittests/fapi/message_buffering/buffered_slot_gateway_impl_test.cpp b/tests/unittests/fapi/message_buffering/message_bufferer_slot_gateway_impl_test.cpp similarity index 95% rename from tests/unittests/fapi/message_buffering/buffered_slot_gateway_impl_test.cpp rename to tests/unittests/fapi/message_buffering/message_bufferer_slot_gateway_impl_test.cpp index 96a62755ff..ac88a064b9 100644 --- a/tests/unittests/fapi/message_buffering/buffered_slot_gateway_impl_test.cpp +++ b/tests/unittests/fapi/message_buffering/message_bufferer_slot_gateway_impl_test.cpp @@ -8,7 +8,7 @@ * */ -#include "../../../lib/fapi/message_buffering/buffered_slot_gateway_impl.h" +#include "../../../lib/fapi/message_buffering/message_bufferer_slot_gateway_impl.h" #include "../message_builder_helpers.h" #include @@ -273,7 +273,7 @@ TEST(bufferer_slot_gateway_impl_test, dl_tti_request_from_same_slot_is_transmitt subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); const dl_tti_request_message& msg = unittest::build_valid_dl_tti_request(); slot_point slot = slot_point(scs, msg.sfn, msg.slot); @@ -293,7 +293,7 @@ TEST(bufferer_slot_gateway_impl_test, cached_slot_is_sended_when_the_current_slo subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); slot_point current_slot(scs, 10, 0); dl_tti_request_message dl_tti_msg = unittest::build_valid_dl_tti_request(); @@ -369,7 +369,7 @@ TEST(bufferer_slot_gateway_impl_test, older_slots_than_supported_delay_are_sende subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); slot_point current_slot(scs, 5, 0); dl_tti_request_message msg = unittest::build_valid_dl_tti_request(); @@ -393,7 +393,7 @@ TEST(bufferer_slot_gateway_impl_test, message_with_slot_bigger_than_delay_deads) subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); slot_point current_slot(scs, 5, 0); dl_tti_request_message msg = unittest::build_valid_dl_tti_request(); @@ -414,7 +414,7 @@ TEST(bufferer_slot_gateway_impl_test, all_cached_slot_is_sended_when_the_current subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); slot_point current_slot(scs, 10, 0); dl_tti_request_message dl_tti_msg = unittest::build_valid_dl_tti_request(); @@ -461,7 +461,7 @@ TEST(bufferer_slot_gateway_impl_test, no_cached_messages_send_nothing) subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); slot_point current_slot(scs, 10, 0); @@ -480,7 +480,7 @@ TEST(bufferer_slot_gateway_impl_test, sended_messages_are_removed_from_the_pool) subcarrier_spacing scs = subcarrier_spacing::kHz30; slot_message_gateway_spy spy; - auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); + auto bufferer = std::make_unique(l2_nof_slots_ahead, scs, spy); slot_point current_slot(scs, 10, 0); dl_tti_request_message dl_tti_msg = unittest::build_valid_dl_tti_request(); From 8a679b4c6fa0c495e121318247a598dba0979389 Mon Sep 17 00:00:00 2001 From: Joaquim Broquetas Date: Fri, 13 Dec 2024 12:48:51 +0100 Subject: [PATCH 162/227] apps,du: set default TA target to 1 instead of 0 --- apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index e9821fff71..efd405f322 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -70,7 +70,7 @@ struct du_high_unit_ta_sched_expert_config { /// \remark T_A is defined in TS 38.213, clause 4.2. int ta_cmd_offset_threshold = 1; /// Timing Advance target in units of TA. - float ta_target = 0.0F; + float ta_target = 1.0F; /// UL SINR threshold (in dB) above which reported N_TA update measurement is considered valid. float ta_update_measurement_ul_sinr_threshold = 0.0F; }; From 81e14bc73ce542168feaeec0ec34137fd56392dd Mon Sep 17 00:00:00 2001 From: frankist Date: Sun, 15 Dec 2024 14:32:30 +0100 Subject: [PATCH 163/227] sched: fix meas gap calculation --- include/srsran/ran/meas_gap_config.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/srsran/ran/meas_gap_config.h b/include/srsran/ran/meas_gap_config.h index 3bf36a5671..1803a3f6e5 100644 --- a/include/srsran/ran/meas_gap_config.h +++ b/include/srsran/ran/meas_gap_config.h @@ -47,9 +47,10 @@ inline float meas_gap_length_to_msec(meas_gap_length len) /// Determines whether a slot is inside the measurement gap. inline bool is_inside_meas_gap(const meas_gap_config& gap, slot_point sl) { - unsigned period_slots = static_cast(gap.mgrp) * sl.nof_slots_per_subframe(); - unsigned length_slots = std::ceil(meas_gap_length_to_msec(gap.mgl) * sl.nof_slots_per_subframe()); - unsigned slot_mod = sl.to_uint() % period_slots; + const unsigned slot_per_sf = sl.nof_slots_per_subframe(); + unsigned period_slots = static_cast(gap.mgrp) * slot_per_sf; + unsigned length_slots = std::ceil(meas_gap_length_to_msec(gap.mgl) * slot_per_sf); + unsigned slot_mod = (sl - gap.offset * slot_per_sf).to_uint() % period_slots; return slot_mod <= length_slots; } From b9ff97748667c6eca1382422a4fc3a95d599782d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Thu, 12 Dec 2024 12:44:47 +0100 Subject: [PATCH 164/227] ran: implement PUSCH TPMI for 3 and 4 layers --- lib/ran/pusch/pusch_tpmi_select.cpp | 376 ++++++++++++++++-- .../ran/pusch/pusch_tpmi_select_test.cpp | 5 - 2 files changed, 352 insertions(+), 29 deletions(-) diff --git a/lib/ran/pusch/pusch_tpmi_select.cpp b/lib/ran/pusch/pusch_tpmi_select.cpp index e9b65704c5..ba58b89cea 100644 --- a/lib/ran/pusch/pusch_tpmi_select.cpp +++ b/lib/ran/pusch/pusch_tpmi_select.cpp @@ -17,7 +17,6 @@ #include "srsran/ran/srs/srs_channel_matrix.h" #include "srsran/srsvec/mean.h" #include "srsran/support/math/math_utils.h" -#include #include #include #include @@ -28,8 +27,12 @@ static constexpr cf_t sqrt1_2(M_SQRT1_2, 0.0F); static constexpr cf_t sqrt1_2j(0.0F, M_SQRT1_2); static constexpr cf_t sqrt1_8(M_SQRT1_2 / 2, 0.0F); static constexpr cf_t sqrt1_8j(0.0F, M_SQRT1_2 / 2); +static constexpr cf_t sqrt1_12(0.2886751345948129F, 0.0F); +static constexpr cf_t sqrt1_12j(0.0F, 0.2886751345948129F); static constexpr cf_t dot5(0.5F, 0.0F); static constexpr cf_t dot5j(0.0F, 0.5F); +static constexpr cf_t dot25(0.25F, 0.0F); +static constexpr cf_t dot25j(0.0F, 0.25F); static constexpr cf_t zero; // TS38.211 Table 6.3.1.5-1 @@ -114,6 +117,152 @@ static const std::array codebook_2layer_4port = {{ precoding_weight_matrix({sqrt1_8, sqrt1_8, -sqrt1_8j, -sqrt1_8j, sqrt1_8j, -sqrt1_8j, sqrt1_8, -sqrt1_8}, 2, 4), }}; +// TS38.211 Table 6.3.1.5-6 +static const std::array codebook_3layer_4port = {{ + // TPMI Index 0-3 + precoding_weight_matrix({dot5, zero, zero, zero, dot5, zero, zero, zero, dot5, zero, zero, zero}, 3, 4), + precoding_weight_matrix({dot5, zero, zero, zero, dot5, zero, dot5, zero, zero, zero, zero, dot5}, 3, 4), + precoding_weight_matrix({dot5, zero, zero, zero, dot5, zero, -dot5, zero, zero, zero, zero, dot5}, 3, 4), + precoding_weight_matrix({sqrt1_12, + sqrt1_12, + sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12, + sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12, + -sqrt1_12, + -sqrt1_12}, + 3, + 4), + // TPMI Index 4-6 + precoding_weight_matrix({sqrt1_12, + sqrt1_12, + sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12, + sqrt1_12j, + sqrt1_12j, + -sqrt1_12j, + sqrt1_12j, + -sqrt1_12j, + -sqrt1_12j}, + 3, + 4), + precoding_weight_matrix({sqrt1_12, + sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12, + sqrt1_12, + -sqrt1_12, + -sqrt1_12, + sqrt1_12, + sqrt1_12}, + 3, + 4), + precoding_weight_matrix({sqrt1_12, + sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12, + -sqrt1_12, + sqrt1_12j, + sqrt1_12j, + -sqrt1_12j, + -sqrt1_12j, + sqrt1_12j, + sqrt1_12j}, + 3, + 4), +}}; + +// TS38.211 Table 6.3.1.5-7 +static const std::array codebook_4layer_4port = {{ + // TPMI Index 0-3 + precoding_weight_matrix( + {dot5, zero, zero, zero, zero, dot5, zero, zero, zero, zero, dot5, zero, zero, zero, zero, dot5}, + 4, + 4), + precoding_weight_matrix({sqrt1_8, + sqrt1_8, + zero, + zero, + zero, + zero, + sqrt1_8, + sqrt1_8, + sqrt1_8, + -sqrt1_8, + zero, + zero, + zero, + zero, + sqrt1_8, + -sqrt1_8}, + 4, + 4), + precoding_weight_matrix({sqrt1_8, + sqrt1_8, + zero, + zero, + zero, + zero, + sqrt1_8, + sqrt1_8, + sqrt1_8j, + -sqrt1_8j, + zero, + zero, + zero, + zero, + sqrt1_8j, + -sqrt1_8j}, + 4, + 4), + precoding_weight_matrix({dot25, + dot25, + dot25, + dot25, + dot25, + -dot25, + dot25, + -dot25, + dot25, + dot25, + -dot25, + -dot25, + dot25, + -dot25, + -dot25, + dot25}, + 4, + 4), + precoding_weight_matrix({dot25, + dot25, + dot25, + dot25, + dot25, + -dot25, + dot25, + -dot25, + dot25j, + dot25j, + -dot25j, + -dot25j, + dot25j, + -dot25j, + -dot25j, + dot25j}, + 4, + 4), +}}; + // Calculates the product of a channel matrix and a precoding weight matrix. The number of transmit ports of each matrix // must be equal. static precoding_weight_matrix product_channel_weight(const srs_channel_matrix& H, const precoding_weight_matrix& W) @@ -137,6 +286,112 @@ static precoding_weight_matrix product_channel_weight(const srs_channel_matrix& return result; } +// Calculates the gram matrix. +template +static void gram_channel_matrix(cf_t out[N][N], const precoding_weight_matrix& H) +{ + unsigned nof_layers = H.get_nof_layers(); + unsigned nof_rx_ports = H.get_nof_ports(); + + precoding_weight_matrix result(nof_layers, nof_layers); + for (unsigned i = 0; i != nof_layers; ++i) { + for (unsigned j = 0; j != nof_layers; ++j) { + for (unsigned i_rx_port = 0; i_rx_port != nof_rx_ports; ++i_rx_port) { + cf_t sum; + for (unsigned k = 0; k != nof_rx_ports; ++k) { + sum += H.get_coefficient(i, k) * std::conj(H.get_coefficient(j, k)); + } + out[j][i] = sum; + } + } + } +} + +// Select the sub elements of a matrix eliminating a given row and column. +template +static void subchannel_matrix(cf_t out[N - 1][N - 1], const cf_t in[N][N], unsigned i_skip_row, unsigned i_skip_col) +{ + unsigned i_row_count = 0; + for (unsigned i_row = 0; i_row != N; ++i_row) { + if (i_row == i_skip_row) { + continue; + } + unsigned i_col_count = 0; + for (unsigned i_col = 0; i_col != N; ++i_col) { + if (i_col == i_skip_col) { + continue; + } + out[i_col_count][i_row_count] = in[i_col][i_row]; + i_col_count++; + } + ++i_row_count; + } +} + +// Calculate the determinant of a matrix of size N. +template +cf_t det_channel_matrix(const cf_t in[N][N]) +{ + static constexpr unsigned subN = N - 1; + cf_t sub[subN][subN]; + cf_t sum; + float sign = 1; + for (unsigned i = 0; i != N; ++i) { + subchannel_matrix(sub, in, i, 0); + cf_t subdet = det_channel_matrix(sub); + sum += sign * in[0][i] * subdet; + sign *= -1; + } + return sum; +} + +// Calculate the determinant of a matrix of size 2. +template <> +cf_t det_channel_matrix<2>(const cf_t in[2][2]) +{ + return in[0][0] * in[1][1] - in[0][1] * in[1][0]; +} + +// Calculate the determinant of a matrix of size 1. +template <> +cf_t det_channel_matrix<1>(const cf_t in[1][1]) +{ + return in[0][0]; +} + +// Calculate the mean layer SINR based on the channel matrix and noise variance. +template +float calculate_mean_layer_sinr(const precoding_weight_matrix& channel_weights, float noise_variance) +{ + // Calculate Gram Matrix. + cf_t gram_matrix[NofLayers][NofLayers]; + gram_channel_matrix(gram_matrix, channel_weights); + + // Add noise variance to the diagonal. + for (unsigned i = 0; i != NofLayers; ++i) { + gram_matrix[i][i] += noise_variance; + } + + // Calculate gram matrix determinant. It must be real. + float det = det_channel_matrix(gram_matrix).real(); + + // Calculate the diagonal of the inverse, it must be real. + std::array inv_diagonal; + cf_t temp_sub[NofLayers - 1][NofLayers - 1]; + for (unsigned i = 0; i != NofLayers; ++i) { + subchannel_matrix(temp_sub, gram_matrix, i, i); + inv_diagonal[i] = det_channel_matrix(temp_sub).real() / det; + } + + // Estimate noise variances. + std::array layer_sinr; + for (unsigned i_layer = 0; i_layer != NofLayers; ++i_layer) { + layer_sinr[i_layer] = 1.0F / (inv_diagonal[i_layer] * noise_variance) - 1.0F; + } + + return srsvec::mean(layer_sinr); +} + static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_1layer(const srs_channel_matrix& channel, float noise_variance, tx_scheme_codebook_subset codebook_subset) @@ -214,7 +469,6 @@ static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_2layer(const srs_c tx_scheme_codebook_subset codebook_subset) { static constexpr unsigned nof_layers = 2; - unsigned nof_rx_ports = channel.get_nof_rx_ports(); unsigned nof_tx_ports = channel.get_nof_tx_ports(); // Select codebook as a function of the number of transmit ports and restrict the candidates according to its subset. @@ -257,34 +511,98 @@ static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_2layer(const srs_c // Calculate the product of the channel matrix and the precoding weights. precoding_weight_matrix channel_weights = product_channel_weight(channel, weights); - // Calculate the product of the channel matrix (recall, it's an Nx2 matrix) and its hermitian transpose. Also, add - // the noise variance. The diagonal coefficients are the squared norms of the channel matrix column vectors. - std::array norm_sq_ch; - for (unsigned i_layer = 0; i_layer != nof_layers; ++i_layer) { - float sum = noise_variance; - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { - sum += std::norm(channel_weights.get_coefficient(i_layer, i_port)); - } - norm_sq_ch[i_layer] = sum; + // Calculate the average SINR. + float sinr = calculate_mean_layer_sinr(channel_weights, noise_variance); + if (sinr > best_sinr) { + best_sinr = sinr; + best_tpmi = tpmi; } + } - // Calculate the anti-diagonal coefficients, which are xi and xi_conj. - cf_t xi = cf_t(); - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { - xi += std::conj(channel_weights.get_coefficient(0, i_port)) * channel_weights.get_coefficient(1, i_port); - } - float xi_mod_sq = std::norm(xi); + return {best_tpmi, convert_power_to_dB(best_sinr)}; +} + +static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_3layer(const srs_channel_matrix& channel, + float noise_variance, + tx_scheme_codebook_subset codebook_subset) +{ + static constexpr unsigned nof_layers = 3; - // Calculate the denominators. - float det = ((norm_sq_ch[0] * norm_sq_ch[1]) - xi_mod_sq); + // Select codebook as a function of the number of transmit ports and restrict the candidates according to its subset. + span codebook; + unsigned tpmi_end = codebook.size(); + + codebook = codebook_3layer_4port; + switch (codebook_subset) { + case tx_scheme_codebook_subset::fully_and_partial_and_non_coherent: + tpmi_end = codebook.size(); + break; + case tx_scheme_codebook_subset::partial_and_non_coherent: + tpmi_end = 3; + break; + case tx_scheme_codebook_subset::non_coherent: + tpmi_end = 1; + break; + } - // Estimate noise variances. - std::array layer_sinr; - for (unsigned i_layer = 0; i_layer != nof_layers; ++i_layer) { - layer_sinr[i_layer] = det / (norm_sq_ch[i_layer] * noise_variance) - 1.0F; + float best_sinr = -std::numeric_limits::infinity(); + unsigned best_tpmi = 0; + + // Iterate possible TPMIs. + for (unsigned tpmi = 0; tpmi != tpmi_end; ++tpmi) { + // Select precoding matrix. + const precoding_weight_matrix& weights = codebook[tpmi]; + + // Calculate the product of the channel matrix and the precoding weights. + precoding_weight_matrix channel_weights = product_channel_weight(channel, weights); + + // Calculate average layer SINR. + float sinr = calculate_mean_layer_sinr(channel_weights, noise_variance); + if (sinr > best_sinr) { + best_sinr = sinr; + best_tpmi = tpmi; } + } + + return {best_tpmi, convert_power_to_dB(best_sinr)}; +} - float sinr = srsvec::mean(layer_sinr); +static pusch_tpmi_select_info::tpmi_info get_tpmi_select_info_4layer(const srs_channel_matrix& channel, + float noise_variance, + tx_scheme_codebook_subset codebook_subset) +{ + static constexpr unsigned nof_layers = 4; + + // Select codebook as a function of the number of transmit ports and restrict the candidates according to its subset. + span codebook; + unsigned tpmi_end = codebook.size(); + + codebook = codebook_4layer_4port; + switch (codebook_subset) { + case tx_scheme_codebook_subset::fully_and_partial_and_non_coherent: + tpmi_end = codebook.size(); + break; + case tx_scheme_codebook_subset::partial_and_non_coherent: + tpmi_end = 3; + break; + case tx_scheme_codebook_subset::non_coherent: + tpmi_end = 1; + break; + } + + float best_sinr = -std::numeric_limits::infinity(); + unsigned best_tpmi = 0; + + // Iterate possible TPMIs. + for (unsigned tpmi = 0; tpmi != tpmi_end; ++tpmi) { + // Select precoding matrix. + const precoding_weight_matrix& weights = codebook[tpmi]; + + // Calculate the product of the channel matrix and the precoding weights. + precoding_weight_matrix channel_weights = product_channel_weight(channel, weights); + + // Calculate average layer SINR. + float sinr = calculate_mean_layer_sinr(channel_weights, noise_variance); if (sinr > best_sinr) { best_sinr = sinr; best_tpmi = tpmi; @@ -315,6 +633,16 @@ pusch_tpmi_select_info srsran::get_tpmi_select_info(const srs_channel_matrix& ch info.emplace_back(get_tpmi_select_info_2layer(channel, noise_variance, codebook_subset)); } + // Calculate TPMI select information for 3 layer. + if ((max_nof_layers >= 3) && (nof_tx_ports == 4) && (nof_rx_ports == 4)) { + info.emplace_back(get_tpmi_select_info_3layer(channel, noise_variance, codebook_subset)); + } + + // Calculate TPMI select information for 4 layer. + if ((max_nof_layers >= 4) && (nof_tx_ports == 4) && (nof_rx_ports == 4)) { + info.emplace_back(get_tpmi_select_info_4layer(channel, noise_variance, codebook_subset)); + } + // Return invalid information. return {info}; } diff --git a/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp b/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp index 8c7d5e1abd..6e12b5acaa 100644 --- a/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp +++ b/tests/unittests/ran/pusch/pusch_tpmi_select_test.cpp @@ -113,11 +113,6 @@ TEST_P(PuschTpmiSelectFixture, VectorTest) unsigned nof_rx_ports = test_case.channel_matrix.get_nof_rx_ports(); unsigned max_nof_layers = std::min(nof_tx_ports, nof_rx_ports); - // Only one layer is currently supported. - if (max_nof_layers > 2) { - GTEST_SKIP(); - } - // Get UL-SCH information parameters. pusch_tpmi_select_info info = get_tpmi_select_info( test_case.channel_matrix, test_case.noise_variance, max_nof_layers, test_case.codebook_subset); From dea4615779e519aa41cf44507e5ac231fc3c70e7 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 13 Dec 2024 10:32:52 +0100 Subject: [PATCH 165/227] ran: review TPMI related --- lib/ran/pusch/pusch_tpmi_select.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/ran/pusch/pusch_tpmi_select.cpp b/lib/ran/pusch/pusch_tpmi_select.cpp index ba58b89cea..d273b7f77b 100644 --- a/lib/ran/pusch/pusch_tpmi_select.cpp +++ b/lib/ran/pusch/pusch_tpmi_select.cpp @@ -321,8 +321,7 @@ static void subchannel_matrix(cf_t out[N - 1][N - 1], const cf_t in[N][N], unsig if (i_col == i_skip_col) { continue; } - out[i_col_count][i_row_count] = in[i_col][i_row]; - i_col_count++; + out[i_col_count++][i_row_count] = in[i_col][i_row]; } ++i_row_count; } @@ -352,6 +351,15 @@ cf_t det_channel_matrix<2>(const cf_t in[2][2]) return in[0][0] * in[1][1] - in[0][1] * in[1][0]; } +// Calculate the determinant of a matrix of size 3. +template <> +cf_t det_channel_matrix<3>(const cf_t in[3][3]) +{ + return in[0][0] * (in[1][1] * in[2][2] - in[1][2] * in[2][1]) + + in[0][1] * (in[1][2] * in[2][0] - in[2][2] * in[1][0]) + + in[0][2] * (in[1][0] * in[2][1] - in[1][1] * in[2][0]); +} + // Calculate the determinant of a matrix of size 1. template <> cf_t det_channel_matrix<1>(const cf_t in[1][1]) @@ -380,7 +388,7 @@ float calculate_mean_layer_sinr(const precoding_weight_matrix& channel_weights, cf_t temp_sub[NofLayers - 1][NofLayers - 1]; for (unsigned i = 0; i != NofLayers; ++i) { subchannel_matrix(temp_sub, gram_matrix, i, i); - inv_diagonal[i] = det_channel_matrix(temp_sub).real() / det; + inv_diagonal[i] = det_channel_matrix(temp_sub).real() / det; } // Estimate noise variances. From 0bc4be1bd69751fec6373ff491fbbccbf6550b79 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 13 Dec 2024 15:19:53 +0100 Subject: [PATCH 166/227] phy: fix GCC 9 compilation --- .../pusch/logging_pusch_processor_decorator.h | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/phy/upper/channel_processors/pusch/logging_pusch_processor_decorator.h b/lib/phy/upper/channel_processors/pusch/logging_pusch_processor_decorator.h index b8969bc91b..58586af09b 100644 --- a/lib/phy/upper/channel_processors/pusch/logging_pusch_processor_decorator.h +++ b/lib/phy/upper/channel_processors/pusch/logging_pusch_processor_decorator.h @@ -14,6 +14,7 @@ #include "srsran/phy/upper/channel_processors/pusch/formatters.h" #include "srsran/phy/upper/unique_rx_buffer.h" #include "srsran/support/format/fmt_optional.h" +#include namespace fmt { @@ -85,14 +86,14 @@ class logging_pusch_processor_decorator : public pusch_processor, private pusch_ pdu = pdu_; time_start = std::chrono::steady_clock::now(); time_uci = std::chrono::time_point(); - time_return = std::chrono::time_point(); + time_return = 0; // Clear processor results. results.sch.reset(); results.uci.reset(); processor->process(data, std::move(rm_buffer), *this, grid, pdu); - time_return = std::chrono::steady_clock::now(); + time_return = std::chrono::steady_clock::now().time_since_epoch().count(); } private: @@ -127,7 +128,8 @@ class logging_pusch_processor_decorator : public pusch_processor, private pusch_ // Calculate the return latency if available. std::chrono::nanoseconds time_return_ns(0); - std::chrono::time_point time_return_local = time_return.load(); + std::chrono::time_point time_return_local = + std::chrono::time_point(std::chrono::steady_clock::duration(time_return)); if (time_return_local != std::chrono::time_point()) { time_return_ns = time_return_local - time_start; } @@ -173,15 +175,15 @@ class logging_pusch_processor_decorator : public pusch_processor, private pusch_ notifier_->on_sch(sch); } - srslog::basic_logger& logger; - std::unique_ptr processor; - span data; - pdu_t pdu; - pusch_processor_result_notifier* notifier; - std::chrono::time_point time_start; - std::chrono::time_point time_uci; - std::atomic> time_return; - fmt::pusch_results_wrapper results; + srslog::basic_logger& logger; + std::unique_ptr processor; + span data; + pdu_t pdu; + pusch_processor_result_notifier* notifier; + std::chrono::time_point time_start; + std::chrono::time_point time_uci; + std::atomic time_return; + fmt::pusch_results_wrapper results; // Makes sure atomics are lock free. static_assert(std::atomic::is_always_lock_free); From ffa37d016d12dac6e7cd32e8da2231a119b8ecca Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Fri, 13 Dec 2024 15:07:57 +0100 Subject: [PATCH 167/227] cmake: remove bad DEPENDS from TARGET variant of add_custom_command() --- tests/unittests/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 94634705e9..ebcf48e947 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -28,7 +28,6 @@ macro(ADD_TEST_VECTOR TARGET VECTOR_FILE TEST_ARGS) POST_BUILD WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test_data COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_CURRENT_SOURCE_DIR}/${VECTOR_FILE} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${VECTOR_FILE} VERBATIM) else (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${VECTOR_FILE}) message(FATAL_ERROR "Vector file ${CMAKE_CURRENT_SOURCE_DIR}/${VECTOR_FILE} does not exist.") From 73a1024bce14f153cb84d78fa138f2d479dbe094 Mon Sep 17 00:00:00 2001 From: qarlosalberto Date: Mon, 16 Dec 2024 11:23:52 +0100 Subject: [PATCH 168/227] ci: move drx test to b200 --- .gitlab/ci/e2e.yml | 4 ++-- tests/e2e/pyproject.toml | 2 +- tests/e2e/tests/ping.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 2924ca06f4..957da2108c 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -477,8 +477,8 @@ android x300 drx: allow_failure: true variables: GROUP: "rf" - TESTBED: "android_x300" - MARKERS: "android_hp_drx" + TESTBED: "android_b200" + MARKERS: "android_drx" E2E_LOG_LEVEL: "info" KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" KUBECONFIG_VAR_NAME_EXTRA: "RETINA_NAMESPACE_KUBECONFIG_EXTRA" diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index dac25400cd..df3d1e78cb 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -22,7 +22,7 @@ markers = [ "rf", "android", "android_hp", - "android_hp_drx", + "android_drx", "udp", "tcp", "downlink", diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index b7688d3cce..7d34ba9365 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -193,17 +193,17 @@ def test_android_hp( @mark.parametrize( "band, common_scs, bandwidth", ( - param(7, 15, 20, id="band:%s-scs:%s-bandwidth:%s"), - param(78, 30, 90, id="band:%s-scs:%s-bandwidth:%s"), + param(3, 15, 10, id="band:%s-scs:%s-bandwidth:%s"), + param(78, 30, 20, id="band:%s-scs:%s-bandwidth:%s"), ), ) -@mark.android_hp_drx +@mark.android_drx @mark.flaky( reruns=2, only_rerun=["failed to start", "Exception calling application", "Attach timeout reached", "Some packages got lost"], ) # pylint: disable=too-many-arguments,too-many-positional-arguments -def test_android_hp_drx( +def test_android_drx( retina_manager: RetinaTestManager, retina_data: RetinaTestData, ue: UEStub, # pylint: disable=invalid-name From 25482b11e3024ce2d0ddd2e0595de267fd3c6dd2 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 23 Oct 2024 16:16:27 +0200 Subject: [PATCH 169/227] sched: build TB info for logical channels sorted based on LC priority --- .../ue_context/dl_logical_channel_manager.cpp | 31 ++++++++++++++++--- .../ue_context/dl_logical_channel_manager.h | 6 ++++ lib/scheduler/ue_context/ue.cpp | 2 +- .../ue_scheduling/logical_channel_test.cpp | 2 +- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp index 758622b955..96ef9c2f16 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp @@ -25,6 +25,7 @@ dl_logical_channel_manager::dl_logical_channel_manager() { // SRB0 is always activated. set_status(LCID_SRB0, true); + sorted_channels.resize(1, LCID_SRB0); } void dl_logical_channel_manager::deactivate() @@ -33,16 +34,34 @@ void dl_logical_channel_manager::deactivate() set_status((lcid_t)lcid, false); } pending_ces.clear(); + sorted_channels.clear(); } void dl_logical_channel_manager::configure(span log_channels_configs) { + // Clear old list of sorted channels. + sorted_channels.clear(); + sorted_channels.resize(log_channels_configs.size()); + for (unsigned i = 1; i != channels.size(); ++i) { channels[i].active = false; } for (const logical_channel_config& lc_ch : log_channels_configs) { set_status(lc_ch.lcid, true); + sorted_channels.push_back(lc_ch.lcid); } + + // Sort logical channels based on priority set in MAC LC configuration. + std::sort( + sorted_channels.begin(), sorted_channels.end(), [log_channels_configs](const auto lcid_lhs, const auto lcid_rhs) { + auto it_lhs = std::find_if(log_channels_configs.begin(), + log_channels_configs.end(), + [lcid_lhs](const logical_channel_config& lc_ch) { return lc_ch.lcid == lcid_lhs; }); + auto it_rhs = std::find_if(log_channels_configs.begin(), + log_channels_configs.end(), + [lcid_rhs](const logical_channel_config& lc_ch) { return lc_ch.lcid == lcid_rhs; }); + return it_lhs->priority < it_rhs->priority; + }); } unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, unsigned rem_bytes, lcid_t lcid) @@ -61,10 +80,9 @@ unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, un lcid_t dl_logical_channel_manager::get_max_prio_lcid() const { - // Prioritize by LCID. - for (unsigned idx = 0; idx != channels.size(); ++idx) { - if (channels[idx].active and channels[idx].buf_st > 0) { - return (lcid_t)idx; + for (const auto lcid : sorted_channels) { + if (channels[lcid].active and channels[lcid].buf_st > 0) { + return lcid; } } return INVALID_LCID; @@ -223,6 +241,11 @@ unsigned dl_logical_channel_manager::allocate_ue_con_res_id_mac_ce(dl_msg_lc_inf return alloc_bytes; } +span dl_logical_channel_manager::get_prioritized_logical_channels() const +{ + return sorted_channels; +} + unsigned srsran::allocate_ue_con_res_id_mac_ce(dl_msg_tb_info& tb_info, dl_logical_channel_manager& lch_mng, unsigned total_tbs) { diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index 6d1b82b3e6..7b6373e30d 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -171,6 +171,9 @@ class dl_logical_channel_manager /// \return Allocated bytes for UE Contention Resolution Identity MAC CE (with subheader). unsigned allocate_ue_con_res_id_mac_ce(dl_msg_lc_info& lch_info, unsigned rem_bytes); + /// \brief Returns a list of LCIDs sorted based on decreasing order of priority. + span get_prioritized_logical_channels() const; + private: struct channel_context { bool active = false; @@ -186,6 +189,9 @@ class dl_logical_channel_manager std::array channels; + /// List of logical channel IDs sorted in decreasing order of priority. i.e. first element has the highest priority. + std::vector sorted_channels; + bool pending_con_res_id{false}; /// \brief List of pending CEs except UE Contention Resolution Identity. diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 584c5f72ac..15cdba4f41 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -224,7 +224,7 @@ unsigned ue::build_dl_transport_block_info(dl_msg_tb_info& { unsigned total_subpdu_bytes = 0; total_subpdu_bytes += allocate_mac_ces(tb_info, dl_lc_ch_mgr, tb_size_bytes); - for (unsigned lcid = 0, e = lcids.size(); lcid != e; ++lcid) { + for (const auto lcid : dl_lc_ch_mgr.get_prioritized_logical_channels()) { if (lcids.test(lcid)) { total_subpdu_bytes += allocate_mac_sdus(tb_info, dl_lc_ch_mgr, tb_size_bytes - total_subpdu_bytes, uint_to_lcid(lcid)); diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index 6a7bad7d7c..3aed66b8fd 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -199,7 +199,7 @@ TEST(dl_logical_channel_test, mac_sdu_is_scheduled_if_tb_has_space) do { unsigned pending_bytes = lch_mng.total_pending_bytes(); dl_msg_lc_info subpdu; - unsigned allocated_bytes = lch_mng.allocate_mac_sdu(subpdu, rem_bytes); + unsigned allocated_bytes = lch_mng.allocate_mac_sdu(subpdu, rem_bytes, lcid); if (not subpdu.lcid.is_valid()) { // There was not enough space in the TB to deplete all the pending tx bytes. ASSERT_LT(tb_size, get_mac_sdu_required_bytes(sdu_size)); From 8808ac729510cfd162fc4935e387468b8acf4333 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 23 Oct 2024 18:19:00 +0200 Subject: [PATCH 170/227] sched,unittest: make default logical channel config generated by helpers consistent with MAC LC config generators --- .../config/logical_channel_config_factory.cpp | 11 ++++++++--- .../unittests/scheduler/multi_cell_scheduler_test.cpp | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/config/logical_channel_config_factory.cpp b/lib/scheduler/config/logical_channel_config_factory.cpp index c520c1e0ce..473f8241fc 100644 --- a/lib/scheduler/config/logical_channel_config_factory.cpp +++ b/lib/scheduler/config/logical_channel_config_factory.cpp @@ -15,9 +15,14 @@ using namespace srsran; logical_channel_config srsran::config_helpers::create_default_logical_channel_config(lcid_t lcid) { logical_channel_config lc_ch; - lc_ch.lcid = lcid; - lc_ch.priority = is_srb(lcid) ? 1 : 2; - lc_ch.lc_group = uint_to_lcg_id(is_srb(lcid) ? 0 : 1); + lc_ch.lcid = lcid; + lc_ch.priority = 5; + lc_ch.lc_group = uint_to_lcg_id(2); + // See TS 38.331, 9.2.1 Default SRB configurations. + if (is_srb(lcid)) { + lc_ch.priority = lcid == LCID_SRB2 ? 3 : 1; + lc_ch.lc_group = uint_to_lcg_id(0); + } lc_ch.lc_sr_mask = false; lc_ch.lc_sr_delay_timer_applied = false; return lc_ch; diff --git a/tests/unittests/scheduler/multi_cell_scheduler_test.cpp b/tests/unittests/scheduler/multi_cell_scheduler_test.cpp index 2b5a221394..290a34b1a8 100644 --- a/tests/unittests/scheduler/multi_cell_scheduler_test.cpp +++ b/tests/unittests/scheduler/multi_cell_scheduler_test.cpp @@ -370,7 +370,7 @@ TEST_P(multi_cell_scheduler_tester, test_ul_scheduling_for_ues_in_different_cell to_du_ue_index(ue_idx), get_ue_crnti(ue_idx), bsr_format::SHORT_BSR, - {ul_bsr_lcg_report{uint_to_lcg_id(1), 100}}}; + {ul_bsr_lcg_report{uint_to_lcg_id(2), 100}}}; push_bsr(bsr); } From b5bb35a5ffd2da4c60517fdad4b5237683fa0972 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Wed, 23 Oct 2024 18:25:30 +0200 Subject: [PATCH 171/227] unittest: add test to verify TB info generation from LC with highest priority to least --- .../policy/scheduler_policy_test.cpp | 5 +- .../ue_scheduling/ue_grid_allocator_test.cpp | 72 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index e4577004b3..114634888a 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -750,7 +750,10 @@ TEST_P(scheduler_pf_qos_test, pf_upholds_qos_in_dl_gbr_flows) (*cfg_req.lc_config_list)[2] = config_helpers::create_default_logical_channel_config(non_gbr_bearer_lcid); (*cfg_req.lc_config_list)[2].lc_group = lcg_id; (*cfg_req.lc_config_list)[3] = config_helpers::create_default_logical_channel_config(gbr_bearer_lcid); - (*cfg_req.lc_config_list)[3].lc_group = lcg_id; + // Increase priority for GBR bearer. + (*cfg_req.lc_config_list)[3].priority -= 1; + // Put GBR bearer in a different LCG than non-GBR bearer. + (*cfg_req.lc_config_list)[3].lc_group = uint_to_lcg_id(lcg_id - 1); cfg_req.drb_info_list.resize(2); cfg_req.drb_info_list[0] = sched_drb_info{.lcid = non_gbr_bearer_lcid, .qos_info = *get_5qi_to_qos_characteristics_mapping(uint_to_five_qi(9))}; diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 8ff5e63e70..429a9a68ed 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -123,6 +123,15 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam return ues[ue_creation_req.ue_index]; } + void push_dl_bs(du_ue_index_t ue_index, lcid_t lcid, unsigned bytes) + { + dl_buffer_state_indication_message ind{}; + ind.ue_index = ue_index; + ind.lcid = lcid; + ind.bs = bytes; + ues[ue_index].handle_dl_buffer_state_indication(ind); + } + scheduler_expert_config sched_cfg; scheduler_ue_expert_config expert_cfg{sched_cfg.ue}; sched_cfg_dummy_notifier mac_notif; @@ -484,6 +493,69 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pdsch_even_with_large_ga nof_slot_until_pdsch_is_allocated_threshold)); } +TEST_P(ue_grid_allocator_tester, successfully_allocates_pdsch_with_gbr_lc_priortized_over_non_gbr_lc) +{ + const lcg_id_t lcg_id = uint_to_lcg_id(2); + const lcid_t gbr_bearer_lcid = uint_to_lcid(6); + const lcid_t non_gbr_bearer_lcid = uint_to_lcid(5); + + // Add UE. + sched_ue_creation_request_message ue_creation_req = + sched_config_helper::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + ue& u1 = add_ue(ue_creation_req); + + // Reconfigure UE to include non-GBR bearer and GBR bearer. + sched_ue_reconfiguration_message reconf_msg{ + .ue_index = ue_creation_req.ue_index, .crnti = ue_creation_req.crnti, .cfg = ue_creation_req.cfg}; + sched_ue_config_request& cfg_req = reconf_msg.cfg; + cfg_req.lc_config_list.emplace(); + cfg_req.lc_config_list->resize(4); + (*cfg_req.lc_config_list)[0] = config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB0); + (*cfg_req.lc_config_list)[1] = config_helpers::create_default_logical_channel_config(lcid_t::LCID_SRB1); + (*cfg_req.lc_config_list)[2] = config_helpers::create_default_logical_channel_config(non_gbr_bearer_lcid); + (*cfg_req.lc_config_list)[2].lc_group = lcg_id; + (*cfg_req.lc_config_list)[3] = config_helpers::create_default_logical_channel_config(gbr_bearer_lcid); + // Increase priority for GBR bearer. + (*cfg_req.lc_config_list)[3].priority -= 1; + // Put GBR bearer in a different LCG than non-GBR bearer. + (*cfg_req.lc_config_list)[3].lc_group = uint_to_lcg_id(lcg_id - 1); + cfg_req.drb_info_list.resize(2); + cfg_req.drb_info_list[0] = sched_drb_info{.lcid = non_gbr_bearer_lcid, + .qos_info = *get_5qi_to_qos_characteristics_mapping(uint_to_five_qi(9))}; + cfg_req.drb_info_list[1] = sched_drb_info{.lcid = gbr_bearer_lcid, + .qos_info = *get_5qi_to_qos_characteristics_mapping(uint_to_five_qi(1)), + .gbr_qos_info = gbr_qos_flow_information{128000, 128000, 128000, 128000}}; + ue_config_update_event ev = cfg_mng.update_ue(reconf_msg); + u1.handle_reconfiguration_request({ev.next_config()}); + + // Add LCID to the bearers of the UE belonging to this slice. + for (const auto& lc_cfg : *cfg_req.lc_config_list) { + slice_ues[u1.ue_index].add_logical_channel(lc_cfg.lcid, lc_cfg.lc_group); + } + + // Push buffer state update to both bearers. + push_dl_bs(u1.ue_index, gbr_bearer_lcid, 200); + push_dl_bs(u1.ue_index, non_gbr_bearer_lcid, 1500); + + static const unsigned sched_bytes = 2000U; + + const ue_pdsch_grant grant1{.user = &slice_ues[u1.ue_index], + .cell_index = to_du_cell_index(0), + .h_id = INVALID_HARQ_ID, + .recommended_nof_bytes = sched_bytes}; + + ASSERT_TRUE(run_until([&]() { alloc.allocate_dl_grant(grant1, dummy_slice_id); }, + [&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); + + const auto* ue_pdsch = find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants); + ASSERT_TRUE(not ue_pdsch->tb_list.empty()); + ASSERT_TRUE(not ue_pdsch->tb_list.back().lc_chs_to_sched.empty()); + // TB info contains GBR LC channel first and then non-GBR LC channel. + ASSERT_EQ(ue_pdsch->tb_list.back().lc_chs_to_sched.front().lcid, gbr_bearer_lcid); +} + TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_gap_to_last_pusch_slot_allocated) { static const unsigned nof_bytes_to_schedule = 400U; From 0696fd0f953bcda1c94c1ec3e0b9742178e4cd24 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 13:52:09 +0100 Subject: [PATCH 172/227] sched: improved DL logical channel manager handling of priorities --- include/srsran/ran/logical_channel/lcid.h | 2 +- .../config/logical_channel_config_factory.h | 17 ++- .../scheduler/config/logical_channel_group.h | 4 +- lib/scheduler/config/CMakeLists.txt | 1 - .../config/logical_channel_config_factory.cpp | 29 ---- .../ue_context/dl_logical_channel_manager.cpp | 141 ++++++++++++++---- .../ue_context/dl_logical_channel_manager.h | 67 ++++----- lib/scheduler/ue_context/ue.cpp | 2 +- 8 files changed, 161 insertions(+), 102 deletions(-) delete mode 100644 lib/scheduler/config/logical_channel_config_factory.cpp diff --git a/include/srsran/ran/logical_channel/lcid.h b/include/srsran/ran/logical_channel/lcid.h index 12b7105297..41d144e0e9 100644 --- a/include/srsran/ran/logical_channel/lcid.h +++ b/include/srsran/ran/logical_channel/lcid.h @@ -36,7 +36,7 @@ constexpr inline lcid_t uint_to_lcid(std::underlying_type_t val) /// \remark See TS 38.331, maxLC-ID. constexpr lcid_t MAX_LCID = LCID_MAX_DRB; -inline bool is_srb(lcid_t lcid) +constexpr bool is_srb(lcid_t lcid) { return lcid <= LCID_SRB3; } diff --git a/include/srsran/scheduler/config/logical_channel_config_factory.h b/include/srsran/scheduler/config/logical_channel_config_factory.h index 4902dcad1b..2ca49943c4 100644 --- a/include/srsran/scheduler/config/logical_channel_config_factory.h +++ b/include/srsran/scheduler/config/logical_channel_config_factory.h @@ -16,7 +16,22 @@ namespace srsran { namespace config_helpers { /// \brief Creates a default logical channel configuration to be used by the scheduler. -logical_channel_config create_default_logical_channel_config(lcid_t lcid); +constexpr logical_channel_config create_default_logical_channel_config(lcid_t lcid) +{ + logical_channel_config lc_ch{}; + lc_ch.lcid = lcid; + // See TS 38.331, 9.2.1 Default SRB configurations. + if (is_srb(lcid)) { + lc_ch.priority = lcid == LCID_SRB2 ? 3 : 1; + lc_ch.lc_group = uint_to_lcg_id(0); + } else { + lc_ch.priority = 5; + lc_ch.lc_group = uint_to_lcg_id(2); + } + lc_ch.lc_sr_mask = false; + lc_ch.lc_sr_delay_timer_applied = false; + return lc_ch; +} } // namespace config_helpers } // namespace srsran diff --git a/include/srsran/scheduler/config/logical_channel_group.h b/include/srsran/scheduler/config/logical_channel_group.h index d161f0e3ed..1296b42bbc 100644 --- a/include/srsran/scheduler/config/logical_channel_group.h +++ b/include/srsran/scheduler/config/logical_channel_group.h @@ -18,9 +18,9 @@ namespace srsran { /// Logical Channel Group as per TS38.331. enum lcg_id_t : uint8_t { MAX_LCG_ID = 7, MAX_NOF_LCGS = 8, LCG_ID_INVALID = 8 }; -inline lcg_id_t uint_to_lcg_id(std::underlying_type_t val) +constexpr lcg_id_t uint_to_lcg_id(std::underlying_type_t val) { return static_cast(val); } -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/scheduler/config/CMakeLists.txt b/lib/scheduler/config/CMakeLists.txt index cbdd0d3d18..67b97509e9 100644 --- a/lib/scheduler/config/CMakeLists.txt +++ b/lib/scheduler/config/CMakeLists.txt @@ -7,7 +7,6 @@ # set(SOURCES serving_cell_config_factory.cpp - logical_channel_config_factory.cpp sched_cell_config_helpers.cpp scheduler_cell_config_validator.cpp scheduler_ue_config_validator.cpp diff --git a/lib/scheduler/config/logical_channel_config_factory.cpp b/lib/scheduler/config/logical_channel_config_factory.cpp deleted file mode 100644 index 473f8241fc..0000000000 --- a/lib/scheduler/config/logical_channel_config_factory.cpp +++ /dev/null @@ -1,29 +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/scheduler/config/logical_channel_config_factory.h" - -using namespace srsran; - -logical_channel_config srsran::config_helpers::create_default_logical_channel_config(lcid_t lcid) -{ - logical_channel_config lc_ch; - lc_ch.lcid = lcid; - lc_ch.priority = 5; - lc_ch.lc_group = uint_to_lcg_id(2); - // See TS 38.331, 9.2.1 Default SRB configurations. - if (is_srb(lcid)) { - lc_ch.priority = lcid == LCID_SRB2 ? 3 : 1; - lc_ch.lc_group = uint_to_lcg_id(0); - } - lc_ch.lc_sr_mask = false; - lc_ch.lc_sr_delay_timer_applied = false; - return lc_ch; -} diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp index 96ef9c2f16..382493655d 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.cpp +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.cpp @@ -9,9 +9,31 @@ */ #include "dl_logical_channel_manager.h" +#include "srsran/scheduler/config/logical_channel_config_factory.h" using namespace srsran; +static const logical_channel_config& get_default_logical_channel_config(lcid_t lcid) +{ + // Default logical channel configs. + constexpr static logical_channel_config lcid0_cfg = config_helpers::create_default_logical_channel_config(LCID_SRB0); + constexpr static logical_channel_config lcid1_cfg = config_helpers::create_default_logical_channel_config(LCID_SRB1); + constexpr static logical_channel_config lcid2_cfg = config_helpers::create_default_logical_channel_config(LCID_SRB2); + constexpr static logical_channel_config default_drb_cfg = + config_helpers::create_default_logical_channel_config(LCID_MIN_DRB); + switch (lcid) { + case LCID_SRB0: + return lcid0_cfg; + case LCID_SRB1: + return lcid1_cfg; + case LCID_SRB2: + return lcid2_cfg; + default: + break; + } + return default_drb_cfg; +} + static unsigned get_mac_sdu_size(unsigned sdu_and_subheader_bytes) { if (sdu_and_subheader_bytes == 0) { @@ -23,9 +45,11 @@ static unsigned get_mac_sdu_size(unsigned sdu_and_subheader_bytes) dl_logical_channel_manager::dl_logical_channel_manager() { + // Reserve entries to avoid allocating in hot path. + sorted_channels.reserve(LCID_MIN_DRB); + // SRB0 is always activated. set_status(LCID_SRB0, true); - sorted_channels.resize(1, LCID_SRB0); } void dl_logical_channel_manager::deactivate() @@ -37,31 +61,101 @@ void dl_logical_channel_manager::deactivate() sorted_channels.clear(); } +void dl_logical_channel_manager::set_status(lcid_t lcid, bool active) +{ + srsran_sanity_check(lcid < MAX_NOF_RB_LCIDS, "Max LCID value 32 exceeded"); + + if (channels[lcid].active == active and channels[lcid].cfg != nullptr) { + // No state change. + return; + } + + // Update channel config. + const bool new_lc = channels[lcid].cfg == nullptr; + auto it = + std::find_if(channel_configs.begin(), channel_configs.end(), [lcid](const auto& c) { return c.lcid == lcid; }); + if (it != channel_configs.end()) { + // In case the channel config was specified. + channels[lcid].cfg = it; + } else { + // in case it was not specified, fallback to default config. + channels[lcid].cfg = &get_default_logical_channel_config(lcid); + } + + // set new state. + channels[lcid].active = active; + + // Refresh sorted_channels list. + if (new_lc) { + sorted_channels.push_back(lcid); + } + std::sort(sorted_channels.begin(), sorted_channels.end(), [this](lcid_t lhs, lcid_t rhs) { + return channels[lhs].cfg->priority < channels[rhs].cfg->priority; + }); +} + void dl_logical_channel_manager::configure(span log_channels_configs) { - // Clear old list of sorted channels. - sorted_channels.clear(); - sorted_channels.resize(log_channels_configs.size()); + const bool cfg_changed = channel_configs != log_channels_configs; + channel_configs = log_channels_configs; - for (unsigned i = 1; i != channels.size(); ++i) { - channels[i].active = false; + if (not cfg_changed) { + // No change in the config. However, we may need to update channel config pointers. + for (const logical_channel_config& ch_cfg : channel_configs) { + channels[ch_cfg.lcid].cfg = &ch_cfg; + } + return; + } + + // If a previously custom configured LC is not in the list of new configs, we delete it. + // Note: LCID will be removed from sorted_channels later. + for (lcid_t lcid : sorted_channels) { + if (channels[lcid].cfg != nullptr) { + auto it = std::find_if( + channel_configs.begin(), channel_configs.end(), [lcid](const auto& c) { return c.lcid == lcid; }); + if (it == channel_configs.end() and channels[lcid].cfg != &get_default_logical_channel_config(lcid)) { + channels[lcid] = {}; + } + } } - for (const logical_channel_config& lc_ch : log_channels_configs) { - set_status(lc_ch.lcid, true); - sorted_channels.push_back(lc_ch.lcid); + + // Set new LC configurations. + for (const logical_channel_config& ch_cfg : channel_configs) { + channels[ch_cfg.lcid].cfg = &ch_cfg; + channels[ch_cfg.lcid].active = true; + // buffer state stays the same when configuration is updated. + } + + // Refresh sorted channels list. + sorted_channels.clear(); + sorted_channels.reserve(channels.size()); + for (unsigned lcid = 0, e = channels.size(); lcid != e; ++lcid) { + if (channels[lcid].cfg != nullptr) { + sorted_channels.push_back(channels[lcid].cfg->lcid); + } } + std::sort(sorted_channels.begin(), sorted_channels.end(), [this](lcid_t lhs, lcid_t rhs) { + return channels[lhs].cfg->priority < channels[rhs].cfg->priority; + }); +} - // Sort logical channels based on priority set in MAC LC configuration. - std::sort( - sorted_channels.begin(), sorted_channels.end(), [log_channels_configs](const auto lcid_lhs, const auto lcid_rhs) { - auto it_lhs = std::find_if(log_channels_configs.begin(), - log_channels_configs.end(), - [lcid_lhs](const logical_channel_config& lc_ch) { return lc_ch.lcid == lcid_lhs; }); - auto it_rhs = std::find_if(log_channels_configs.begin(), - log_channels_configs.end(), - [lcid_rhs](const logical_channel_config& lc_ch) { return lc_ch.lcid == lcid_rhs; }); - return it_lhs->priority < it_rhs->priority; - }); +void dl_logical_channel_manager::handle_mac_ce_indication(const mac_ce_info& ce) +{ + if (ce.ce_lcid == lcid_dl_sch_t::UE_CON_RES_ID) { + // CON RES is a special case, as it needs to be always scheduled first. + pending_con_res_id = true; + return; + } + if (ce.ce_lcid == lcid_dl_sch_t::TA_CMD) { + auto ce_it = std::find_if(pending_ces.begin(), pending_ces.end(), [](const mac_ce_info& c) { + return c.ce_lcid == lcid_dl_sch_t::TA_CMD; + }); + if (ce_it != pending_ces.end()) { + ce_it->ce_payload = ce.ce_payload; + return; + } + } + pending_ces.push_back(ce); } unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, unsigned rem_bytes, lcid_t lcid) @@ -81,7 +175,7 @@ unsigned dl_logical_channel_manager::allocate_mac_sdu(dl_msg_lc_info& subpdu, un lcid_t dl_logical_channel_manager::get_max_prio_lcid() const { for (const auto lcid : sorted_channels) { - if (channels[lcid].active and channels[lcid].buf_st > 0) { + if (has_pending_bytes(lcid)) { return lcid; } } @@ -241,11 +335,6 @@ unsigned dl_logical_channel_manager::allocate_ue_con_res_id_mac_ce(dl_msg_lc_inf return alloc_bytes; } -span dl_logical_channel_manager::get_prioritized_logical_channels() const -{ - return sorted_channels; -} - unsigned srsran::allocate_ue_con_res_id_mac_ce(dl_msg_tb_info& tb_info, dl_logical_channel_manager& lch_mng, unsigned total_tbs) { diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index 7b6373e30d..1fef82ae91 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -35,29 +35,20 @@ class dl_logical_channel_manager void deactivate(); /// \brief Activate/Deactivate Bearer. - void set_status(lcid_t lcid, bool active) - { - srsran_sanity_check(lcid < MAX_NOF_RB_LCIDS, "Max LCID value 32 exceeded"); - channels[lcid].active = active; - } + void set_status(lcid_t lcid, bool active); /// \brief Update the configurations of the provided lists of bearers. void configure(span log_channels_configs); /// \brief Verifies if logical channel is activated for DL. - bool is_active(lcid_t lcid) const - { - if (lcid > LCID_MAX_DRB) { - return false; - } - return channels[lcid].active; - } + bool is_active(lcid_t lcid) const { return lcid <= LCID_MAX_DRB and channels[lcid].active; } /// \brief Checks whether the UE has pending data, regardless of the state it is in. bool has_pending_bytes() const { - return has_pending_ces() or - std::any_of(channels.begin(), channels.end(), [](const auto& ch) { return ch.active and ch.buf_st > 0; }); + return has_pending_ces() or std::any_of(sorted_channels.begin(), sorted_channels.end(), [this](lcid_t lcid) { + return channels[lcid].active and channels[lcid].buf_st > 0; + }); } /// \brief Check whether the UE has pending data, given its current state. @@ -66,8 +57,8 @@ class dl_logical_channel_manager if (fallback_enabled) { return is_con_res_id_pending() or has_pending_bytes(LCID_SRB0) or has_pending_bytes(LCID_SRB1); } - return has_pending_ces() or std::any_of(channels.begin() + 1, channels.end(), [](const auto& ch) { - return ch.active and ch.buf_st > 0; + return has_pending_ces() or std::any_of(sorted_channels.begin(), sorted_channels.end(), [this](lcid_t lcid) { + return lcid != LCID_SRB0 and channels[lcid].active and channels[lcid].buf_st > 0; }); } @@ -85,8 +76,8 @@ class dl_logical_channel_manager unsigned total_pending_bytes() const { unsigned bytes = pending_ce_bytes(); - for (unsigned i = 0; i <= MAX_LCID; ++i) { - bytes += pending_bytes(static_cast(i)); + for (lcid_t lcid : sorted_channels) { + bytes += pending_bytes(lcid); } return bytes; } @@ -98,8 +89,8 @@ class dl_logical_channel_manager return pending_con_res_ce_bytes() + pending_bytes(LCID_SRB0) + pending_bytes(LCID_SRB1); } unsigned bytes = pending_ce_bytes(); - for (unsigned i = 1; i <= MAX_LCID; ++i) { - bytes += pending_bytes(static_cast(i)); + for (lcid_t lcid : sorted_channels) { + bytes += lcid != LCID_SRB0 ? pending_bytes(lcid) : 0; } return bytes; } @@ -136,24 +127,7 @@ class dl_logical_channel_manager } /// \brief Enqueue new MAC CE to be scheduled. - void handle_mac_ce_indication(const mac_ce_info& ce) - { - if (ce.ce_lcid == lcid_dl_sch_t::UE_CON_RES_ID) { - // CON RES is a special case, as it needs to be always scheduled first. - pending_con_res_id = true; - return; - } - if (ce.ce_lcid == lcid_dl_sch_t::TA_CMD) { - auto ce_it = std::find_if(pending_ces.begin(), pending_ces.end(), [](const mac_ce_info& c) { - return c.ce_lcid == lcid_dl_sch_t::TA_CMD; - }); - if (ce_it != pending_ces.end()) { - ce_it->ce_payload = ce.ce_payload; - return; - } - } - pending_ces.push_back(ce); - } + void handle_mac_ce_indication(const mac_ce_info& ce); /// \brief Allocates highest priority MAC SDU within space of \c rem_bytes bytes. Updates \c lch_info with allocated /// bytes for the MAC SDU (no MAC subheader). @@ -172,29 +146,40 @@ class dl_logical_channel_manager unsigned allocate_ue_con_res_id_mac_ce(dl_msg_lc_info& lch_info, unsigned rem_bytes); /// \brief Returns a list of LCIDs sorted based on decreasing order of priority. - span get_prioritized_logical_channels() const; + span get_prioritized_logical_channels() const { return sorted_channels; } private: struct channel_context { bool active = false; + /// Configuration of the logical channel. + const logical_channel_config* cfg = nullptr; /// DL Buffer status of this logical channel. unsigned buf_st = 0; }; + struct active_channel { + /// Pending bytes for this logical channel. + unsigned buf_st = 0; + }; + /// \brief Returns the next highest priority LCID. The prioritization policy is implementation-defined. lcid_t get_max_prio_lcid() const; /// \brief Updates DL Buffer State for a given LCID based on available space. unsigned allocate_mac_sdu(dl_msg_lc_info& subpdu, lcid_t lcid, unsigned rem_bytes); + // List of UE-dedicated logical channel configurations. + span channel_configs; + + // State of configured channels. std::array channels; - /// List of logical channel IDs sorted in decreasing order of priority. i.e. first element has the highest priority. + // List of logical channel IDs sorted in decreasing order of priority. i.e. first element has the highest priority. std::vector sorted_channels; bool pending_con_res_id{false}; - /// \brief List of pending CEs except UE Contention Resolution Identity. + // List of pending CEs except UE Contention Resolution Identity. std::deque pending_ces; }; diff --git a/lib/scheduler/ue_context/ue.cpp b/lib/scheduler/ue_context/ue.cpp index 15cdba4f41..35a18a9149 100644 --- a/lib/scheduler/ue_context/ue.cpp +++ b/lib/scheduler/ue_context/ue.cpp @@ -225,7 +225,7 @@ unsigned ue::build_dl_transport_block_info(dl_msg_tb_info& unsigned total_subpdu_bytes = 0; total_subpdu_bytes += allocate_mac_ces(tb_info, dl_lc_ch_mgr, tb_size_bytes); for (const auto lcid : dl_lc_ch_mgr.get_prioritized_logical_channels()) { - if (lcids.test(lcid)) { + if (lcid < lcids.size() and lcids.test(lcid)) { total_subpdu_bytes += allocate_mac_sdus(tb_info, dl_lc_ch_mgr, tb_size_bytes - total_subpdu_bytes, uint_to_lcid(lcid)); } From ef1c822333b01fa06c3567f9ac008b6b0cd78a41 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 14:09:38 +0100 Subject: [PATCH 173/227] sched: fix flaky unit test due to ambiguity in logical channel pending bytes --- .../scheduler/ue_scheduling/logical_channel_test.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index 3aed66b8fd..6304b96fd4 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -214,10 +214,15 @@ TEST(dl_logical_channel_test, mac_sdu_is_scheduled_if_tb_has_space) ASSERT_FALSE(lch_mng.has_pending_bytes()) << "subPDU is large enough to deplete all the pending tx bytes"; } else { rem_sdu_size -= subpdu.sched_bytes; - // Note: In the case the logical channel was totally flushed, the manager adds some extra bytes to account for + // Note: In the case the logical channel was not totally flushed, the manager adds some extra bytes to account for // RLC overhead. const unsigned RLC_SEGMENTATION_OVERHEAD = 4; - ASSERT_EQ(get_mac_sdu_required_bytes(rem_sdu_size), lch_mng.total_pending_bytes() - RLC_SEGMENTATION_OVERHEAD) + unsigned req_bytes = get_mac_sdu_required_bytes(rem_sdu_size); + if (req_bytes == 256) { + // Note: account for ambiguity in transition between MAC subheader sizes. + req_bytes++; + } + ASSERT_EQ(req_bytes, lch_mng.total_pending_bytes() - RLC_SEGMENTATION_OVERHEAD) << "incorrect calculation of remaining pending tx bytes"; } From c3407f79d905ebe73d643b1d7ce5ca735c8d2c5b Mon Sep 17 00:00:00 2001 From: frankist Date: Sun, 15 Dec 2024 15:06:10 +0100 Subject: [PATCH 174/227] sched: fix missing config_applied() signal in ue scheduler unit test --- .../unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 429a9a68ed..87cceedf68 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -529,6 +529,7 @@ TEST_P(ue_grid_allocator_tester, successfully_allocates_pdsch_with_gbr_lc_priort .gbr_qos_info = gbr_qos_flow_information{128000, 128000, 128000, 128000}}; ue_config_update_event ev = cfg_mng.update_ue(reconf_msg); u1.handle_reconfiguration_request({ev.next_config()}); + u1.handle_config_applied(); // Add LCID to the bearers of the UE belonging to this slice. for (const auto& lc_cfg : *cfg_req.lc_config_list) { From 74da9d5f30efe94313443e49ee6f0cbe11f40234 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 14:21:10 +0100 Subject: [PATCH 175/227] du-manager: fix generation of ASN.1 meas Gap config --- .../du_high/du_manager/converters/asn1_rrc_config_helpers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp b/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp index 295b123386..b9d060ffd2 100644 --- a/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp +++ b/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp @@ -3302,7 +3302,9 @@ static gap_cfg_s make_gap_cfg(const meas_gap_config& cfg) gap.gap_offset = cfg.offset; gap.mgl.value = (asn1::rrc_nr::gap_cfg_s::mgl_opts::options)cfg.mgl; - gap.mgrp.value = (asn1::rrc_nr::gap_cfg_s::mgrp_opts::options)cfg.mgrp; + if (not asn1::number_to_enum(gap.mgrp, (uint8_t)cfg.mgrp)) { + gap.mgrp.value = asn1::rrc_nr::gap_cfg_s::mgrp_opts::nulltype; + } return gap; } From 896d02c4fe0193a75014ca2d5af030f98e24c18d Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 15:04:04 +0100 Subject: [PATCH 176/227] du-manager: fix generation of ASN.1 meas Gap MGTA value --- lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp b/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp index b9d060ffd2..098a047e30 100644 --- a/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp +++ b/lib/du/du_high/du_manager/converters/asn1_rrc_config_helpers.cpp @@ -3305,6 +3305,7 @@ static gap_cfg_s make_gap_cfg(const meas_gap_config& cfg) if (not asn1::number_to_enum(gap.mgrp, (uint8_t)cfg.mgrp)) { gap.mgrp.value = asn1::rrc_nr::gap_cfg_s::mgrp_opts::nulltype; } + gap.mgta.value = gap_cfg_s::mgta_opts::ms0; return gap; } From 24f89b7c27781487d55a4b4a285e844c901b68fa Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 13 Dec 2024 16:19:39 +0100 Subject: [PATCH 177/227] cu_cp,rrc: add measurement config to ue context setup/modification --- include/srsran/rrc/meas_types.h | 45 ++++-------------- include/srsran/rrc/rrc_types.h | 4 +- include/srsran/rrc/rrc_ue.h | 8 +++- .../mobility/intra_cu_handover_routine.cpp | 1 + ..._session_resource_modification_routine.cpp | 2 + .../pdu_session_resource_setup_routine.cpp | 3 +- .../routines/pdu_session_routine_helpers.cpp | 5 ++ lib/rrc/ue/rrc_asn1_helpers.cpp | 13 ++++++ .../rrc_measurement_types_asn1_converters.cpp | 46 ------------------- lib/rrc/ue/rrc_ue_impl.h | 1 + lib/rrc/ue/rrc_ue_message_handlers.cpp | 15 ++++++ .../handover_reconfiguration_routine_test.cpp | 16 ++++++- 12 files changed, 72 insertions(+), 87 deletions(-) diff --git a/include/srsran/rrc/meas_types.h b/include/srsran/rrc/meas_types.h index 74a290c18b..ea6281246e 100644 --- a/include/srsran/rrc/meas_types.h +++ b/include/srsran/rrc/meas_types.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/adt/byte_buffer.h" #include "srsran/adt/slotted_array.h" #include "srsran/ran/pci.h" #include "srsran/ran/subcarrier_spacing.h" @@ -467,42 +468,16 @@ struct rrc_quant_cfg { std::vector quant_cfg_nr_list; }; -struct rrc_gap_cfg { - uint8_t gap_offset; - uint8_t mgl; - uint8_t mgrp; - float mgta; -}; - -struct rrc_gap_cfg_setup_release { - bool is_release; - std::optional setup; -}; - -struct rrc_measg_gap_cfg { - std::optional gap_fr2; -}; - -struct rrc_meas_gap_sharing_scheme_setup_release { - bool is_release; - std::optional setup; -}; - -struct rrc_meas_gap_sharing_cfg { - std::optional gap_sharing_fr2; -}; - struct rrc_meas_cfg { - std::vector meas_obj_to_rem_list; - std::vector meas_obj_to_add_mod_list; - std::vector report_cfg_to_rem_list; - std::vector report_cfg_to_add_mod_list; - std::vector meas_id_to_rem_list; - std::vector meas_id_to_add_mod_list; - std::optional s_measure_cfg; - std::optional quant_cfg; - std::optional meas_gap_cfg; - std::optional meas_gap_sharing_cfg; + std::vector meas_obj_to_rem_list; + std::vector meas_obj_to_add_mod_list; + std::vector report_cfg_to_rem_list; + std::vector report_cfg_to_add_mod_list; + std::vector meas_id_to_rem_list; + std::vector meas_id_to_add_mod_list; + std::optional s_measure_cfg; + std::optional quant_cfg; + // The meas gap config is excluded from the common type and stored in the RRC UE context. }; struct rrc_meas_quant_results { diff --git a/include/srsran/rrc/rrc_types.h b/include/srsran/rrc/rrc_types.h index 5eb36bd54f..4750d2cc5c 100644 --- a/include/srsran/rrc/rrc_types.h +++ b/include/srsran/rrc/rrc_types.h @@ -101,7 +101,9 @@ struct rrc_reconfiguration_procedure_request { std::optional radio_bearer_cfg; byte_buffer secondary_cell_group; std::optional meas_cfg; - std::optional non_crit_ext; + // Optional measurement gap config to include in Reconfiguration. + byte_buffer meas_gap_cfg; + std::optional non_crit_ext; }; struct rrc_ue_capability_transfer_request { diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index e33d090033..08baebf599 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -265,9 +265,13 @@ class rrc_ue_control_message_handler virtual rrc_ue_transfer_context get_transfer_context() = 0; /// \brief Get the RRC measurement config for the current serving cell of the UE. - /// \params[in] current_meas_config The current meas config of the UE (if applicable). + /// \param[in] current_meas_config The current meas config of the UE (if applicable). /// \return The measurement config, if present. - virtual std::optional generate_meas_config(std::optional current_meas_config = {}) = 0; + virtual std::optional + generate_meas_config(std::optional current_meas_config = std::nullopt) = 0; + + /// \brief Get the packed RRC measurement config for the current serving cell of the UE. + virtual byte_buffer get_packed_meas_config() = 0; /// \brief Handle the handover command RRC PDU. /// \param[in] cmd The handover command RRC PDU. 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 9bf1b5064f..cfcdd746d2 100644 --- a/lib/cu_cp/routines/mobility/intra_cu_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/intra_cu_handover_routine.cpp @@ -101,6 +101,7 @@ void intra_cu_handover_routine::operator()(coro_contextget_rrc_ue()->get_packed_meas_config(); CORO_AWAIT_VALUE(target_ue_context_setup_response, target_du_f1ap_ue_ctxt_mng.handle_ue_context_setup_request(target_ue_context_setup_request, 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 ae6db7dc52..2830ad1232 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -107,6 +107,8 @@ void pdu_session_resource_modification_routine::operator()( { // Prepare UEContextModificationRequest and call F1 notifier. ue_context_mod_request.ue_index = modify_request.ue_index; + ue_context_mod_request.cu_to_du_rrc_info.emplace(); + ue_context_mod_request.cu_to_du_rrc_info->meas_cfg = rrc_ue->get_packed_meas_config(); CORO_AWAIT_VALUE(ue_context_modification_response, f1ap_ue_ctxt_mng.handle_ue_context_modification_request(ue_context_mod_request)); 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 a5c9e0a429..45999eba04 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -154,6 +154,7 @@ void pdu_session_resource_setup_routine::operator()( 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 = rrc_ue->get_packed_ue_capability_rat_container_list(); + ue_context_mod_request.cu_to_du_rrc_info.value().meas_cfg = rrc_ue->get_packed_meas_config(); // DRB setup have already added above. CORO_AWAIT_VALUE(ue_context_modification_response, @@ -217,7 +218,7 @@ void pdu_session_resource_setup_routine::operator()( {} /* No extra DRB to be removed */, ue_context_modification_response.du_to_cu_rrc_info, nas_pdus, - next_config.initial_context_creation ? rrc_ue->generate_meas_config() + next_config.initial_context_creation ? rrc_ue->generate_meas_config(std::nullopt) : std::optional{}, false, false, diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index d92dccd178..9a9694a02d 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -172,6 +172,11 @@ bool srsran::srs_cu_cp::fill_rrc_reconfig_args( rrc_reconfig_args.meas_cfg = rrc_meas_cfg; + // Fill meas gap config. + if (!du_to_cu_rrc_info.meas_gap_cfg.empty()) { + rrc_reconfig_args.meas_gap_cfg = du_to_cu_rrc_info.meas_gap_cfg.copy(); + } + if (!sib1.empty()) { rrc_reconfig_args.non_crit_ext.value().ded_sib1_delivery = std::move(sib1); } diff --git a/lib/rrc/ue/rrc_asn1_helpers.cpp b/lib/rrc/ue/rrc_asn1_helpers.cpp index 0964c26461..95e67dc553 100644 --- a/lib/rrc/ue/rrc_asn1_helpers.cpp +++ b/lib/rrc/ue/rrc_asn1_helpers.cpp @@ -214,6 +214,19 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf if (rrc_reconf.meas_cfg.has_value()) { asn1_reconfig_ies.meas_cfg_present = true; asn1_reconfig_ies.meas_cfg = meas_config_to_rrc_asn1(rrc_reconf.meas_cfg.value()); + + // Fill measurement gap config. + if (!rrc_reconf.meas_gap_cfg.empty()) { + asn1_reconfig_ies.meas_cfg.meas_gap_cfg_present = true; + + // Unpack measurement gap config PDU. + asn1::rrc_nr::meas_gap_cfg_s asn1_meas_gap_cfg; + asn1::cbit_ref bref(rrc_reconf.meas_gap_cfg); + + if (asn1_reconfig_ies.meas_cfg.meas_gap_cfg.unpack(bref) != asn1::SRSASN_SUCCESS) { + report_fatal_error("Couldn't unpack MeasGapConfig RRC container"); + } + } } // non crit ext diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp b/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp index 3294895d02..077f50e555 100644 --- a/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.cpp @@ -1099,52 +1099,6 @@ asn1::rrc_nr::meas_cfg_s srsran::srs_cu_cp::meas_config_to_rrc_asn1(const rrc_me } } - // meas gap cfg - if (meas_cfg.meas_gap_cfg.has_value()) { - asn1_meas_cfg.meas_gap_cfg_present = true; - if (meas_cfg.meas_gap_cfg.value().gap_fr2.has_value()) { - asn1_meas_cfg.meas_gap_cfg.gap_fr2_present = true; - if (meas_cfg.meas_gap_cfg.value().gap_fr2.value().is_release) { - asn1_meas_cfg.meas_gap_cfg.gap_fr2.set_release(); - } else if (meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.has_value()) { - asn1_meas_cfg.meas_gap_cfg.gap_fr2.set_setup(); - // gap offset - asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().gap_offset = - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().gap_offset; - // mgl - asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgl, - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgl); - // mgrp - asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgrp, - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgrp); - // mgta - asn1::number_to_enum(asn1_meas_cfg.meas_gap_cfg.gap_fr2.setup().mgta, - meas_cfg.meas_gap_cfg.value().gap_fr2.value().setup.value().mgta); - } else { - // error - report_fatal_error("Cannot convert gap fr2 to ASN.1 type"); - } - } - } - - // meas gap sharing cfg - if (meas_cfg.meas_gap_sharing_cfg.has_value()) { - asn1_meas_cfg.meas_gap_sharing_cfg_present = true; - if (meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.has_value()) { - asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2_present = true; - if (meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().is_release) { - asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.set_release(); - } else if (!meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().setup.value().empty()) { - asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.set_setup(); - asn1::string_to_enum(asn1_meas_cfg.meas_gap_sharing_cfg.gap_sharing_fr2.setup(), - meas_cfg.meas_gap_sharing_cfg.value().gap_sharing_fr2.value().setup.value()); - } else { - // error - report_fatal_error("Cannot convert gap sharing fr2 to ASN.1 type"); - } - } - } - return asn1_meas_cfg; } diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index 8381befcab..2bc5f45947 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -66,6 +66,7 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller rrc_ue_release_context get_rrc_ue_release_context(bool requires_rrc_message) override; rrc_ue_transfer_context get_transfer_context() override; std::optional generate_meas_config(std::optional current_meas_config) override; + byte_buffer get_packed_meas_config() override; byte_buffer get_rrc_handover_command(const rrc_reconfiguration_procedure_request& request, unsigned transaction_id) override; byte_buffer handle_rrc_handover_command(byte_buffer cmd) override; diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index f4b72cd833..951ef5498c 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -18,6 +18,7 @@ #include "ue/rrc_measurement_types_asn1_converters.h" #include "srsran/asn1/asn1_utils.h" #include "srsran/asn1/rrc_nr/dl_ccch_msg.h" +#include "srsran/asn1/rrc_nr/meas_cfg.h" #include "srsran/asn1/rrc_nr/ul_ccch_msg.h" #include "srsran/ran/rb_id.h" @@ -578,9 +579,23 @@ std::optional rrc_ue_impl::generate_meas_config(std::optional generate_meas_config(std::optional current_meas_config = {}) override + std::optional + generate_meas_config(std::optional current_meas_config = std::nullopt) override { + logger.info("Received a new request to generate RRC UE meas config"); std::optional meas_config; return meas_config; } + byte_buffer get_packed_meas_config() override + { + logger.info("Received a new request to get packed RRC UE meas config"); + return {}; + } + byte_buffer handle_rrc_handover_command(byte_buffer cmd) override { return byte_buffer{}; } byte_buffer get_rrc_handover_command(const rrc_reconfiguration_procedure_request& request, From 82815f1f3b075140007c6d4458a81d911c5f2bc1 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 13 Dec 2024 16:20:08 +0100 Subject: [PATCH 178/227] cu_cp,rrc: improve readability and documentation --- include/srsran/rrc/rrc_ue.h | 3 +- lib/cu_cp/adapters/rrc_ue_adapters.h | 3 +- .../cell_meas_manager_impl.h | 2 +- lib/cu_cp/cu_cp_impl.h | 2 +- lib/cu_cp/cu_cp_impl_interface.h | 2 +- lib/rrc/ue/rrc_asn1_helpers.cpp | 30 +++++++++---------- .../rrc_measurement_types_asn1_converters.h | 6 +++- .../du_processor_test_helpers.cpp | 2 +- tests/unittests/rrc/test_helpers.h | 3 +- 9 files changed, 30 insertions(+), 23 deletions(-) diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index 08baebf599..fe2c8e6964 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -410,7 +410,8 @@ class rrc_ue_measurement_notifier /// \param[in] nci The cell id of the serving cell to update. /// \param[in] current_meas_config The current meas config of the UE (if applicable). virtual std::optional - on_measurement_config_request(nr_cell_identity nci, std::optional current_meas_config = {}) = 0; + on_measurement_config_request(nr_cell_identity nci, + std::optional current_meas_config = std::nullopt) = 0; /// \brief Submit measurement report for given UE to cell manager. virtual void on_measurement_report(const rrc_meas_results& meas_results) = 0; diff --git a/lib/cu_cp/adapters/rrc_ue_adapters.h b/lib/cu_cp/adapters/rrc_ue_adapters.h index ce108b6f49..b6473f42df 100644 --- a/lib/cu_cp/adapters/rrc_ue_adapters.h +++ b/lib/cu_cp/adapters/rrc_ue_adapters.h @@ -239,7 +239,8 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u } std::optional - on_measurement_config_request(nr_cell_identity nci, std::optional current_meas_config = {}) override + on_measurement_config_request(nr_cell_identity nci, + std::optional current_meas_config = std::nullopt) override { srsran_assert(meas_handler != nullptr, "Measurement handler must not be nullptr"); return meas_handler->handle_measurement_config_request(ue_index, nci, current_meas_config); diff --git a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h index 0f5f6c2f7b..83d6a8a007 100644 --- a/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h +++ b/lib/cu_cp/cell_meas_manager/cell_meas_manager_impl.h @@ -44,7 +44,7 @@ class cell_meas_manager std::optional get_measurement_config(ue_index_t ue_index, nr_cell_identity nci, - std::optional current_meas_config = {}); + std::optional current_meas_config = std::nullopt); std::optional get_cell_config(nr_cell_identity nci); bool update_cell_config(nr_cell_identity nci, const serving_cell_meas_config& serv_cell_cfg); void report_measurement(ue_index_t ue_index, const rrc_meas_results& meas_results); diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index d16d805e58..cebda3348d 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -116,7 +116,7 @@ class cu_cp_impl final : public cu_cp, std::optional handle_measurement_config_request(ue_index_t ue_index, nr_cell_identity nci, - std::optional current_meas_config = {}) override; + std::optional current_meas_config = std::nullopt) override; void handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) override; // cu_cp_measurement_config_handler. diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 3d8cbcf5df..b658450a66 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -248,7 +248,7 @@ class cu_cp_measurement_handler virtual std::optional handle_measurement_config_request(ue_index_t ue_index, nr_cell_identity nci, - std::optional current_meas_config = {}) = 0; + std::optional current_meas_config = std::nullopt) = 0; /// \brief Handle a measurement report for given UE. virtual void handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) = 0; diff --git a/lib/rrc/ue/rrc_asn1_helpers.cpp b/lib/rrc/ue/rrc_asn1_helpers.cpp index 95e67dc553..4514fa18a3 100644 --- a/lib/rrc/ue/rrc_asn1_helpers.cpp +++ b/lib/rrc/ue/rrc_asn1_helpers.cpp @@ -111,14 +111,14 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf rrc_recfg_ies_s& asn1_reconfig_ies = asn1_rrc_reconf.crit_exts.set_rrc_recfg(); - // radio bearer cfg + // Fill radio bearer config. if (rrc_reconf.radio_bearer_cfg.has_value()) { asn1_reconfig_ies.radio_bearer_cfg_present = true; auto& asn1_radio_bearer_cfg = asn1_reconfig_ies.radio_bearer_cfg; auto& cu_cp_radio_bearer_cfg = rrc_reconf.radio_bearer_cfg.value(); - // srb to add mod list + // Fill SRB to add mod list. for (const auto& srb_to_add : cu_cp_radio_bearer_cfg.srb_to_add_mod_list) { srsran_assert(srb_to_add.srb_id != srb_id_t::nulltype, "Invalid SRB ID"); @@ -129,7 +129,7 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf asn1_srb_to_add.discard_on_pdcp_present = srb_to_add.discard_on_pdcp_present; - // PDCP config + // Fill PDCP config. if (srb_to_add.pdcp_cfg.has_value()) { asn1_srb_to_add.pdcp_cfg_present = true; asn1_srb_to_add.pdcp_cfg = pdcp_config_to_rrc_nr_asn1(srb_to_add.pdcp_cfg.value()); @@ -138,7 +138,7 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf asn1_radio_bearer_cfg.srb_to_add_mod_list.push_back(asn1_srb_to_add); } - // drb to add mod list + // Fill DRB to add mod list. for (const auto& drb_to_add : cu_cp_radio_bearer_cfg.drb_to_add_mod_list) { srsran_assert(drb_to_add.drb_id != drb_id_t::invalid, "Invalid DRB ID"); @@ -147,13 +147,13 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf asn1_drb_to_add.reestablish_pdcp_present = drb_to_add.reestablish_pdcp_present; - // PDCP config + // Fill PDCP config. if (drb_to_add.pdcp_cfg.has_value()) { asn1_drb_to_add.pdcp_cfg_present = true; asn1_drb_to_add.pdcp_cfg = pdcp_config_to_rrc_nr_asn1(drb_to_add.pdcp_cfg.value()); } - // Add CN association and SDAP config + // Fill CN association and SDAP config. if (drb_to_add.cn_assoc.has_value()) { asn1_drb_to_add.cn_assoc_present = true; if (drb_to_add.cn_assoc.value().sdap_cfg.has_value()) { @@ -168,27 +168,27 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf asn1_radio_bearer_cfg.drb_to_add_mod_list.push_back(asn1_drb_to_add); } - // drb to release list + // Fill DRB to release list. for (const auto& drb_to_release : cu_cp_radio_bearer_cfg.drb_to_release_list) { srsran_assert(drb_to_release != drb_id_t::invalid, "Invalid DRB ID"); asn1_radio_bearer_cfg.drb_to_release_list.push_back(drb_id_to_uint(drb_to_release)); } - // security cfg + // Fill security config. if (cu_cp_radio_bearer_cfg.security_cfg.has_value()) { asn1_radio_bearer_cfg.security_cfg_present = true; const auto& security_cfg = cu_cp_radio_bearer_cfg.security_cfg.value(); - // security algorithm cfg + // Fill security algorithm config. if (security_cfg.security_algorithm_cfg.has_value()) { asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg_present = true; - // ciphering algorithm + // Fill ciphering algorithm config. asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.ciphering_algorithm = ciphering_algorithm_to_rrc_asn1(security_cfg.security_algorithm_cfg.value().ciphering_algorithm); - // integrity prot algorithm + // Fill integrity prot algorithm config. if (security_cfg.security_algorithm_cfg.value().integrity_prot_algorithm.has_value()) { asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.integrity_prot_algorithm_present = true; asn1_radio_bearer_cfg.security_cfg.security_algorithm_cfg.integrity_prot_algorithm = @@ -196,21 +196,21 @@ void srsran::srs_cu_cp::fill_asn1_rrc_reconfiguration_msg(asn1::rrc_nr::rrc_recf security_cfg.security_algorithm_cfg.value().integrity_prot_algorithm.value()); } } - // key to use + // Fill key to use. if (security_cfg.key_to_use.has_value()) { asn1_radio_bearer_cfg.security_cfg.key_to_use_present = true; asn1::string_to_enum(asn1_radio_bearer_cfg.security_cfg.key_to_use, security_cfg.key_to_use.value()); } } - // srb3 to release present + // Fill SRB3 to release present. asn1_radio_bearer_cfg.srb3_to_release_present = cu_cp_radio_bearer_cfg.srb3_to_release_present; } - // secondary cell group + // Fill secondary cell group. asn1_reconfig_ies.secondary_cell_group = rrc_reconf.secondary_cell_group.copy(); - // meas config + // Fill measurement config. if (rrc_reconf.meas_cfg.has_value()) { asn1_reconfig_ies.meas_cfg_present = true; asn1_reconfig_ies.meas_cfg = meas_config_to_rrc_asn1(rrc_reconf.meas_cfg.value()); diff --git a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h index 6963ecc7b1..1a39c4a1c4 100644 --- a/lib/rrc/ue/rrc_measurement_types_asn1_converters.h +++ b/lib/rrc/ue/rrc_measurement_types_asn1_converters.h @@ -152,7 +152,11 @@ asn1::rrc_nr::quant_cfg_rs_s quant_cfg_rs_to_rrc_asn1(const rrc_quant_cfg_rs& qu /// \param[in] meas_cfg Meas config object. /// \return The RRC NR ASN.1 object where the result of the conversion is stored. asn1::rrc_nr::meas_cfg_s meas_config_to_rrc_asn1(const rrc_meas_cfg& meas_cfg); -rrc_meas_quant_results asn1_to_meas_quant_results(const asn1::rrc_nr::meas_quant_results_s& asn1_meas_quant_results); + +/// \brief Convert ASN.1 type \c asn1::rrc_nr::meas_quant_results_s to common type. +/// \param[in] asn1_meas_quant_results measurement quant result nr ASN.1 object. +/// \return The common type object where the result of the conversion is stored. +rrc_meas_quant_results asn1_to_meas_quant_results(const asn1::rrc_nr::meas_quant_results_s& asn1_meas_quant_results); /// \brief Convert ASN.1 type \c asn1::rrc_nr::meas_result_nr_s to common type. /// \param[in] asn1_meas_result_nr measurement result nr ASN.1 object. 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 fb0d6bb2c4..bc48100c97 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 @@ -39,7 +39,7 @@ struct dummy_cu_cp_measurement_handler : public cu_cp_measurement_handler { std::optional handle_measurement_config_request(ue_index_t ue_index, nr_cell_identity nci, - std::optional current_meas_config = {}) override + std::optional current_meas_config = std::nullopt) override { return std::nullopt; }; diff --git a/tests/unittests/rrc/test_helpers.h b/tests/unittests/rrc/test_helpers.h index f449ea8144..f54f635f77 100644 --- a/tests/unittests/rrc/test_helpers.h +++ b/tests/unittests/rrc/test_helpers.h @@ -136,7 +136,8 @@ class dummy_rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public } std::optional - on_measurement_config_request(nr_cell_identity nci, std::optional current_meas_config = {}) override + on_measurement_config_request(nr_cell_identity nci, + std::optional current_meas_config = std::nullopt) override { std::optional meas_cfg; return meas_cfg; From 49946698bda09d15ff1f836778af285d629ff14c Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 12:13:17 +0100 Subject: [PATCH 179/227] du: use true multicell as the default --- apps/du/du_appconfig.h | 2 +- apps/gnb/gnb_appconfig.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index 4d4f4d9262..66acbfb75d 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -47,7 +47,7 @@ struct du_appconfig { /// Default constructor to update the log filename. du_appconfig() { log_cfg.filename = "/tmp/du.log"; } /// DU multicell flag. - bool du_multicell_enabled = false; + bool du_multicell_enabled = true; /// Loggers configuration. logger_appconfig log_cfg; /// Metrics configuration. diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 17d31a90ea..dada5d43c4 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -36,7 +36,7 @@ struct gnb_appconfig { /// Default constructor to update the log filename. gnb_appconfig() { log_cfg.filename = "/tmp/gnb.log"; } /// DU multicell flag. - bool du_multicell_enabled = false; + bool du_multicell_enabled = true; /// Loggers configuration. logger_appconfig log_cfg; /// Metrics configuration. From ecbed65bbfec0bd5f67ab867b2bf3b05f9158fcb Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 12:16:06 +0100 Subject: [PATCH 180/227] du: comment that the du multicell set to false is deprecated --- apps/du/du_appconfig.h | 2 +- apps/gnb/gnb_appconfig.h | 2 +- apps/gnb/gnb_appconfig_cli11_schema.cpp | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index 66acbfb75d..e8f740a6f7 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -46,7 +46,7 @@ struct metrics_appconfig { struct du_appconfig { /// Default constructor to update the log filename. du_appconfig() { log_cfg.filename = "/tmp/du.log"; } - /// DU multicell flag. + /// DU multicell flag. This flag set to false is a deprecated feature. bool du_multicell_enabled = true; /// Loggers configuration. logger_appconfig log_cfg; diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index dada5d43c4..15a03f426d 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -35,7 +35,7 @@ struct metrics_appconfig { struct gnb_appconfig { /// Default constructor to update the log filename. gnb_appconfig() { log_cfg.filename = "/tmp/gnb.log"; } - /// DU multicell flag. + /// DU multicell flag. This flag set to false is a deprecated feature. bool du_multicell_enabled = true; /// Loggers configuration. logger_appconfig log_cfg; diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index 8ceb127965..e43d9bfd5c 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -43,7 +43,11 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon ->check(CLI::Range(22, 32)); add_option(app, "--ran_node_name", gnb_cfg.ran_node_name, "RAN node name")->capture_default_str(); - add_option(app, "--du_multicell_enabled", gnb_parsed_cfg.du_multicell_enabled, "DU multicell enabled flag") + add_option(app, + "--du_multicell_enabled", + gnb_parsed_cfg.du_multicell_enabled, + "DU multicell enabled flag. The support for the value 'false' is deprecated and will be removed in future " + "releases") ->capture_default_str(); // Loggers section. From fb4ed3f19d2cfa9f12ae03dbcb94cf4d40b9da5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 16 Dec 2024 15:12:02 +0100 Subject: [PATCH 181/227] ci: update retina --- .gitlab/ci/e2e/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index d296fba376..0d13a79dd8 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.58.5 +RETINA_VERSION=0.58.7 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From bb5f3dbf4f6348124a6e17cadf87468c1343358a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 16 Dec 2024 15:12:25 +0100 Subject: [PATCH 182/227] ci: increase viavi extended timeout --- .gitlab/ci/e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 957da2108c..b6ca7925bc 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -537,6 +537,7 @@ viavi-extended: viavi-extended-24h: extends: .viavi + timeout: 28 hours rules: - if: $CI_DESCRIPTION =~ /Weekly/ variables: From 1f98d4d0ba2257abfdaec0db30dfbd93f9fa232a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 16 Dec 2024 15:13:41 +0100 Subject: [PATCH 183/227] ci: upgrade clang used in smoke tsan test --- .gitlab/ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 946ac3a1cf..9e87d49da6 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -258,7 +258,7 @@ variables: extends: .build_and_unit variables: PLUGIN_BRANCH: $MR_PLUGIN_REF - OS: ubuntu-24.04 + OS: ubuntu-24.10 COMPILER: clang CMAKE_BUILD_TYPE: Debug ASSERT_LEVEL: PARANOID From 3de6aac01fcb8e874298aa5073bedf99341d8918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 16 Dec 2024 15:16:34 +0100 Subject: [PATCH 184/227] ci: gcovr exclude updated --- .gitlab/ci/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 9e87d49da6..eabda58e1d 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -163,6 +163,8 @@ variables: --exclude=${CI_PROJECT_DIR}/lib/asn1/ngap/.* \ --exclude=${CI_PROJECT_DIR}/lib/asn1/nrppa/.* \ --exclude=${CI_PROJECT_DIR}/lib/asn1/rrc_nr/.* \ + --exclude=${CI_PROJECT_DIR}/plugins/.*/include/srsran/asn1/nrppa/.* \ + --exclude=${CI_PROJECT_DIR}/plugins/.*/lib/asn1/nrppa/.* \ --exclude-lines-by-pattern \".*srsran_assert.*|.*srsran_sanity_check.*\" \ --root=${CI_PROJECT_DIR}" From 7f3f14193a3cb434b816e24ae9a2c58355b40827 Mon Sep 17 00:00:00 2001 From: faluco Date: Mon, 16 Dec 2024 12:51:15 +0100 Subject: [PATCH 185/227] - Fix deadlock in unique fd. - [EPOLL BROKER] Avoid enqueueing for execution a read callback if the FD was requested to be removed. --- include/srsran/support/io/io_broker.h | 40 ++++++++----------------- lib/support/network/io_broker_epoll.cpp | 9 ++++++ 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/include/srsran/support/io/io_broker.h b/include/srsran/support/io/io_broker.h index a4ef4335b8..3670d9f055 100644 --- a/include/srsran/support/io/io_broker.h +++ b/include/srsran/support/io/io_broker.h @@ -13,8 +13,8 @@ #include "srsran/support/executors/task_executor.h" #include "srsran/support/executors/unique_thread.h" #include "srsran/support/io/unique_fd.h" +#include #include -#include #include namespace srsran { @@ -45,55 +45,43 @@ class io_broker subscriber(subscriber&& other) noexcept { - std::lock_guard lock(other.mutex); + fd = other.fd.exchange(-1); broker = other.broker; - fd = std::exchange(other.fd, -1); } subscriber& operator=(subscriber&& other) noexcept { - std::scoped_lock lock(mutex, other.mutex); - - reset_nolock(); + reset_impl(); + fd = other.fd.exchange(-1); broker = other.broker; - fd = std::exchange(other.fd, -1); return *this; } ~subscriber() { reset(); } /// Checks whether the FD is connected to the broker. - bool registered() const - { - std::lock_guard lock(mutex); - return fd >= 0; - } + bool registered() const { return fd >= 0; } /// Resets the handle, deregistering the FD from the broker. /// \note: This function will block until the FD has been removed from the broker. bool reset() { - std::lock_guard lock(mutex); - std::promise p; - std::future fut = p.get_future(); + std::promise p; + std::future fut = p.get_future(); - bool ret = reset_nolock(&p); + bool ret = reset_impl(&p); fut.get(); return ret; } /// Returns the file descriptor value held by this subscriber. - int value() const - { - std::lock_guard lock(mutex); - return fd; - } + int value() const { return fd; } private: - bool reset_nolock(std::promise* complete_notifier = nullptr) + bool reset_impl(std::promise* complete_notifier = nullptr) { - int fd_tmp = std::exchange(fd, -1); + int fd_tmp = fd.exchange(-1); if (fd_tmp >= 0) { return broker->unregister_fd(fd_tmp, complete_notifier); } @@ -103,10 +91,8 @@ class io_broker return false; } - // Mutex unique to the subscriber object. - mutable std::mutex mutex; - io_broker* broker = nullptr; - int fd = -1; + io_broker* broker = nullptr; + std::atomic fd{-1}; }; /// Callback called when registered fd has data diff --git a/lib/support/network/io_broker_epoll.cpp b/lib/support/network/io_broker_epoll.cpp index 3392a06a46..4fe3f50e56 100644 --- a/lib/support/network/io_broker_epoll.cpp +++ b/lib/support/network/io_broker_epoll.cpp @@ -167,6 +167,15 @@ void io_broker_epoll::thread_loop() continue; } + // Avoid enqueuing the callback if this FD is enqueued for deletion. It will be removed in the next loop + // iteration. + if (auto pending_it = std::find_if(pending_fds_to_remove.begin(), + pending_fds_to_remove.end(), + [fd](const auto& elem) { return fd == elem.first; }); + pending_it != pending_fds_to_remove.end()) { + continue; + } + it->second.is_executing_recv_callback.store(true, std::memory_order_release); if (not it->second.executor->defer([this, fd, From b7e0a33299f5edd6015a738c9e18ad3ee19680d7 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Mon, 16 Dec 2024 11:11:48 +0100 Subject: [PATCH 186/227] cli: fix setting of mcs_table={qam64,qam256} --- .../du_high/du_high_config_cli11_schema.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index c2925b9d6a..d324efc6eb 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -250,8 +250,12 @@ static void configure_cli11_pdsch_args(CLI::App& app, du_high_unit_pdsch_config& app, "--mcs_table", [&pdsch_params](const std::string& value) { - if (value == "qam256") { + if (value == "qam64") { + pdsch_params.mcs_table = pdsch_mcs_table::qam64; + } else if (value == "qam256") { pdsch_params.mcs_table = pdsch_mcs_table::qam256; + } else { + report_fatal_error("PDSCH mcs_table={} not in {{qam64,qam256}}.", value); } }, "MCS table to use PDSCH") @@ -653,8 +657,12 @@ static void configure_cli11_pusch_args(CLI::App& app, du_high_unit_pusch_config& app, "--mcs_table", [&pusch_params](const std::string& value) { - if (value == "qam256") { + if (value == "qam64") { + pusch_params.mcs_table = pusch_mcs_table::qam64; + } else if (value == "qam256") { pusch_params.mcs_table = pusch_mcs_table::qam256; + } else { + report_fatal_error("PUSCH mcs_table={} not in {{qam64,qam256}}.", value); } }, "MCS table to use PUSCH") From 517a135ac1202b4d202fd25786263d2ccfa11b7e Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Mon, 16 Dec 2024 12:18:26 +0100 Subject: [PATCH 187/227] config: update srsUE config, pdsch.mcs_table=qam64 --- configs/gnb_rf_b210_fdd_srsUE.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/gnb_rf_b210_fdd_srsUE.yml b/configs/gnb_rf_b210_fdd_srsUE.yml index 5096a1c434..d90752e382 100644 --- a/configs/gnb_rf_b210_fdd_srsUE.yml +++ b/configs/gnb_rf_b210_fdd_srsUE.yml @@ -41,6 +41,8 @@ cell_cfg: coreset0_index: 12 prach: prach_config_index: 1 + pdsch: + mcs_table: qam64 log: filename: /tmp/gnb.log From fee26f41e10ccfad6ed142196583adc55133c238 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Mon, 16 Dec 2024 12:26:35 +0100 Subject: [PATCH 188/227] tests,e2e: set pdsch_mcs_table and pusch_mcs_table for srsUE tests --- tests/e2e/tests/iperf.py | 8 ++++++++ tests/e2e/tests/ping.py | 6 ++++++ tests/e2e/tests/steps/configuration.py | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 12c8396bab..63452f8d9d 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -213,6 +213,8 @@ def test_srsue( always_download_artifacts=True, common_search_space_enable=True, prach_config_index=1, + pdsch_mcs_table="qam64", + pusch_mcs_table="qam64", ) @@ -266,6 +268,8 @@ def test_ric( always_download_artifacts=True, common_search_space_enable=True, prach_config_index=1, + pdsch_mcs_table="qam64", + pusch_mcs_table="qam64", ric=ric, ) @@ -746,6 +750,8 @@ def _iperf( enable_dddsu: bool = False, nof_antennas_dl: int = 1, nof_antennas_ul: int = 1, + pdsch_mcs_table: str = "qam256", + pusch_mcs_table: str = "qam256", inter_ue_start_period=INTER_UE_START_PERIOD, ric: Optional[NearRtRicStub] = None, ): @@ -768,6 +774,8 @@ def _iperf( enable_dddsu=enable_dddsu, nof_antennas_dl=nof_antennas_dl, nof_antennas_ul=nof_antennas_ul, + pdsch_mcs_table=pdsch_mcs_table, + pusch_mcs_table=pusch_mcs_table, ) configure_artifacts( retina_data=retina_data, diff --git a/tests/e2e/tests/ping.py b/tests/e2e/tests/ping.py index 7d34ba9365..4f70d432d2 100644 --- a/tests/e2e/tests/ping.py +++ b/tests/e2e/tests/ping.py @@ -352,6 +352,8 @@ def test_example_srsue( time_alignment_calibration=0, common_search_space_enable=True, prach_config_index=1, + pdsch_mcs_table="qam64", + pusch_mcs_table="qam64", ue_stop_timeout=3, ) @@ -577,6 +579,8 @@ def _ping( enable_drx: bool = False, common_search_space_enable: bool = False, prach_config_index=-1, + pdsch_mcs_table: str = "qam256", + pusch_mcs_table: str = "qam256", ): logging.info("Ping Test") @@ -596,6 +600,8 @@ def _ping( enable_drx=enable_drx, common_search_space_enable=common_search_space_enable, prach_config_index=prach_config_index, + pdsch_mcs_table=pdsch_mcs_table, + pusch_mcs_table=pusch_mcs_table, ) configure_artifacts( retina_data=retina_data, diff --git a/tests/e2e/tests/steps/configuration.py b/tests/e2e/tests/steps/configuration.py index dea4a93c3f..4000d77597 100644 --- a/tests/e2e/tests/steps/configuration.py +++ b/tests/e2e/tests/steps/configuration.py @@ -46,6 +46,8 @@ def configure_test_parameters( nof_antennas_ul: int = 1, ims_mode: str = "", enable_drx: bool = False, + pdsch_mcs_table: str = "qam256", + pusch_mcs_table: str = "qam256", ): """ Configure test parameters @@ -86,6 +88,8 @@ def configure_test_parameters( "nof_antennas_dl": nof_antennas_dl, "nof_antennas_ul": nof_antennas_ul, "enable_drx": enable_drx, + "pdsch_mcs_table": pdsch_mcs_table, + "pusch_mcs_table": pusch_mcs_table, }, }, "5gc": {"parameters": {"ims_mode": ims_mode}}, From 99d4057b28f4d240e0da98e5f8dbe23c3ca3b0cf Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Mon, 16 Dec 2024 13:59:41 +0100 Subject: [PATCH 189/227] yaml: captures the exception threw by the as method in yaml-cpp --- lib/support/config_yaml.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/support/config_yaml.cpp b/lib/support/config_yaml.cpp index c18d711ef0..fa659159ab 100644 --- a/lib/support/config_yaml.cpp +++ b/lib/support/config_yaml.cpp @@ -123,9 +123,15 @@ std::vector yaml_config_parser::from_config_impl(const YAML::No } for (const auto& node : config) { - const auto& key = node.first; - const auto& value = node.second; - const auto& key_name = key.as(); + const auto& key = node.first; + const auto& value = node.second; + + std::string key_name; + try { + key_name = key.as(); + } catch (const YAML::Exception& ex) { + throw CLI::FileError(std::string("Error parsing YAML configuration file: ") + ex.what()); + } if (value.IsScalar()) { results.emplace_back(); From 2e80544efc0a67c45eebbac107781885ac81124a Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 16:24:16 +0100 Subject: [PATCH 190/227] sched: move DL result types out of scheduler_slot_handler.h --- include/srsran/mac/cell_configuration.h | 2 +- include/srsran/ran/pdcch/dci_format.h | 37 +++ .../{scheduler_dci.h => result/dci_info.h} | 27 +- include/srsran/scheduler/result/dmrs_info.h | 39 +++ include/srsran/scheduler/result/pdcch_info.h | 90 ++++++ include/srsran/scheduler/result/pdsch_info.h | 199 +++++++++++++ .../srsran/scheduler/scheduler_configurator.h | 2 +- .../srsran/scheduler/scheduler_slot_handler.h | 276 +----------------- lib/scheduler/cell/cell_harq_manager.h | 3 +- .../pdcch_resource_allocator_impl.h | 2 +- .../pdcch_slot_resource_allocator.h | 5 +- .../pucch_scheduling/pucch_allocator_impl.h | 2 +- lib/scheduler/support/bwp_helpers.h | 2 +- lib/scheduler/support/config_helpers.h | 2 +- lib/scheduler/support/dci_builder.h | 2 +- .../support/pdcch/search_space_helper.h | 2 +- .../support/pdsch/pdsch_resource_allocation.h | 2 +- .../support/pusch/pusch_resource_allocation.h | 2 +- lib/scheduler/support/rb_helper.h | 2 +- .../ue_scheduling/ue_cell_grid_allocator.cpp | 3 +- .../scheduler/multiple_ue_sched_test.cpp | 2 +- 21 files changed, 397 insertions(+), 306 deletions(-) create mode 100644 include/srsran/ran/pdcch/dci_format.h rename include/srsran/scheduler/{scheduler_dci.h => result/dci_info.h} (83%) create mode 100644 include/srsran/scheduler/result/dmrs_info.h create mode 100644 include/srsran/scheduler/result/pdcch_info.h create mode 100644 include/srsran/scheduler/result/pdsch_info.h diff --git a/include/srsran/mac/cell_configuration.h b/include/srsran/mac/cell_configuration.h index 1e541bfbec..1d46686df9 100644 --- a/include/srsran/mac/cell_configuration.h +++ b/include/srsran/mac/cell_configuration.h @@ -19,9 +19,9 @@ #include "srsran/ran/ssb_configuration.h" #include "srsran/ran/subcarrier_spacing.h" #include "srsran/scheduler/config/bwp_configuration.h" +#include "srsran/scheduler/result/dci_info.h" #include "srsran/scheduler/sched_consts.h" #include "srsran/scheduler/scheduler_configurator.h" -#include "srsran/scheduler/scheduler_dci.h" namespace srsran { diff --git a/include/srsran/ran/pdcch/dci_format.h b/include/srsran/ran/pdcch/dci_format.h new file mode 100644 index 0000000000..23bea7ecde --- /dev/null +++ b/include/srsran/ran/pdcch/dci_format.h @@ -0,0 +1,37 @@ +/* + * + * 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 { + +/// Supported DL DCI formats. +enum class dci_dl_format { f1_0, f1_1, f2_0 }; + +/// Supported UL DCI formats. +enum class dci_ul_format { f0_0, f0_1 }; + +inline const char* dci_dl_format_to_string(dci_dl_format type) +{ + constexpr static std::array names = {"1_0", "1_1", "2_0", "invalid"}; + unsigned idx = static_cast(type); + return names[idx < names.size() ? idx : names.size() - 1]; +} + +inline const char* dci_ul_format_to_string(dci_ul_format type) +{ + constexpr static std::array names = {"0_0", "0_1", "invalid"}; + unsigned idx = static_cast(type); + return names[idx < names.size() ? idx : names.size() - 1]; +} + +} // namespace srsran diff --git a/include/srsran/scheduler/scheduler_dci.h b/include/srsran/scheduler/result/dci_info.h similarity index 83% rename from include/srsran/scheduler/scheduler_dci.h rename to include/srsran/scheduler/result/dci_info.h index 54422c66bb..d5a4582b76 100644 --- a/include/srsran/scheduler/scheduler_dci.h +++ b/include/srsran/scheduler/result/dci_info.h @@ -11,11 +11,8 @@ #pragma once #include "srsran/ran/pdcch/aggregation_level.h" +#include "srsran/ran/pdcch/dci_format.h" #include "srsran/ran/pdcch/dci_packing.h" -#include "srsran/ran/rnti.h" -#include "srsran/ran/slot_point.h" -#include "srsran/scheduler/vrb_alloc.h" -#include namespace srsran { @@ -26,9 +23,6 @@ struct cce_position { aggregation_level aggr_lvl; }; -enum class dci_dl_format { f1_0, f1_1, f2_0 }; -enum class dci_ul_format { f0_0, f0_1 }; - /// Defines which fields are stored in the DCI payload, based on the chosen DCI format and RNTI type. enum class dci_dl_rnti_config_type { si_f1_0, ra_f1_0, c_rnti_f1_0, tc_rnti_f1_0, p_rnti_f1_0, c_rnti_f1_1 }; @@ -40,16 +34,14 @@ inline dci_dl_format get_dci_dl_format(dci_dl_rnti_config_type rnti_dci_type) inline const char* dci_dl_rnti_config_rnti_type(dci_dl_rnti_config_type type) { - std::array rnti_types = {"si-rnti", "ra-rnti", "c-rnti", "tc-rnti", "p-rnti", "c-rnti"}; + static constexpr std::array rnti_types = { + "si-rnti", "ra-rnti", "c-rnti", "tc-rnti", "p-rnti", "c-rnti"}; return (unsigned)type < rnti_types.size() ? rnti_types[(unsigned)type] : "invalid"; } inline const char* dci_dl_rnti_config_format(dci_dl_rnti_config_type type) { - if (type != dci_dl_rnti_config_type::c_rnti_f1_1) { - return "1_0"; - } - return "1_1"; + return dci_dl_format_to_string(get_dci_dl_format(type)); } /// \brief Describes an unpacked DL DCI message. @@ -77,12 +69,15 @@ inline const char* dci_ul_rnti_config_rnti_type(dci_ul_rnti_config_type type) return (unsigned)type < rnti_types.size() ? rnti_types[(unsigned)type] : "invalid"; } +/// Retrieve DCI format from DCI UL payload format. +inline dci_ul_format get_dci_ul_format(dci_ul_rnti_config_type rnti_dci_type) +{ + return rnti_dci_type == dci_ul_rnti_config_type::c_rnti_f0_1 ? dci_ul_format::f0_1 : dci_ul_format::f0_0; +} + inline const char* dci_ul_rnti_config_format(dci_ul_rnti_config_type type) { - if (type != dci_ul_rnti_config_type::c_rnti_f0_1) { - return "0_0"; - } - return "0_1"; + return dci_ul_format_to_string(get_dci_ul_format(type)); } struct dci_ul_info { diff --git a/include/srsran/scheduler/result/dmrs_info.h b/include/srsran/scheduler/result/dmrs_info.h new file mode 100644 index 0000000000..20068b3828 --- /dev/null +++ b/include/srsran/scheduler/result/dmrs_info.h @@ -0,0 +1,39 @@ +/* + * + * 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/scheduler/config/dmrs.h" + +namespace srsran { + +/// Information relative to a PDSCH or PUSCH DMRS. +struct dmrs_information { + /// Bitmap of DM-RS position symbols. + dmrs_symbol_mask dmrs_symb_pos; + dmrs_config_type config_type; + /// \brief DMRS-Scrambling-ID (see TS 38.211 sec 7.4.1.1.1) as provided by parameter \f$N^{n_{SCID}}_{ID}\f$. + /// Values: (0..65535). + unsigned dmrs_scrambling_id; + /// PHY shall disregard this parameter if lowPaprDmrs=0. + unsigned dmrs_scrambling_id_complement; + /// False means that dmrs_scrambling_id == dmrs_scrambling_id_complement. + bool low_papr_dmrs; + /// \brief DMRS sequence initialization (see TS 38.211 sec 7.4.1.1.2), as provided by parameter n_{SCID}. + /// Values: false -> 0, true -> 1. + bool n_scid; + /// Values: (1..3). + uint8_t num_dmrs_cdm_grps_no_data; + /// \brief Bitmap of antenna ports. Bit 0 corresponds to antenna port 1000 and bit 11 to antenna port 1011, and + /// each bit=1 mean DM-RS port used. + bounded_bitset<12> dmrs_ports; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/pdcch_info.h b/include/srsran/scheduler/result/pdcch_info.h new file mode 100644 index 0000000000..b3237a8224 --- /dev/null +++ b/include/srsran/scheduler/result/pdcch_info.h @@ -0,0 +1,90 @@ +/* + * + * 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/ran/slot_pdu_capacity_constants.h" +#include "srsran/scheduler/result/dci_info.h" + +namespace srsran { + +/// The precoding information associated with PDCCH PDUs. +struct pdcch_precoding_info {}; + +/// Transmit power information associated with PDCCH PDU. +struct tx_power_pdcch_information { + /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. + /// \remark If the UE has not been provided dedicated higher layer parameters, the UE may assume that the ratio of + /// PDCCH DMRS EPRE to SSS EPRE is within -8 dB and 8 dB when the UE monitors PDCCHs for a DCI format 1_0 with CRC + /// scrambled by SI-RNTI, P-RNTI, or RA-RNTI. See TS 38.213, clause 4.1. + /// \remark [Implementation-defined] In case UE is not configured with powerControlOffsetSS we assume it to be 0dB. + int8_t pwr_ctrl_offset_ss{0}; +}; + +/// Information relative to the allocation of PDCCH for DCI. +struct dci_context_information { + const bwp_configuration* bwp_cfg; + const coreset_configuration* coreset_cfg; + /// RNTI used to identify the destination of this DCI (e.g. UE, RA-RNTI, SI, Paging). + rnti_t rnti; + /// Parameter \f$n_{ID}\f$ used for PDCCH Data scrambling as per 3GPP TS 38.211 [2], sec 7.3.2.3. Values: (0..65535). + /// For a UE-specific search space it equals the higherlayer parameter PDCCH-DMRS-Scrambling-ID if configured, + /// otherwise it should be set to the phy cell ID. + unsigned n_id_pdcch_data; + /// Parameter \f$n_{RNTI}\f$ used for PDCCH data scrambling, as per 3GPP TS 38.211 [2], sec 7.3.2.3. + /// Values: (0..65535). For a UE-specific search space where PDCCH-DMRSScrambling-ID is configured, this param + /// equals the CRNTI. Otherwise, it should be set to 0. + unsigned n_rnti_pdcch_data; + /// CCE position of the allocated PDCCH. + cce_position cces; + /// Starting symbol of the Search Space. + unsigned starting_symbol; + /// Precoding info used for this DCI. This field is empty in case of 1 antenna port. + std::optional precoding_info; + /// Transmission power information used for this DCI. + tx_power_pdcch_information tx_pwr; + /// Parameter \f$N_{ID}\f$ used for PDCCH DMRS scrambling as per TS38.211, 7.4.1.3.1. Values: {0, ..., 65535}. + unsigned n_id_pdcch_dmrs; + + /// \brief Information relative to a PDCCH allocation decision that is used for the purpose of logging or + /// tracing, but not passed to the PHY. + struct decision_context { + /// Chosen SearchSpace-Id. + search_space_id ss_id; + /// DCI format string. + const char* dci_format; + /// Number of slots the UE is expected to wait before transmitting a DL HARQ-ACK, upon a PDSCH reception. + std::optional harq_feedback_timing; + } context; +}; + +/// PDCCH DL allocation. +struct pdcch_dl_information { + /// Context associated with PDCCH allocation. + dci_context_information ctx; + /// DL DCI unpacked content. + dci_dl_info dci; +}; + +/// List of DL PDCCH allocations within a given slot. +using pdcch_dl_info_list = static_vector; + +/// PDCCH UL allocation. +struct pdcch_ul_information { + /// Context associated with PDCCH allocation. + dci_context_information ctx; + /// UL DCI unpacked content. + dci_ul_info dci; +}; + +/// List of UL PDCCH allocations within a given slot. +using pdcch_ul_info_list = static_vector; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/pdsch_info.h b/include/srsran/scheduler/result/pdsch_info.h new file mode 100644 index 0000000000..9644fbdbf5 --- /dev/null +++ b/include/srsran/scheduler/result/pdsch_info.h @@ -0,0 +1,199 @@ +/* + * + * 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/ran/csi_report/csi_report_data.h" +#include "srsran/ran/pdsch/pdsch_mcs.h" +#include "srsran/ran/precoding/precoding_constants.h" +#include "srsran/ran/slot_pdu_capacity_constants.h" +#include "srsran/scheduler/config/bwp_configuration.h" +#include "srsran/scheduler/harq_id.h" +#include "srsran/scheduler/result/dci_info.h" +#include "srsran/scheduler/result/dmrs_info.h" + +namespace srsran { + +/// The precoding information associated with PDSCH PDUs. +struct pdsch_precoding_info { + /// Precoding Resource Block Group (PRG) information. + using prg_info = csi_report_pmi; + + /// \brief Size in RBs of a precoding resource block group (PRG) to which same precoding and digital beamforming gets + /// applied. Values: {1,...,275}. + unsigned nof_rbs_per_prg; + /// PRG list. + static_vector prg_infos; +}; + +/// PDSCH codeword. +struct pdsch_codeword { + /// Modulation and coding scheme. + sch_mcs_description mcs_descr; + /// \brief MCS index, range {0, ..., 31} (See TS38.214 Section 5.1.3.1). + /// \note Should match value sent in DCI. + sch_mcs_index mcs_index; + /// MCS table (See TS38.214 Section 5.1.3.1). + pdsch_mcs_table mcs_table; + /// Redundancy version index (see TS38.212 Table 5.4.2.1-2, and TS38.214 Table 5.1.2.1-2). + uint8_t rv_index; + /// Transport block size, in bytes (see TS38.214 Section 5.1.3.2). + uint32_t tb_size_bytes; + /// Whether this is the first Tx or retx of the HARQ codeword. + bool new_data; +}; + +/// Transmit power information associated with PDSCH PDU. +struct tx_power_pdsch_information { + /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE when UE derives CSI feedback. See 3GPP TS 38.214, clause 5.2.2.3.1. Values + /// {-8,...,15} dB with 1 dB step size. + /// \remark [Implementation-defined] In case UE is not configured with powerControlOffset we assume it to be 0dB. + int8_t pwr_ctrl_offset{0}; + /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. + /// \remark [Implementation-defined] In case UE is not configured with powerControlOffsetSS we assume it to be 0dB. + int8_t pwr_ctrl_offset_ss{0}; +}; + +/// \brief Information relative to a PDSCH grant in a given slot. +struct pdsch_information { + rnti_t rnti; + const bwp_configuration* bwp_cfg; + const coreset_configuration* coreset_cfg; + vrb_alloc rbs; + ofdm_symbol_range symbols; + static_vector codewords; + dmrs_information dmrs; + /// Parameter n_ID, used for scrambling, as per TS 38.211, Section 7.3.1.1. + unsigned n_id; + /// Number of layers as per TS 38.211, Section 7.3.1.3. Values: {1,...,8}. + unsigned nof_layers; + /// Whether the PDSCH is interleaved via VRB-to-PRB mapping. + bool is_interleaved; + search_space_set_type ss_set_type; + dci_dl_format dci_fmt; + /// HARQ process number as per TS38.212 Section 7.3.1.1. Values: {0,...,15}. + harq_id_t harq_id; + /// Precoding information for the PDSCH. This field is empty in case of 1-antenna port setups. + std::optional precoding; + /// Transmit power information for the PDSCH. + tx_power_pdsch_information tx_pwr_info; +}; + +/// Dummy MAC CE payload. +/// To be replaced by other MAC CE payload when its supported. +using dummy_ce_payload = unsigned; + +/// Timing Advance Command CE payload. +struct ta_cmd_ce_payload { + uint8_t tag_id; + unsigned ta_cmd; +}; + +struct dl_msg_lc_info { + /// Values of LCID for DL-SCH. See TS 38.321, Table 6.2.1-1. + lcid_dl_sch_t lcid; + /// Number of scheduled bytes for this specific logical channel. {0..65535}. + unsigned sched_bytes; + /// Holds payload of CE except UE Contention Resolution Identity. + std::variant ce_payload; +}; + +/// Information relative to the transport blocks scheduled for a given PDSCH. +struct dl_msg_tb_info { + /// List of logical channels to schedule in this TB. + static_vector lc_chs_to_sched; +}; + +using dl_msg_tb_info_list = static_vector; + +/// Dedicated DL Grant for UEs. +struct dl_msg_alloc { + pdsch_information pdsch_cfg; + dl_msg_tb_info_list tb_list; + + /// \brief Information relative to a PDSCH allocation decision that is used for the purpose of logging or + /// tracing, but not passed to the PHY. + struct decision_context { + /// UE index of allocated UE. + du_ue_index_t ue_index; + /// Chosen k1 delay to receive UCI HARQ-ACK. + unsigned k1; + /// Chosen search space id + search_space_id ss_id; + /// Number of times the HARQ process has been retransmitted. + unsigned nof_retxs; + /// Current UE DL buffer occupancy, after this PDSCH grant. + unsigned buffer_occupancy; + /// Offset that the OLLA algorithm applied to the DL MCS candidate to account for channel impairments. + std::optional olla_offset; + } context; +}; + +/// \brief RAR grant composed of subheader as per TS38.321 6.2.2, payload as per TS38.321 6.2.3, +/// with UL grant as per TS38.213, Table 8.2-1. +struct rar_ul_grant { + // MAC subheader. + uint16_t rapid; + + // RAR payload. + uint16_t ta; + rnti_t temp_crnti; + + // UL Grant Payload. + bool freq_hop_flag; + uint8_t time_resource_assignment; + uint16_t freq_resource_assignment; + sch_mcs_index mcs; + int8_t tpc; + bool csi_req; +}; + +/// Stores the information associated with a RAR. +struct rar_information { + pdsch_information pdsch_cfg; + static_vector grants; +}; + +/// Stores the information associated with an SSB. +struct ssb_information { + unsigned ssb_index; + crb_interval crbs; + ofdm_symbol_range symbols; +}; + +/// Stores the information associated with an SIB1 or other SI allocation. +struct sib_information { + enum si_indicator_type { sib1, other_si } si_indicator; + std::optional si_msg_index; + unsigned nof_txs; + pdsch_information pdsch_cfg; +}; + +/// See ORAN WG8, 9.2.3.3.12 - Downlink Broadcast Allocation. +struct dl_broadcast_allocation { + static_vector ssb_info; + static_vector sibs; +}; + +struct paging_ue_info { + /// Type of Paging. RAN initiated or CN initiated. + enum paging_identity_type { ran_ue_paging_identity, cn_ue_paging_identity } paging_type_indicator; + /// Paging identity assigned to UE. Possible values are \c I-RNTI-Value (Bit string of size 40) and \c NG-5G-S-TMSI + /// (Bit string of size 48). See TS 38.331. + uint64_t paging_identity; +}; + +/// Stores the information associated with Paging allocation. +struct dl_paging_allocation { + static_vector paging_ue_list; + pdsch_information pdsch_cfg; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/scheduler_configurator.h b/include/srsran/scheduler/scheduler_configurator.h index 8427b26946..e816f988a6 100644 --- a/include/srsran/scheduler/scheduler_configurator.h +++ b/include/srsran/scheduler/scheduler_configurator.h @@ -36,7 +36,7 @@ #include "srsran/scheduler/config/serving_cell_config.h" #include "srsran/scheduler/config/si_scheduling_config.h" #include "srsran/scheduler/config/slice_rrm_policy_config.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index 0a4afae96c..653cc07777 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -15,233 +15,25 @@ #include "srsran/ran/csi_report/csi_report_data.h" #include "srsran/ran/csi_rs/csi_rs_types.h" #include "srsran/ran/du_types.h" -#include "srsran/ran/logical_channel/lcid.h" #include "srsran/ran/logical_channel/lcid_dl_sch.h" #include "srsran/ran/pci.h" -#include "srsran/ran/pdsch/pdsch_mcs.h" #include "srsran/ran/prach/prach_format_type.h" -#include "srsran/ran/precoding/precoding_constants.h" #include "srsran/ran/pucch/pucch_mapping.h" #include "srsran/ran/pusch/pusch_mcs.h" #include "srsran/ran/resource_allocation/ofdm_symbol_range.h" #include "srsran/ran/rnti.h" -#include "srsran/ran/sch/modulation_scheme.h" #include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/slot_point.h" #include "srsran/ran/srs/srs_configuration.h" -#include "srsran/ran/subcarrier_spacing.h" #include "srsran/ran/uci/uci_configuration.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/config/dmrs.h" -#include "srsran/scheduler/harq_id.h" -#include "srsran/scheduler/sched_consts.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/pdcch_info.h" +#include "srsran/scheduler/result/pdsch_info.h" #include "srsran/scheduler/scheduler_pucch_format.h" #include "srsran/scheduler/vrb_alloc.h" -#include namespace srsran { -/// The precoding information associated with PDCCH PDUs. -struct pdcch_precoding_info {}; - -/// The precoding information associated with PDSCH PDUs. -struct pdsch_precoding_info { - /// Precoding Resource Block Group (PRG) information. - using prg_info = csi_report_pmi; - - /// \brief Size in RBs of a precoding resource block group (PRG) to which same precoding and digital beamforming gets - /// applied. Values: {1,...,275}. - unsigned nof_rbs_per_prg; - /// PRG list. - static_vector prg_infos; -}; - -/// Transmit power information associated with PDCCH PDU. -struct tx_power_pdcch_information { - /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. - /// \remark If the UE has not been provided dedicated higher layer parameters, the UE may assume that the ratio of - /// PDCCH DMRS EPRE to SSS EPRE is within -8 dB and 8 dB when the UE monitors PDCCHs for a DCI format 1_0 with CRC - /// scrambled by SI-RNTI, P-RNTI, or RA-RNTI. See TS 38.213, clause 4.1. - /// \remark [Implementation-defined] In case UE is not configured with powerControlOffsetSS we assume it to be 0dB. - int8_t pwr_ctrl_offset_ss{0}; -}; - -struct dmrs_information { - /// Bitmap of DM-RS position symbols. - dmrs_symbol_mask dmrs_symb_pos; - dmrs_config_type config_type; - /// \brief DMRS-Scrambling-ID (see TS 38.211 sec 7.4.1.1.1) as provided by parameter \f$N^{n_{SCID}}_{ID}\f$. - /// Values: (0..65535). - unsigned dmrs_scrambling_id; - /// PHY shall disregard this parameter if lowPaprDmrs=0. - unsigned dmrs_scrambling_id_complement; - /// False means that dmrs_scrambling_id == dmrs_scrambling_id_complement. - bool low_papr_dmrs; - /// \brief DMRS sequence initialization (see TS 38.211 sec 7.4.1.1.2), as provided by parameter n_{SCID}. - /// Values: false -> 0, true -> 1. - bool n_scid; - /// Values: (1..3). - uint8_t num_dmrs_cdm_grps_no_data; - /// \brief Bitmap of antenna ports. Bit 0 corresponds to antenna port 1000 and bit 11 to antenna port 1011, and - /// each bit=1 mean DM-RS port used. - bounded_bitset<12> dmrs_ports; -}; - -struct dci_context_information { - const bwp_configuration* bwp_cfg; - const coreset_configuration* coreset_cfg; - /// RNTI used to identify the destination of this DCI (e.g. UE, RA-RNTI, SI, Paging). - rnti_t rnti; - /// Parameter \f$n_{ID}\f$ used for PDCCH Data scrambling as per 3GPP TS 38.211 [2], sec 7.3.2.3. Values: (0..65535). - /// For a UE-specific search space it equals the higherlayer parameter PDCCH-DMRS-Scrambling-ID if configured, - /// otherwise it should be set to the phy cell ID. - unsigned n_id_pdcch_data; - /// Parameter \f$n_{RNTI}\f$ used for PDCCH data scrambling, as per 3GPP TS 38.211 [2], sec 7.3.2.3. - /// Values: (0..65535). For a UE-specific search space where PDCCH-DMRSScrambling-ID is configured, this param - /// equals the CRNTI. Otherwise, it should be set to 0. - unsigned n_rnti_pdcch_data; - /// CCE position of the allocated PDCCH. - cce_position cces; - /// Starting symbol of the Search Space. - unsigned starting_symbol; - /// Precoding info used for this DCI. This field is empty in case of 1 antenna port. - std::optional precoding_info; - /// Transmission power information used for this DCI. - tx_power_pdcch_information tx_pwr; - /// Parameter \f$N_{ID}\f$ used for PDCCH DMRS scrambling as per TS38.211, 7.4.1.3.1. Values: {0, ..., 65535}. - unsigned n_id_pdcch_dmrs; - - /// \brief Information relative to a PDCCH allocation decision that is used for the purpose of logging or - /// tracing, but not passed to the PHY. - struct decision_context { - /// Chosen SearchSpace-Id. - search_space_id ss_id; - /// DCI format string. - const char* dci_format; - /// Number of slots the UE is expected to wait before transmitting a DL HARQ-ACK, upon a PDSCH reception. - std::optional harq_feedback_timing; - } context; -}; - -/// PDCCH DL allocation. -struct pdcch_dl_information { - /// Context associated with PDCCH allocation. - dci_context_information ctx; - /// DL DCI unpacked content. - dci_dl_info dci; -}; - -/// PDCCH UL allocation. -struct pdcch_ul_information { - /// Context associated with PDCCH allocation. - dci_context_information ctx; - /// UL DCI unpacked content. - dci_ul_info dci; -}; - -/// PDSCH codeword. -struct pdsch_codeword { - /// Modulation and coding scheme. - sch_mcs_description mcs_descr; - /// \brief MCS index, range {0, ..., 31} (See TS38.214 Section 5.1.3.1). - /// \note Should match value sent in DCI. - sch_mcs_index mcs_index; - /// MCS table (See TS38.214 Section 5.1.3.1). - pdsch_mcs_table mcs_table; - /// Redundancy version index (see TS38.212 Table 5.4.2.1-2, and TS38.214 Table 5.1.2.1-2). - uint8_t rv_index; - /// Transport block size, in bytes (see TS38.214 Section 5.1.3.2). - uint32_t tb_size_bytes; - /// Whether this is the first Tx or retx of the HARQ codeword. - bool new_data; -}; - -/// Transmit power information associated with PDSCH PDU. -struct tx_power_pdsch_information { - /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE when UE derives CSI feedback. See 3GPP TS 38.214, clause 5.2.2.3.1. Values - /// {-8,...,15} dB with 1 dB step size. - /// \remark [Implementation-defined] In case UE is not configured with powerControlOffset we assume it to be 0dB. - int8_t pwr_ctrl_offset{0}; - /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. See 3GPP TS 38.214, clause 5.2.2.3.1. Values {-3, 0, 3, 6} dB. - /// \remark [Implementation-defined] In case UE is not configured with powerControlOffsetSS we assume it to be 0dB. - int8_t pwr_ctrl_offset_ss{0}; -}; - -/// \brief Information relative to a PDSCH grant in a given slot. -struct pdsch_information { - rnti_t rnti; - const bwp_configuration* bwp_cfg; - const coreset_configuration* coreset_cfg; - vrb_alloc rbs; - ofdm_symbol_range symbols; - static_vector codewords; - dmrs_information dmrs; - /// Parameter n_ID, used for scrambling, as per TS 38.211, Section 7.3.1.1. - unsigned n_id; - /// Number of layers as per TS 38.211, Section 7.3.1.3. Values: {1,...,8}. - unsigned nof_layers; - /// Whether the PDSCH is interleaved via VRB-to-PRB mapping. - bool is_interleaved; - search_space_set_type ss_set_type; - dci_dl_format dci_fmt; - /// HARQ process number as per TS38.212 Section 7.3.1.1. Values: {0,...,15}. - harq_id_t harq_id; - /// Precoding information for the PDSCH. This field is empty in case of 1-antenna port setups. - std::optional precoding; - /// Transmit power information for the PDSCH. - tx_power_pdsch_information tx_pwr_info; -}; - -/// Dummy MAC CE payload. -/// To be replaced by other MAC CE payload when its supported. -using dummy_ce_payload = unsigned; - -/// Timing Advance Command CE payload. -struct ta_cmd_ce_payload { - uint8_t tag_id; - unsigned ta_cmd; -}; - -struct dl_msg_lc_info { - /// Values of LCID for DL-SCH. See TS 38.321, Table 6.2.1-1. - lcid_dl_sch_t lcid; - /// Number of scheduled bytes for this specific logical channel. {0..65535}. - unsigned sched_bytes; - /// Holds payload of CE except UE Contention Resolution Identity. - std::variant ce_payload; -}; - -struct dl_msg_tb_info { - /// List of logical channels to schedule in this TB. - static_vector lc_chs_to_sched; -}; - -using dl_msg_tb_info_list = static_vector; - -/// Dedicated DL Grant for UEs. -struct dl_msg_alloc { - pdsch_information pdsch_cfg; - dl_msg_tb_info_list tb_list; - - /// \brief Information relative to a PDSCH allocation decision that is used for the purpose of logging or - /// tracing, but not passed to the PHY. - struct decision_context { - /// UE index of allocated UE. - du_ue_index_t ue_index; - /// Chosen k1 delay to receive UCI HARQ-ACK. - unsigned k1; - /// Chosen search space id - search_space_id ss_id; - /// Number of times the HARQ process has been retransmitted. - unsigned nof_retxs; - /// Current UE DL buffer occupancy, after this PDSCH grant. - unsigned buffer_occupancy; - /// Offset that the OLLA algorithm applied to the DL MCS candidate to account for channel impairments. - std::optional olla_offset; - } context; -}; - struct pusch_information { rnti_t rnti; const bwp_configuration* bwp_cfg; @@ -327,66 +119,6 @@ struct uci_info { alpha_scaling_opt alpha; }; -/// \brief RAR grant composed of subheader as per TS38.321 6.2.2, payload as per TS38.321 6.2.3, -/// with UL grant as per TS38.213, Table 8.2-1. -struct rar_ul_grant { - // MAC subheader. - uint16_t rapid; - - // RAR payload. - uint16_t ta; - rnti_t temp_crnti; - - // UL Grant Payload. - bool freq_hop_flag; - uint8_t time_resource_assignment; - uint16_t freq_resource_assignment; - sch_mcs_index mcs; - int8_t tpc; - bool csi_req; -}; - -/// Stores the information associated with a RAR. -struct rar_information { - pdsch_information pdsch_cfg; - static_vector grants; -}; - -/// Stores the information associated with an SSB. -struct ssb_information { - unsigned ssb_index; - crb_interval crbs; - ofdm_symbol_range symbols; -}; - -/// Stores the information associated with an SIB1 or other SI allocation. -struct sib_information { - enum si_indicator_type { sib1, other_si } si_indicator; - std::optional si_msg_index; - unsigned nof_txs; - pdsch_information pdsch_cfg; -}; - -/// See ORAN WG8, 9.2.3.3.12 - Downlink Broadcast Allocation. -struct dl_broadcast_allocation { - static_vector ssb_info; - static_vector sibs; -}; - -struct paging_ue_info { - /// Type of Paging. RAN initiated or CN initiated. - enum paging_identity_type { ran_ue_paging_identity, cn_ue_paging_identity } paging_type_indicator; - /// Paging identity assigned to UE. Possible values are \c I-RNTI-Value (Bit string of size 40) and \c NG-5G-S-TMSI - /// (Bit string of size 48). See TS 38.331. - uint64_t paging_identity; -}; - -/// Stores the information associated with Paging allocation. -struct dl_paging_allocation { - static_vector paging_ue_list; - pdsch_information pdsch_cfg; -}; - /// Stores the information associated with a CSI-RS signalling. struct csi_rs_info { const bwp_configuration* bwp_cfg; @@ -419,10 +151,10 @@ struct dl_sched_result { unsigned nof_dl_symbols; /// Allocated DL PDCCHs. Includes both SIB, RAR and Data PDCCHs. - static_vector dl_pdcchs; + pdcch_dl_info_list dl_pdcchs; /// Allocated UL PDCCHs. - static_vector ul_pdcchs; + pdcch_ul_info_list ul_pdcchs; /// Allocation of SSB and SIBs. dl_broadcast_allocation bc; diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 15663657e3..989ff6d0f4 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -20,7 +20,8 @@ #include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/slot_point.h" #include "srsran/scheduler/harq_id.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" +#include "srsran/scheduler/vrb_alloc.h" #include "srsran/srslog/srslog.h" namespace srsran { diff --git a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.h b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.h index d0c1cd5345..2bbbc0b158 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.h +++ b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator_impl.h @@ -12,7 +12,7 @@ #include "../config/ue_configuration.h" #include "pdcch_resource_allocator.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { diff --git a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h index 8e2a9b7e77..f15394def6 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h +++ b/lib/scheduler/pdcch_scheduling/pdcch_slot_resource_allocator.h @@ -12,8 +12,7 @@ #include "../support/pdcch/pdcch_mapping.h" #include "srsran/ran/pdcch/pdcch_candidates.h" -#include "srsran/scheduler/scheduler_dci.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pdcch_info.h" namespace srsran { @@ -73,4 +72,4 @@ class pdcch_slot_allocator std::vector dfs_tree, saved_dfs_tree; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h index 9eb725b1e4..79115d31b6 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h @@ -14,7 +14,7 @@ #include "../config/ue_configuration.h" #include "pucch_allocator.h" #include "pucch_resource_manager.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" #include namespace srsran { diff --git a/lib/scheduler/support/bwp_helpers.h b/lib/scheduler/support/bwp_helpers.h index 93522da377..169b5fe668 100644 --- a/lib/scheduler/support/bwp_helpers.h +++ b/lib/scheduler/support/bwp_helpers.h @@ -14,7 +14,7 @@ #include "srsran/ran/pdcch/coreset.h" #include "srsran/ran/pdcch/search_space.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" #include "srsran/support/error_handling.h" namespace srsran { diff --git a/lib/scheduler/support/config_helpers.h b/lib/scheduler/support/config_helpers.h index 7526994016..e1b92b30a1 100644 --- a/lib/scheduler/support/config_helpers.h +++ b/lib/scheduler/support/config_helpers.h @@ -11,7 +11,7 @@ #pragma once #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { diff --git a/lib/scheduler/support/dci_builder.h b/lib/scheduler/support/dci_builder.h index ee65905003..a4fe5b2f5c 100644 --- a/lib/scheduler/support/dci_builder.h +++ b/lib/scheduler/support/dci_builder.h @@ -13,7 +13,7 @@ #include "srsran/ran/pdcch/search_space.h" #include "srsran/ran/resource_allocation/resource_allocation_frequency.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { diff --git a/lib/scheduler/support/pdcch/search_space_helper.h b/lib/scheduler/support/pdcch/search_space_helper.h index 99e205cc87..a578ac4b06 100644 --- a/lib/scheduler/support/pdcch/search_space_helper.h +++ b/lib/scheduler/support/pdcch/search_space_helper.h @@ -11,7 +11,7 @@ #pragma once #include "srsran/ran/pdcch/search_space.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { namespace pdcch_helper { diff --git a/lib/scheduler/support/pdsch/pdsch_resource_allocation.h b/lib/scheduler/support/pdsch/pdsch_resource_allocation.h index 65ace4c119..ce81689d92 100644 --- a/lib/scheduler/support/pdsch/pdsch_resource_allocation.h +++ b/lib/scheduler/support/pdsch/pdsch_resource_allocation.h @@ -12,7 +12,7 @@ #include "srsran/ran/pdcch/search_space.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { namespace pdsch_helper { diff --git a/lib/scheduler/support/pusch/pusch_resource_allocation.h b/lib/scheduler/support/pusch/pusch_resource_allocation.h index 8b38f7a734..9b341d7447 100644 --- a/lib/scheduler/support/pusch/pusch_resource_allocation.h +++ b/lib/scheduler/support/pusch/pusch_resource_allocation.h @@ -12,7 +12,7 @@ #include "srsran/ran/pdcch/search_space.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" namespace srsran { namespace pusch_helper { diff --git a/lib/scheduler/support/rb_helper.h b/lib/scheduler/support/rb_helper.h index ecbd54c199..5b0cc283b3 100644 --- a/lib/scheduler/support/rb_helper.h +++ b/lib/scheduler/support/rb_helper.h @@ -10,10 +10,10 @@ #pragma once +#include "srsran/ran/pdcch/dci_format.h" #include "srsran/ran/pdcch/search_space.h" #include "srsran/ran/rnti.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/scheduler_dci.h" #include "srsran/scheduler/vrb_alloc.h" #include "srsran/support/error_handling.h" diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index b72d6c7cda..2e22c030a9 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -15,9 +15,8 @@ #include "../ue_context/ue_drx_controller.h" #include "ue_pdsch_alloc_param_candidate_searcher.h" #include "ue_pusch_alloc_param_candidate_searcher.h" -#include "srsran/ran/pdcch/coreset.h" #include "srsran/ran/transform_precoding/transform_precoding_helpers.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" #include "srsran/support/error_handling.h" using namespace srsran; diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index 57aba7059a..62aec773f6 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -18,7 +18,7 @@ #include "srsran/ran/duplex_mode.h" #include "srsran/ran/pdcch/search_space.h" #include "srsran/scheduler/config/logical_channel_config_factory.h" -#include "srsran/scheduler/scheduler_dci.h" +#include "srsran/scheduler/result/dci_info.h" #include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/test_utils.h" #include From e7d6b46f824bc53299bc0491e98325c9c64a8795 Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 17:09:58 +0100 Subject: [PATCH 191/227] sched: move UL result types out of scheduler_slot_handler.h --- .../srsran/fapi_adaptor/mac/messages/pdcch.h | 2 +- .../fapi_adaptor/precoding_matrix_mapper.h | 1 + include/srsran/mac/mac_cell_result.h | 8 +- include/srsran/scheduler/result/csi_rs_info.h | 45 +++ include/srsran/scheduler/result/pdsch_info.h | 4 +- include/srsran/scheduler/result/prach_info.h | 42 +++ include/srsran/scheduler/result/pucch_info.h | 48 +++ include/srsran/scheduler/result/pusch_info.h | 128 ++++++++ .../srsran/scheduler/result/sched_result.h | 71 +++++ include/srsran/scheduler/result/srs_info.h | 68 ++++ .../srsran/scheduler/scheduler_slot_handler.h | 298 +----------------- .../test_mode/mac_test_mode_adapter.cpp | 1 + .../du_high/test_mode/mac_test_mode_adapter.h | 2 + .../test_mode/mac_test_mode_helpers.cpp | 2 + .../du_high/test_mode/mac_test_mode_helpers.h | 7 +- .../mac/mac_to_fapi_translator.cpp | 1 + lib/fapi_adaptor/mac/mac_to_fapi_translator.h | 1 + lib/fapi_adaptor/mac/messages/pdsch.cpp | 1 + lib/fapi_adaptor/mac/messages/prach.cpp | 2 +- lib/fapi_adaptor/mac/messages/pucch.cpp | 2 +- lib/fapi_adaptor/mac/messages/pusch.cpp | 2 +- lib/fapi_adaptor/mac/messages/srs.cpp | 2 +- lib/mac/mac_dl/dl_sch_pdu_assembler.cpp | 2 +- lib/mac/mac_dl/dl_sch_pdu_assembler.h | 3 + lib/mac/mac_dl/mac_cell_processor.cpp | 1 + lib/mac/mac_dl/paging_pdu_assembler.cpp | 1 + lib/mac/mac_dl/paging_pdu_assembler.h | 3 +- lib/mac/mac_dl/rar_pdu_assembler.cpp | 1 + lib/mac/mac_dl/rar_pdu_assembler.h | 3 +- lib/mac/mac_dl/ssb_assembler.cpp | 2 +- .../mac_sched/srsran_scheduler_adapter.cpp | 1 + lib/mac/mac_sched/uci_cell_decoder.cpp | 2 + lib/mac/mac_sched/uci_cell_decoder.h | 4 +- lib/scheduler/cell/cell_harq_manager.cpp | 3 +- lib/scheduler/cell/resource_grid.h | 4 +- .../common_scheduling/paging_scheduler.h | 4 + .../common_scheduling/ra_scheduler.h | 2 + .../logging/scheduler_metric_handler.cpp | 1 + .../logging/scheduler_result_logger.cpp | 1 + .../logging/scheduler_result_logger.h | 4 +- lib/scheduler/srs/srs_scheduler_impl.h | 1 + lib/scheduler/support/dmrs_helpers.h | 2 +- lib/scheduler/support/mcs_tbs_calculator.h | 2 +- lib/scheduler/support/sch_pdu_builder.h | 3 +- .../ue_context/dl_logical_channel_manager.h | 3 +- .../ue_context/ue_channel_state_manager.h | 2 +- .../scheduler_multi_ue_benchmark.cpp | 1 + .../scheduler/scheduler_no_ues_benchmark.cpp | 1 + .../mac/dummy_mac_result_notifier.h | 1 + tests/test_doubles/mac/mac_test_messages.cpp | 3 +- tests/test_doubles/mac/mac_test_messages.h | 2 + .../scheduler/scheduler_result_test.h | 2 +- .../fapi_adaptor/mac/messages/helpers.h | 1 + tests/unittests/mac/mac_test_helpers.h | 1 + .../scheduler/cell/cell_harq_manager_test.cpp | 1 + .../scheduler_metrics_handler_test.cpp | 1 + .../test_utils/indication_generators.cpp | 2 +- 57 files changed, 484 insertions(+), 325 deletions(-) create mode 100644 include/srsran/scheduler/result/csi_rs_info.h create mode 100644 include/srsran/scheduler/result/prach_info.h create mode 100644 include/srsran/scheduler/result/pucch_info.h create mode 100644 include/srsran/scheduler/result/pusch_info.h create mode 100644 include/srsran/scheduler/result/sched_result.h create mode 100644 include/srsran/scheduler/result/srs_info.h diff --git a/include/srsran/fapi_adaptor/mac/messages/pdcch.h b/include/srsran/fapi_adaptor/mac/messages/pdcch.h index 869d79588b..c6bcdc4248 100644 --- a/include/srsran/fapi_adaptor/mac/messages/pdcch.h +++ b/include/srsran/fapi_adaptor/mac/messages/pdcch.h @@ -11,7 +11,7 @@ #pragma once #include "srsran/fapi/message_builders.h" -#include "srsran/mac/mac_cell_result.h" +#include "srsran/scheduler/result/pdcch_info.h" namespace srsran { namespace fapi_adaptor { diff --git a/include/srsran/fapi_adaptor/precoding_matrix_mapper.h b/include/srsran/fapi_adaptor/precoding_matrix_mapper.h index 4fec8b9ffb..5a407195b4 100644 --- a/include/srsran/fapi_adaptor/precoding_matrix_mapper.h +++ b/include/srsran/fapi_adaptor/precoding_matrix_mapper.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/mac/mac_cell_result.h" +#include "srsran/ran/csi_report/csi_report_data.h" #include "srsran/srslog/logger.h" #include diff --git a/include/srsran/mac/mac_cell_result.h b/include/srsran/mac/mac_cell_result.h index 759826428b..3cef60ee64 100644 --- a/include/srsran/mac/mac_cell_result.h +++ b/include/srsran/mac/mac_cell_result.h @@ -2,16 +2,20 @@ #pragma once #include "srsran/adt/byte_buffer.h" -#include "srsran/adt/byte_buffer_chain.h" #include "srsran/adt/static_vector.h" +#include "srsran/ran/du_types.h" +#include "srsran/ran/pci.h" #include "srsran/ran/pdcch/dci_packing.h" +#include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/slot_point.h" #include "srsran/ran/ssb_properties.h" -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/shared_transport_block.h" namespace srsran { +struct dl_sched_result; +struct ul_sched_result; + /// \brief Describes part of the parameters that are encoded in the MIB payload as per TS38.331 Section 6.2.2 - MIB. struct ssb_mib_data_pdu { /// Symbol position of the first DM-RS. diff --git a/include/srsran/scheduler/result/csi_rs_info.h b/include/srsran/scheduler/result/csi_rs_info.h new file mode 100644 index 0000000000..e8b3dad742 --- /dev/null +++ b/include/srsran/scheduler/result/csi_rs_info.h @@ -0,0 +1,45 @@ +/* + * + * 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/ran/csi_rs/csi_rs_types.h" +#include "srsran/scheduler/config/bwp_configuration.h" + +namespace srsran { + +/// Stores the information associated with a CSI-RS signalling. +struct csi_rs_info { + const bwp_configuration* bwp_cfg; + /// Range of RBs where this CSI resource starts and ends, with relation to CRB#0. Only multiples of 4 are allowed. + crb_interval crbs; + csi_rs_type type; + /// \brief Row entry into the CSI Resource location table, as per 3GP TS 38.211, sec 7.4.1.5.3 and table 7.4.1.5.3-1. + /// Values: {1,...,18}. + uint8_t row; + /// \brief Bitmap defining the frequencyDomainAllocation as per 3GPP TS 38.211, sec 7.4.1.5.3 and 3GPP TS 38.331 + /// "CSIResource Mapping". + bounded_bitset<12, false> freq_domain; + /// \brief The time domain location l0 and firstOFDMSymbolInTimeDomain as per 3GPP TS 38.211, sec 7.4.1.5.3. + /// Values: {0,...,13}. + uint8_t symbol0; + /// \brief The time domain location l1 and firstOFDMSymbolInTimeDomain2 as per 3GPP TS 38.211, sec 7.4.1.5.3. + uint8_t symbol1; + csi_rs_cdm_type cdm_type; + csi_rs_freq_density_type freq_density; + /// \brief ScramblingID of the CSI-RS as per 3GPP TS 38.214, sec 5.2.2.3.1. Values: {0,...,1023}. + uint16_t scrambling_id; + /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE as per 3GPP TS 38.214, clause 5.2.2.3.1. Values: {-8,...,15}. + int8_t power_ctrl_offset; + /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. Values: {-3,0,3,6}. + int8_t power_ctrl_offset_ss; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/pdsch_info.h b/include/srsran/scheduler/result/pdsch_info.h index 9644fbdbf5..488da332a1 100644 --- a/include/srsran/scheduler/result/pdsch_info.h +++ b/include/srsran/scheduler/result/pdsch_info.h @@ -11,12 +11,14 @@ #pragma once #include "srsran/ran/csi_report/csi_report_data.h" +#include "srsran/ran/logical_channel/lcid_dl_sch.h" +#include "srsran/ran/pdcch/dci_format.h" #include "srsran/ran/pdsch/pdsch_mcs.h" #include "srsran/ran/precoding/precoding_constants.h" +#include "srsran/ran/rnti.h" #include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/scheduler/config/bwp_configuration.h" #include "srsran/scheduler/harq_id.h" -#include "srsran/scheduler/result/dci_info.h" #include "srsran/scheduler/result/dmrs_info.h" namespace srsran { diff --git a/include/srsran/scheduler/result/prach_info.h b/include/srsran/scheduler/result/prach_info.h new file mode 100644 index 0000000000..0d220fab7d --- /dev/null +++ b/include/srsran/scheduler/result/prach_info.h @@ -0,0 +1,42 @@ +/* + * + * 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/ran/pci.h" +#include "srsran/ran/prach/prach_format_type.h" + +namespace srsran { + +/// Information relative to a PRACH opportunity. +struct prach_occasion_info { + /// Physical Cell identifier. + pci_t pci; + /// Number of time-domain PRACH occasions (\f$N^{RAslot}_t\f$), as per TS38.211 Tables 6.3.3.2-[2-4]. + uint8_t nof_prach_occasions; + /// RACH format information for the PRACH occasions. + prach_format_type format; + /// Frequency domain occasion index \f$n \in \{0,...,M-1\}\f$, where \f$M\f$ is the higher-layer parameter msg1-FDM, + /// which can take the values \f$\{1,2,4,8\}\f$. See TS38.211, sec 6.3.3.2. Possible values {0,...,7}. + uint8_t index_fd_ra; + /// Starting symbol for the first PRACH TD occasion. + /// \remark See TS38.211, sec 6.3.3.2 and Tables 6.3.3.2-2 and 6.3.3.2-4. Possible values: {0,...,13}. + uint8_t start_symbol; + /// N-CS configuration as per TS38.211, Table 6.3.3.1-5. Possible values: {0,...,419}. + uint16_t nof_cs; + /// Number of frequency domain occasions starting with index_fd_ra. Possible values: {1,...,8}. + uint8_t nof_fd_ra; + /// Start of preamble logical index to monitor the PRACH occasions in this slot. Values: {0,...63}. + uint8_t start_preamble_index; + /// Number of preamble logical indices. Values: {1,...,64}. + uint8_t nof_preamble_indexes; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/pucch_info.h b/include/srsran/scheduler/result/pucch_info.h new file mode 100644 index 0000000000..d228bb117c --- /dev/null +++ b/include/srsran/scheduler/result/pucch_info.h @@ -0,0 +1,48 @@ +/* + * + * 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/ran/csi_report/csi_report_configuration.h" +#include "srsran/ran/pucch/pucch_mapping.h" +#include "srsran/scheduler/scheduler_pucch_format.h" + +namespace srsran { + +/// Info about PUCCH used resource. +struct pucch_info { + /// This information only is used by the scheduler and not passed to the PHY. + struct context { + /// Identifier of the PUCCH PDU within the list of PUCCH PDUs for a given slot. The ID is only meaningful for a + /// given UE; i.e., different UEs can reuse the same ID, but a UE cannot reuse the same ID for different PDUs. + unsigned id = MAX_PUCCH_PDUS_PER_SLOT; + /// Determines whether the PUCCH PDU uses common resources. + bool is_common = false; + }; + + rnti_t crnti; + const bwp_configuration* bwp_cfg; + pucch_format format; + /// PRBs and symbols for this PUCCH resource. + pucch_resources resources; + union { + pucch_format_0 format_0; + pucch_format_1 format_1; + pucch_format_2 format_2; + pucch_format_3 format_3; + pucch_format_4 format_4; + }; + /// In case the PUCCH will contain CSI bits, this struct contains information how those bits are to be decoded. + std::optional csi_rep_cfg; + + context pdu_context; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/pusch_info.h b/include/srsran/scheduler/result/pusch_info.h new file mode 100644 index 0000000000..5e07d98bca --- /dev/null +++ b/include/srsran/scheduler/result/pusch_info.h @@ -0,0 +1,128 @@ +/* + * + * 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/ran/csi_report/csi_report_configuration.h" +#include "srsran/ran/pusch/pusch_mcs.h" +#include "srsran/ran/uci/uci_configuration.h" +#include "srsran/scheduler/result/dmrs_info.h" +#include "srsran/scheduler/vrb_alloc.h" + +namespace srsran { + +/// Information relative to a PUSCH allocation. +struct pusch_information { + rnti_t rnti; + const bwp_configuration* bwp_cfg; + vrb_alloc rbs; + ofdm_symbol_range symbols; + /// \brief For resource allocation type 1, it indicates if intra-slot frequency hopping is enabled, as per TS38.212 + /// Section 7.3.1.1. + bool intra_slot_freq_hopping; + /// \brief Index of the first PRB after intra-slot frequency hopping, as indicated by the value of \f$RB_{start}\f$ + /// for i=1, as per TS38.214, Section 6.3. Valid when intra_slot_freq_hopping is enabled. Values: {0,...274}. + uint16_t pusch_second_hop_prb; + /// \brief The uplink Tx Direct Current location for the carrier. Only values in the value range of this field + /// between 0 and 3299, which indicate the subcarrier index within the carrier corresponding to the numerology of the + /// corresponding uplink BWP and value 3300, which indicates "Outside the carrier" and value 3301, which indicates + /// "Undetermined position within the carrier" are used. + uint16_t tx_direct_current_location; + /// Indicates whether there is 7.5 kHz shift or not. + bool ul_freq_shift_7p5khz; + /// Modulation and coding scheme. + sch_mcs_description mcs_descr; + /// \brief MCS index, range {0, ..., 31} (See TS38.214 Section 5.1.4.1). + /// \note Should match value sent in DCI. + sch_mcs_index mcs_index; + /// MCS table (See TS38.214 Section 6.1.4.1). + pusch_mcs_table mcs_table; + /// Indicates if transform precoding is enabled or disabled (see TS 38.214, Section 6.1.4.1). + bool transform_precoding; + /// Parameter \f$n_{ID}\f$ as per TS38.211 Section 6.3.1.1. Values: {0,...,1023}. + uint16_t n_id; + /// Number of layers as per TS38.211, Section 6.3.1.3. + unsigned nof_layers; + /// DMRS configuration as per TS38.211 Section 6.4.1.1. + dmrs_information dmrs; + /// \brief PUSCH DMRS ID \f$n_{ID}^{RS}\f$ as per TS38.211 Section 6.4.1.1.1.2. This field is only valid when + /// transform_precoding is enabled. Values: {0,...,1007} (Rel-15), {0,...,65535} (Rel-16). + uint16_t pusch_dmrs_id; + /// \brief PUSCH DMRS hopping mode as per TS38.211, Section 6.4.1.1.1.2. It is only valid when the transform + /// precoding for PUSCH is enabled. + enum class dmrs_hopping_mode { no_hopping, group_hopping, sequence_hopping } dmrs_hopping_mode; + /// Redundancy version index (see TS38.214 Table 6.1.4). Values: {0,...,3}. + uint8_t rv_index; + /// HARQ process number as per TS38.212 Section 6.3.1.1. Values: {0,...,15}. + uint8_t harq_id; + /// \brief Signals whether the PUSCH PDU corresponds to an initial transmission or a retransmission of a MAC PDU for + /// this HARQ process ID for this TB. Note: Unlike NDI, new_data does not toggle to indicate new transmission, + /// but is set to 1. + bool new_data; + /// Transport block size in bytes. + uint32_t tb_size_bytes; + /// \brief Number of CBs in the TB (could be more than the number of CBs in this PUSCH transmission). Should be set + /// to zero in any of the following conditions: 1) CBG is not supported or requested 2) newData=1 (new transmission) + /// 3) tbSize=0. + uint16_t num_cb; +}; + +struct uci_info { + /// Contains the HARQ-ACK information for UCI on PUSCH. + struct harq_info { + /// Number of bits of ACK to be reported. + uint16_t harq_ack_nof_bits = 0; + /// \f$\beta^{HARQ-ACK}_{offset}\f$ parameter, as per Section 9.3, TS 38.213. The default value is defined in \c + /// BetaOffsets, TS 38.331. + uint8_t beta_offset_harq_ack = 11; + }; + + /// Contains the CSI part 1 and part 2 information for UCI on PUSCH. + struct csi_info { + /// Contains information how the CSI bits are to be decoded. + csi_report_configuration csi_rep_cfg; + /// Number of bits of CSI Part 1 to be reported. + uint16_t csi_part1_nof_bits = 0; + /// \f$\beta^{CSI-1}_{offset}\f$ parameter, as per Section 9.3, TS 38.213. The default value is defined in \c + /// BetaOffsets, TS 38.331. + uint8_t beta_offset_csi_1 = 13; + /// \f$\beta^{CSI-2}_{offset}\f$ parameter, as per Section 9.3, TS 38.213. + /// If set, the CSI report includes CSI Part 2. + std::optional beta_offset_csi_2; + }; + + std::optional harq; + std::optional csi; + /// \f$\alpha\f$ parameter, as per Section 6.3.2.4.1.1-3, TS 38.212. + alpha_scaling_opt alpha; +}; + +/// Information related to a scheduler UL allocation, which includes PUSCH and may include UCI. +struct ul_sched_info { + pusch_information pusch_cfg; + std::optional uci; + + /// \brief Information relative to a PDSCH allocation decision that is used for the purpose of logging or + /// tracing, but not passed to the PHY. + struct decision_context { + du_ue_index_t ue_index; + search_space_id ss_id; + /// Chosen k2 delay between UL PDCCH and PUSCH. + unsigned k2; + /// Number of times the HARQ process has been retransmitted. + unsigned nof_retxs; + /// Delay between PDSCH message with RAR and its corresponding PUSCH. + std::optional msg3_delay; + /// Offset that the OLLA algorithm applied to derive the UL MCS. + std::optional olla_offset; + } context; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/sched_result.h b/include/srsran/scheduler/result/sched_result.h new file mode 100644 index 0000000000..34d6cdc6a0 --- /dev/null +++ b/include/srsran/scheduler/result/sched_result.h @@ -0,0 +1,71 @@ +/* + * + * 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/scheduler/result/csi_rs_info.h" +#include "srsran/scheduler/result/pdcch_info.h" +#include "srsran/scheduler/result/pdsch_info.h" +#include "srsran/scheduler/result/prach_info.h" +#include "srsran/scheduler/result/pucch_info.h" +#include "srsran/scheduler/result/pusch_info.h" +#include "srsran/scheduler/result/srs_info.h" + +namespace srsran { + +/// Scheduler decision made for DL in a given slot. +struct dl_sched_result { + /// Number of DL symbols active for this slot. + unsigned nof_dl_symbols; + + /// Allocated DL PDCCHs. Includes both SIB, RAR and Data PDCCHs. + pdcch_dl_info_list dl_pdcchs; + + /// Allocated UL PDCCHs. + pdcch_ul_info_list ul_pdcchs; + + /// Allocation of SSB and SIBs. + dl_broadcast_allocation bc; + + /// Allocation of dedicated RARs. + static_vector rar_grants; + + /// Allocation of Paging messages. + static_vector paging_grants; + + /// Allocation of dedicated UE messages. + static_vector ue_grants; + + /// Allocation of CSI-RS messages. + static_vector csi_rs; +}; + +/// Scheduler decision made for UL in a given slot. +struct ul_sched_result { + /// Number of UL symbols active for this slot. + unsigned nof_ul_symbols; + /// PUSCH grants allocated in the current slot. + static_vector puschs; + /// PRACH occasions within the given slot. + static_vector prachs; + /// PUCCH grants allocated in the current slot. + static_vector pucchs; + /// SRS grants allocated in the current slot. + static_vector srss; +}; + +/// Scheduler decision made for DL and UL in a given slot. +struct sched_result { + bool success; + dl_sched_result dl; + ul_sched_result ul; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/result/srs_info.h b/include/srsran/scheduler/result/srs_info.h new file mode 100644 index 0000000000..4baf40afc4 --- /dev/null +++ b/include/srsran/scheduler/result/srs_info.h @@ -0,0 +1,68 @@ +/* + * + * 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/ran/resource_allocation/ofdm_symbol_range.h" +#include "srsran/ran/srs/srs_configuration.h" +#include "srsran/scheduler/config/bwp_configuration.h" + +namespace srsran { + +struct srs_info { + rnti_t crnti; + const bwp_configuration* bwp_cfg; + uint8_t nof_antenna_ports; + /// Symbols used for this SRS resource, starting from \f$l_0\f$ until \f$l_0 + n^{SRS}_{symb}\f$, as per + /// Section 6.4.1.4.1, TS 38.211. + ofdm_symbol_range symbols; + /// Repetition factor \f$R\f$, or \c repetitionFactor, as per \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// \remark As per TS 38.211, Section 6.4.1.4.3, the number of repetitions must be not greater than the \ref symbols + /// length. + srs_nof_symbols nof_repetitions; + /// Configuration index, given by \c c_SRS, as per \c freqHopping, \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// Values {0,...,63}. + uint8_t config_index; + /// SRS sequence ID or \c sequenceId, as per \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// Values {0,...,1023}. + unsigned sequence_id; + /// Bandwidth index, given by \c b_SRS, as per \c freqHopping, \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// Values {0,...,3}. + uint8_t bw_index; + /// Transmission comb size, as per \c transmissionComb, in \c SRS-Config, TS 38.331, or \f$K_{TC}\f$, as per + /// Section 6.4.1.4.1, TS 38.211. + tx_comb_size tx_comb; + /// Transmission comb offset, given in \c combOffset-n2 or \c combOffset-n4, \c transmissionComb, \c SRS-Resource, + /// in \c SRS-Config, TS 38.331. Values {0, 1} if tx_comb_size == 2, {0,...,3} if tx_comb_size == 4. + uint8_t comb_offset; + /// Cyclic shift, given in \c cyclicShift-n2 or \c cyclicShift-n4, \c transmissionComb, \c SRS-Resource, in \c + /// SRS-Config, TS 38.331. Values {0,...,7} if tx_comb_size == 2, {0,...,11} if tx_comb_size == 4. + uint8_t cyclic_shift; + /// Frequency domain position \c freqDomainPosition, \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// Values {0,...,67}. + uint8_t freq_position; + /// Frequency domain shift \c freqDomainShift, \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// Values {0,...,268}. + unsigned freq_shift; + /// Frequency hopping \c b_hop, as per \c freqHopping, \c SRS-Resource, in \c SRS-Config, TS 38.331. + /// Values {0,...,3}. + uint8_t freq_hopping; + srs_group_or_sequence_hopping group_or_seq_hopping; + srs_resource_type resource_type; + /// SRS periodicity in slots, as per \c SRS-PeriodicityAndOffset, in \c SRS-Config, TS 38.331. + /// \remark Only applies if resource_type == periodic or resource_type == semi_persistent. + srs_periodicity t_srs_period; + /// SRS offset in slots, as per \c SRS-PeriodicityAndOffset, in \c SRS-Config, TS 38.331. + /// Values { 0,...,t_srs_period - 1}. + /// \remark Only applies if resource_type == periodic or resource_type == semi_persistent. + unsigned t_offset; +}; + +} // namespace srsran diff --git a/include/srsran/scheduler/scheduler_slot_handler.h b/include/srsran/scheduler/scheduler_slot_handler.h index 653cc07777..eaeeb15c3e 100644 --- a/include/srsran/scheduler/scheduler_slot_handler.h +++ b/include/srsran/scheduler/scheduler_slot_handler.h @@ -10,308 +10,12 @@ #pragma once -#include "srsran/adt/static_vector.h" -#include "srsran/ran/csi_report/csi_report_configuration.h" -#include "srsran/ran/csi_report/csi_report_data.h" -#include "srsran/ran/csi_rs/csi_rs_types.h" #include "srsran/ran/du_types.h" -#include "srsran/ran/logical_channel/lcid_dl_sch.h" -#include "srsran/ran/pci.h" -#include "srsran/ran/prach/prach_format_type.h" -#include "srsran/ran/pucch/pucch_mapping.h" -#include "srsran/ran/pusch/pusch_mcs.h" -#include "srsran/ran/resource_allocation/ofdm_symbol_range.h" -#include "srsran/ran/rnti.h" -#include "srsran/ran/slot_pdu_capacity_constants.h" #include "srsran/ran/slot_point.h" -#include "srsran/ran/srs/srs_configuration.h" -#include "srsran/ran/uci/uci_configuration.h" -#include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/result/pdcch_info.h" -#include "srsran/scheduler/result/pdsch_info.h" -#include "srsran/scheduler/scheduler_pucch_format.h" -#include "srsran/scheduler/vrb_alloc.h" namespace srsran { -struct pusch_information { - rnti_t rnti; - const bwp_configuration* bwp_cfg; - vrb_alloc rbs; - ofdm_symbol_range symbols; - /// \brief For resource allocation type 1, it indicates if intra-slot frequency hopping is enabled, as per TS38.212 - /// Section 7.3.1.1. - bool intra_slot_freq_hopping; - /// \brief Index of the first PRB after intra-slot frequency hopping, as indicated by the value of \f$RB_{start}\f$ - /// for i=1, as per TS38.214, Section 6.3. Valid when intra_slot_freq_hopping is enabled. Values: {0,...274}. - uint16_t pusch_second_hop_prb; - /// \brief The uplink Tx Direct Current location for the carrier. Only values in the value range of this field - /// between 0 and 3299, which indicate the subcarrier index within the carrier corresponding to the numerology of the - /// corresponding uplink BWP and value 3300, which indicates "Outside the carrier" and value 3301, which indicates - /// "Undetermined position within the carrier" are used. - uint16_t tx_direct_current_location; - /// Indicates whether there is 7.5 kHz shift or not. - bool ul_freq_shift_7p5khz; - /// Modulation and coding scheme. - sch_mcs_description mcs_descr; - /// \brief MCS index, range {0, ..., 31} (See TS38.214 Section 5.1.4.1). - /// \note Should match value sent in DCI. - sch_mcs_index mcs_index; - /// MCS table (See TS38.214 Section 6.1.4.1). - pusch_mcs_table mcs_table; - /// Indicates if transform precoding is enabled or disabled (see TS 38.214, Section 6.1.4.1). - bool transform_precoding; - /// Parameter \f$n_{ID}\f$ as per TS38.211 Section 6.3.1.1. Values: {0,...,1023}. - uint16_t n_id; - /// Number of layers as per TS38.211, Section 6.3.1.3. - unsigned nof_layers; - /// DMRS configuration as per TS38.211 Section 6.4.1.1. - dmrs_information dmrs; - /// \brief PUSCH DMRS ID \f$n_{ID}^{RS}\f$ as per TS38.211 Section 6.4.1.1.1.2. This field is only valid when - /// transform_precoding is enabled. Values: {0,...,1007} (Rel-15), {0,...,65535} (Rel-16). - uint16_t pusch_dmrs_id; - /// \brief PUSCH DMRS hopping mode as per TS38.211, Section 6.4.1.1.1.2. It is only valid when the transform - /// precoding for PUSCH is enabled. - enum class dmrs_hopping_mode { no_hopping, group_hopping, sequence_hopping } dmrs_hopping_mode; - /// Redundancy version index (see TS38.214 Table 6.1.4). Values: {0,...,3}. - uint8_t rv_index; - /// HARQ process number as per TS38.212 Section 6.3.1.1. Values: {0,...,15}. - uint8_t harq_id; - /// \brief Signals whether the PUSCH PDU corresponds to an initial transmission or a retransmission of a MAC PDU for - /// this HARQ process ID for this TB. Note: Unlike NDI, new_data does not toggle to indicate new transmission, - /// but is set to 1. - bool new_data; - /// Transport block size in bytes. - uint32_t tb_size_bytes; - /// \brief Number of CBs in the TB (could be more than the number of CBs in this PUSCH transmission). Should be set - /// to zero in any of the following conditions: 1) CBG is not supported or requested 2) newData=1 (new transmission) - /// 3) tbSize=0. - uint16_t num_cb; -}; - -struct uci_info { - /// Contains the HARQ-ACK information for UCI on PUSCH. - struct harq_info { - /// Number of bits of ACK to be reported. - uint16_t harq_ack_nof_bits = 0; - /// \f$\beta^{HARQ-ACK}_{offset}\f$ parameter, as per Section 9.3, TS 38.213. The default value is defined in \c - /// BetaOffsets, TS 38.331. - uint8_t beta_offset_harq_ack = 11; - }; - - /// Contains the CSI part 1 and part 2 information for UCI on PUSCH. - struct csi_info { - /// Contains information how the CSI bits are to be decoded. - csi_report_configuration csi_rep_cfg; - /// Number of bits of CSI Part 1 to be reported. - uint16_t csi_part1_nof_bits = 0; - /// \f$\beta^{CSI-1}_{offset}\f$ parameter, as per Section 9.3, TS 38.213. The default value is defined in \c - /// BetaOffsets, TS 38.331. - uint8_t beta_offset_csi_1 = 13; - /// \f$\beta^{CSI-2}_{offset}\f$ parameter, as per Section 9.3, TS 38.213. - /// If set, the CSI report includes CSI Part 2. - std::optional beta_offset_csi_2; - }; - - std::optional harq; - std::optional csi; - /// \f$\alpha\f$ parameter, as per Section 6.3.2.4.1.1-3, TS 38.212. - alpha_scaling_opt alpha; -}; - -/// Stores the information associated with a CSI-RS signalling. -struct csi_rs_info { - const bwp_configuration* bwp_cfg; - /// Range of RBs where this CSI resource starts and ends, with relation to CRB#0. Only multiples of 4 are allowed. - crb_interval crbs; - csi_rs_type type; - /// \brief Row entry into the CSI Resource location table, as per 3GP TS 38.211, sec 7.4.1.5.3 and table 7.4.1.5.3-1. - /// Values: {1,...,18}. - uint8_t row; - /// \brief Bitmap defining the frequencyDomainAllocation as per 3GPP TS 38.211, sec 7.4.1.5.3 and 3GPP TS 38.331 - /// "CSIResource Mapping". - bounded_bitset<12, false> freq_domain; - /// \brief The time domain location l0 and firstOFDMSymbolInTimeDomain as per 3GPP TS 38.211, sec 7.4.1.5.3. - /// Values: {0,...,13}. - uint8_t symbol0; - /// \brief The time domain location l1 and firstOFDMSymbolInTimeDomain2 as per 3GPP TS 38.211, sec 7.4.1.5.3. - uint8_t symbol1; - csi_rs_cdm_type cdm_type; - csi_rs_freq_density_type freq_density; - /// \brief ScramblingID of the CSI-RS as per 3GPP TS 38.214, sec 5.2.2.3.1. Values: {0,...,1023}. - uint16_t scrambling_id; - /// Ratio of PDSCH EPRE to NZP CSI-RS EPRE as per 3GPP TS 38.214, clause 5.2.2.3.1. Values: {-8,...,15}. - int8_t power_ctrl_offset; - /// Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE. Values: {-3,0,3,6}. - int8_t power_ctrl_offset_ss; -}; - -struct dl_sched_result { - /// Number of DL symbols active for this slot. - unsigned nof_dl_symbols; - - /// Allocated DL PDCCHs. Includes both SIB, RAR and Data PDCCHs. - pdcch_dl_info_list dl_pdcchs; - - /// Allocated UL PDCCHs. - pdcch_ul_info_list ul_pdcchs; - - /// Allocation of SSB and SIBs. - dl_broadcast_allocation bc; - - /// Allocation of dedicated RARs. - static_vector rar_grants; - - /// Allocation of Paging messages. - static_vector paging_grants; - - /// Allocation of dedicated UE messages. - static_vector ue_grants; - - /// Allocation of CSI-RS messages. - static_vector csi_rs; -}; - -struct ul_sched_info { - pusch_information pusch_cfg; - std::optional uci; - - /// \brief Information relative to a PDSCH allocation decision that is used for the purpose of logging or - /// tracing, but not passed to the PHY. - struct decision_context { - du_ue_index_t ue_index; - search_space_id ss_id; - /// Chosen k2 delay between UL PDCCH and PUSCH. - unsigned k2; - /// Number of times the HARQ process has been retransmitted. - unsigned nof_retxs; - /// Delay between PDSCH message with RAR and its corresponding PUSCH. - std::optional msg3_delay; - /// Offset that the OLLA algorithm applied to derive the UL MCS. - std::optional olla_offset; - } context; -}; - -struct prach_occasion_info { - /// Physical Cell identifier. - pci_t pci; - /// Number of time-domain PRACH occasions (\f$N^{RAslot}_t\f$), as per TS38.211 Tables 6.3.3.2-[2-4]. - uint8_t nof_prach_occasions; - /// RACH format information for the PRACH occasions. - prach_format_type format; - /// Frequency domain occasion index \f$n \in \{0,...,M-1\}\f$, where \f$M\f$ is the higher-layer parameter msg1-FDM, - /// which can take the values \f$\{1,2,4,8\}\f$. See TS38.211, sec 6.3.3.2. Possible values {0,...,7}. - uint8_t index_fd_ra; - /// Starting symbol for the first PRACH TD occasion. - /// \remark See TS38.211, sec 6.3.3.2 and Tables 6.3.3.2-2 and 6.3.3.2-4. Possible values: {0,...,13}. - uint8_t start_symbol; - /// N-CS configuration as per TS38.211, Table 6.3.3.1-5. Possible values: {0,...,419}. - uint16_t nof_cs; - /// Number of frequency domain occasions starting with index_fd_ra. Possible values: {1,...,8}. - uint8_t nof_fd_ra; - /// Start of preamble logical index to monitor the PRACH occasions in this slot. Values: {0,...63}. - uint8_t start_preamble_index; - /// Number of preamble logical indices. Values: {1,...,64}. - uint8_t nof_preamble_indexes; -}; - -/// Info about PUCCH used resource. -struct pucch_info { - /// This information only is used by the scheduler and not passed to the PHY. - struct context { - /// Identifier of the PUCCH PDU within the list of PUCCH PDUs for a given slot. The ID is only meaningful for a - /// given UE; i.e., different UEs can reuse the same ID, but a UE cannot reuse the same ID for different PDUs. - unsigned id = MAX_PUCCH_PDUS_PER_SLOT; - /// Determines whether the PUCCH PDU uses common resources. - bool is_common = false; - }; - - rnti_t crnti; - const bwp_configuration* bwp_cfg; - pucch_format format; - /// PRBs and symbols for this PUCCH resource. - pucch_resources resources; - union { - pucch_format_0 format_0; - pucch_format_1 format_1; - pucch_format_2 format_2; - pucch_format_3 format_3; - pucch_format_4 format_4; - }; - /// In case the PUCCH will contain CSI bits, this struct contains information how those bits are to be decoded. - std::optional csi_rep_cfg; - - context pdu_context; -}; - -struct srs_info { - rnti_t crnti; - const bwp_configuration* bwp_cfg; - uint8_t nof_antenna_ports; - /// Symbols used for this SRS resource, starting from \f$l_0\f$ until \f$l_0 + n^{SRS}_{symb}\f$, as per - /// Section 6.4.1.4.1, TS 38.211. - ofdm_symbol_range symbols; - /// Repetition factor \f$R\f$, or \c repetitionFactor, as per \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// \remark As per TS 38.211, Section 6.4.1.4.3, the number of repetitions must be not greater than the \ref symbols - /// length. - srs_nof_symbols nof_repetitions; - /// Configuration index, given by \c c_SRS, as per \c freqHopping, \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// Values {0,...,63}. - uint8_t config_index; - /// SRS sequence ID or \c sequenceId, as per \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// Values {0,...,1023}. - unsigned sequence_id; - /// Bandwidth index, given by \c b_SRS, as per \c freqHopping, \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// Values {0,...,3}. - uint8_t bw_index; - /// Transmission comb size, as per \c transmissionComb, in \c SRS-Config, TS 38.331, or \f$K_{TC}\f$, as per - /// Section 6.4.1.4.1, TS 38.211. - tx_comb_size tx_comb; - /// Transmission comb offset, given in \c combOffset-n2 or \c combOffset-n4, \c transmissionComb, \c SRS-Resource, - /// in \c SRS-Config, TS 38.331. Values {0, 1} if tx_comb_size == 2, {0,...,3} if tx_comb_size == 4. - uint8_t comb_offset; - /// Cyclic shift, given in \c cyclicShift-n2 or \c cyclicShift-n4, \c transmissionComb, \c SRS-Resource, in \c - /// SRS-Config, TS 38.331. Values {0,...,7} if tx_comb_size == 2, {0,...,11} if tx_comb_size == 4. - uint8_t cyclic_shift; - /// Frequency domain position \c freqDomainPosition, \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// Values {0,...,67}. - uint8_t freq_position; - /// Frequency domain shift \c freqDomainShift, \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// Values {0,...,268}. - unsigned freq_shift; - /// Frequency hopping \c b_hop, as per \c freqHopping, \c SRS-Resource, in \c SRS-Config, TS 38.331. - /// Values {0,...,3}. - uint8_t freq_hopping; - srs_group_or_sequence_hopping group_or_seq_hopping; - srs_resource_type resource_type; - /// SRS periodicity in slots, as per \c SRS-PeriodicityAndOffset, in \c SRS-Config, TS 38.331. - /// \remark Only applies if resource_type == periodic or resource_type == semi_persistent. - srs_periodicity t_srs_period; - /// SRS offset in slots, as per \c SRS-PeriodicityAndOffset, in \c SRS-Config, TS 38.331. - /// Values { 0,...,t_srs_period - 1}. - /// \remark Only applies if resource_type == periodic or resource_type == semi_persistent. - unsigned t_offset; -}; - -struct ul_sched_result { - /// Number of UL symbols active for this slot. - unsigned nof_ul_symbols; - /// PUSCH grants allocated in the current slot. - static_vector puschs; - /// PRACH occasions within the given slot. - static_vector prachs; - /// PUCCH grants allocated in the current slot. - static_vector pucchs; - /// SRS grants allocated in the current slot. - static_vector srss; -}; - -/// Scheduler decision made for DL and UL in a given slot. -struct sched_result { - bool success; - dl_sched_result dl; - ul_sched_result ul; -}; +struct sched_result; class scheduler_slot_handler { 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 3f223317e0..76a01fda27 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 @@ -16,6 +16,7 @@ #include "srsran/ran/csi_report/csi_report_on_pucch_helpers.h" #include "srsran/scheduler/harq_id.h" #include "srsran/scheduler/resource_grid_util.h" +#include "srsran/scheduler/result/sched_result.h" #include #include 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 85663027d6..619783cdf1 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 @@ -15,6 +15,8 @@ #include "srsran/du/du_high/du_test_mode_config.h" #include "srsran/mac/mac.h" #include "srsran/mac/mac_cell_result.h" +#include "srsran/scheduler/result/pucch_info.h" +#include "srsran/scheduler/result/pusch_info.h" #include "srsran/srslog/srslog.h" #include #include diff --git a/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp b/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp index ba52c66326..f965ccf4b4 100644 --- a/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp +++ b/lib/du/du_high/test_mode/mac_test_mode_helpers.cpp @@ -9,6 +9,8 @@ */ #include "mac_test_mode_helpers.h" +#include "srsran/scheduler/result/pucch_info.h" +#include "srsran/scheduler/result/pusch_info.h" using namespace srsran; using namespace srs_du; diff --git a/lib/du/du_high/test_mode/mac_test_mode_helpers.h b/lib/du/du_high/test_mode/mac_test_mode_helpers.h index 31e10b9556..a4004b109f 100644 --- a/lib/du/du_high/test_mode/mac_test_mode_helpers.h +++ b/lib/du/du_high/test_mode/mac_test_mode_helpers.h @@ -15,9 +15,12 @@ #include "srsran/mac/mac_pdu_handler.h" #include "srsran/scheduler/harq_id.h" #include "srsran/scheduler/scheduler_configurator.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { + +struct pucch_info; +struct ul_sched_info; + namespace srs_du { /// Create dummy PDU with BSR. @@ -31,4 +34,4 @@ mac_uci_pdu create_uci_pdu(const ul_sched_info& pusch, const du_test_mode_config bool pucch_info_and_uci_ind_match(const pucch_info& pucch, const mac_uci_pdu& uci_ind); } // namespace srs_du -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp b/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp index b6b19821bc..a37ea4535a 100644 --- a/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp +++ b/lib/fapi_adaptor/mac/mac_to_fapi_translator.cpp @@ -19,6 +19,7 @@ #include "srsran/fapi_adaptor/mac/messages/pusch.h" #include "srsran/fapi_adaptor/mac/messages/srs.h" #include "srsran/fapi_adaptor/mac/messages/ssb.h" +#include "srsran/scheduler/result/sched_result.h" using namespace srsran; using namespace fapi_adaptor; diff --git a/lib/fapi_adaptor/mac/mac_to_fapi_translator.h b/lib/fapi_adaptor/mac/mac_to_fapi_translator.h index 6292be6a92..4b1217385b 100644 --- a/lib/fapi_adaptor/mac/mac_to_fapi_translator.h +++ b/lib/fapi_adaptor/mac/mac_to_fapi_translator.h @@ -14,6 +14,7 @@ #include "srsran/fapi_adaptor/precoding_matrix_mapper.h" #include "srsran/fapi_adaptor/uci_part2_correspondence_mapper.h" #include "srsran/mac/mac_cell_result.h" +#include "srsran/scheduler/result/pdcch_info.h" namespace srsran { diff --git a/lib/fapi_adaptor/mac/messages/pdsch.cpp b/lib/fapi_adaptor/mac/messages/pdsch.cpp index 1903e8de5c..dc8a06a764 100644 --- a/lib/fapi_adaptor/mac/messages/pdsch.cpp +++ b/lib/fapi_adaptor/mac/messages/pdsch.cpp @@ -14,6 +14,7 @@ #include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" #include "srsran/ran/sch/sch_constants.h" #include "srsran/ran/sch/tbs_calculator.h" +#include "srsran/scheduler/result/pdsch_info.h" #include using namespace srsran; diff --git a/lib/fapi_adaptor/mac/messages/prach.cpp b/lib/fapi_adaptor/mac/messages/prach.cpp index bd1d6f0418..64a2bec6b2 100644 --- a/lib/fapi_adaptor/mac/messages/prach.cpp +++ b/lib/fapi_adaptor/mac/messages/prach.cpp @@ -9,7 +9,7 @@ */ #include "srsran/fapi_adaptor/mac/messages/prach.h" -#include "srsran/mac/mac_cell_result.h" +#include "srsran/scheduler/result/prach_info.h" using namespace srsran; using namespace fapi_adaptor; diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index 7331270f05..abe3e00849 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -10,7 +10,7 @@ #include "srsran/fapi_adaptor/mac/messages/pucch.h" #include "srsran/mac/mac_cell_result.h" -#include "srsran/scheduler/scheduler_pucch_format.h" +#include "srsran/scheduler/result/pucch_info.h" using namespace srsran; using namespace fapi_adaptor; diff --git a/lib/fapi_adaptor/mac/messages/pusch.cpp b/lib/fapi_adaptor/mac/messages/pusch.cpp index b2df7778a2..9f7a1b08fe 100644 --- a/lib/fapi_adaptor/mac/messages/pusch.cpp +++ b/lib/fapi_adaptor/mac/messages/pusch.cpp @@ -10,9 +10,9 @@ #include "srsran/fapi_adaptor/mac/messages/pusch.h" #include "srsran/fapi_adaptor/uci_part2_correspondence_mapper.h" -#include "srsran/mac/mac_cell_result.h" #include "srsran/phy/upper/channel_coding/ldpc/ldpc.h" #include "srsran/ran/sch/sch_constants.h" +#include "srsran/scheduler/result/pusch_info.h" using namespace srsran; using namespace fapi_adaptor; diff --git a/lib/fapi_adaptor/mac/messages/srs.cpp b/lib/fapi_adaptor/mac/messages/srs.cpp index 19c39a945f..6364b6cc3d 100644 --- a/lib/fapi_adaptor/mac/messages/srs.cpp +++ b/lib/fapi_adaptor/mac/messages/srs.cpp @@ -9,7 +9,7 @@ */ #include "srsran/fapi_adaptor/mac/messages/srs.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/srs_info.h" using namespace srsran; using namespace fapi_adaptor; diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp index 303af5ccac..a925578118 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp @@ -10,8 +10,8 @@ #include "dl_sch_pdu_assembler.h" #include "cell_dl_harq_buffer_pool.h" -#include "srsran/adt/byte_buffer_chain.h" #include "srsran/ran/pdsch/pdsch_constants.h" +#include "srsran/scheduler/result/pdsch_info.h" #include "srsran/support/error_handling.h" #include "srsran/support/format/fmt_to_c_str.h" diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.h b/lib/mac/mac_dl/dl_sch_pdu_assembler.h index 278de59266..a342c3f409 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.h +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.h @@ -20,6 +20,9 @@ namespace srsran { class byte_buffer_chain; class cell_dl_harq_buffer_pool; +struct ta_cmd_ce_payload; +struct dl_msg_tb_info; +struct dl_msg_lc_info; /// \brief This class represents and encodes a MAC DL-SCH PDU that may contain multiple subPDUs. /// diff --git a/lib/mac/mac_dl/mac_cell_processor.cpp b/lib/mac/mac_dl/mac_cell_processor.cpp index 4b9b869aac..49f2cc62c9 100644 --- a/lib/mac/mac_dl/mac_cell_processor.cpp +++ b/lib/mac/mac_dl/mac_cell_processor.cpp @@ -12,6 +12,7 @@ #include "srsran/instrumentation/traces/du_traces.h" #include "srsran/mac/mac_cell_result.h" #include "srsran/ran/pdsch/pdsch_constants.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/support/async/execute_on_blocking.h" #include "srsran/support/rtsan.h" diff --git a/lib/mac/mac_dl/paging_pdu_assembler.cpp b/lib/mac/mac_dl/paging_pdu_assembler.cpp index 62905bf84b..4f255aeeb4 100644 --- a/lib/mac/mac_dl/paging_pdu_assembler.cpp +++ b/lib/mac/mac_dl/paging_pdu_assembler.cpp @@ -10,6 +10,7 @@ #include "paging_pdu_assembler.h" #include "srsran/asn1/rrc_nr/pcch_msg.h" +#include "srsran/scheduler/result/pdsch_info.h" using namespace srsran; diff --git a/lib/mac/mac_dl/paging_pdu_assembler.h b/lib/mac/mac_dl/paging_pdu_assembler.h index 8040a51717..2653b1a8f9 100644 --- a/lib/mac/mac_dl/paging_pdu_assembler.h +++ b/lib/mac/mac_dl/paging_pdu_assembler.h @@ -10,11 +10,12 @@ #pragma once -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/memory_pool/ring_buffer_pool.h" namespace srsran { +struct dl_paging_allocation; + /// Encodes Paging PDUs based on Paging information provided by the scheduler. class paging_pdu_assembler { diff --git a/lib/mac/mac_dl/rar_pdu_assembler.cpp b/lib/mac/mac_dl/rar_pdu_assembler.cpp index 2be8a491af..d06f5d57c3 100644 --- a/lib/mac/mac_dl/rar_pdu_assembler.cpp +++ b/lib/mac/mac_dl/rar_pdu_assembler.cpp @@ -9,6 +9,7 @@ */ #include "rar_pdu_assembler.h" +#include "srsran/scheduler/result/pdsch_info.h" using namespace srsran; diff --git a/lib/mac/mac_dl/rar_pdu_assembler.h b/lib/mac/mac_dl/rar_pdu_assembler.h index 1a2a5832d9..f5c2cbf252 100644 --- a/lib/mac/mac_dl/rar_pdu_assembler.h +++ b/lib/mac/mac_dl/rar_pdu_assembler.h @@ -11,11 +11,12 @@ #pragma once #include "srsran/mac/cell_configuration.h" -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/memory_pool/ring_buffer_pool.h" namespace srsran { +struct rar_information; + /// Encodes RAR PDUs based on RAR information provided by the scheduler. class rar_pdu_assembler { diff --git a/lib/mac/mac_dl/ssb_assembler.cpp b/lib/mac/mac_dl/ssb_assembler.cpp index c0480cfa23..6bd3aa880c 100644 --- a/lib/mac/mac_dl/ssb_assembler.cpp +++ b/lib/mac/mac_dl/ssb_assembler.cpp @@ -11,7 +11,7 @@ #include "ssb_assembler.h" #include "srsran/mac/mac_cell_result.h" #include "srsran/ran/ssb_mapping.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pdsch_info.h" using namespace srsran; diff --git a/lib/mac/mac_sched/srsran_scheduler_adapter.cpp b/lib/mac/mac_sched/srsran_scheduler_adapter.cpp index 1a3e216579..2faa496b71 100644 --- a/lib/mac/mac_sched/srsran_scheduler_adapter.cpp +++ b/lib/mac/mac_sched/srsran_scheduler_adapter.cpp @@ -9,6 +9,7 @@ */ #include "srsran_scheduler_adapter.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/scheduler/scheduler_factory.h" using namespace srsran; diff --git a/lib/mac/mac_sched/uci_cell_decoder.cpp b/lib/mac/mac_sched/uci_cell_decoder.cpp index fce909de84..7d3f5076ab 100644 --- a/lib/mac/mac_sched/uci_cell_decoder.cpp +++ b/lib/mac/mac_sched/uci_cell_decoder.cpp @@ -10,6 +10,8 @@ #include "uci_cell_decoder.h" #include "srsran/ran/csi_report/csi_report_on_pucch_helpers.h" +#include "srsran/scheduler/result/pucch_info.h" +#include "srsran/scheduler/result/pusch_info.h" using namespace srsran; diff --git a/lib/mac/mac_sched/uci_cell_decoder.h b/lib/mac/mac_sched/uci_cell_decoder.h index 56e95803f7..b22ea2b024 100644 --- a/lib/mac/mac_sched/uci_cell_decoder.h +++ b/lib/mac/mac_sched/uci_cell_decoder.h @@ -16,10 +16,12 @@ #include "srsran/ran/csi_report/csi_report_configuration.h" #include "srsran/scheduler/scheduler_configurator.h" #include "srsran/scheduler/scheduler_feedback_handler.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { +struct ul_sched_info; +struct pucch_info; + using du_rnti_table = rnti_value_table; class uci_cell_decoder diff --git a/lib/scheduler/cell/cell_harq_manager.cpp b/lib/scheduler/cell/cell_harq_manager.cpp index 22f451c4d8..52f1328148 100644 --- a/lib/scheduler/cell/cell_harq_manager.cpp +++ b/lib/scheduler/cell/cell_harq_manager.cpp @@ -10,7 +10,8 @@ #include "cell_harq_manager.h" #include "srsran/scheduler/resource_grid_util.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pdsch_info.h" +#include "srsran/scheduler/result/pusch_info.h" using namespace srsran; using namespace harq_utils; diff --git a/lib/scheduler/cell/resource_grid.h b/lib/scheduler/cell/resource_grid.h index a86771ad60..6b62f22294 100644 --- a/lib/scheduler/cell/resource_grid.h +++ b/lib/scheduler/cell/resource_grid.h @@ -15,8 +15,8 @@ #include "../support/rb_helper.h" #include "srsran/adt/circular_array.h" #include "srsran/ran/slot_point.h" -#include "srsran/scheduler/mac_scheduler.h" #include "srsran/scheduler/resource_grid_util.h" +#include "srsran/scheduler/result/sched_result.h" namespace srsran { @@ -367,4 +367,4 @@ struct formatter { } }; -} // namespace fmt \ No newline at end of file +} // namespace fmt diff --git a/lib/scheduler/common_scheduling/paging_scheduler.h b/lib/scheduler/common_scheduling/paging_scheduler.h index 3cd1cea199..2a635aeefe 100644 --- a/lib/scheduler/common_scheduling/paging_scheduler.h +++ b/lib/scheduler/common_scheduling/paging_scheduler.h @@ -15,11 +15,15 @@ #include "srsran/adt/concurrent_queue.h" #include "srsran/adt/mpmc_queue.h" #include "srsran/scheduler/config/scheduler_expert_config.h" +#include "srsran/scheduler/result/pdsch_info.h" +#include "srsran/scheduler/scheduler_paging_handler.h" #include "srsran/srslog/logger.h" #include namespace srsran { +struct sched_paging_information; + /// Defines Paging scheduler that is used to allocate resources to send paging information to UE in a given slot. class paging_scheduler { diff --git a/lib/scheduler/common_scheduling/ra_scheduler.h b/lib/scheduler/common_scheduling/ra_scheduler.h index 3a886624a9..b939aba00f 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.h +++ b/lib/scheduler/common_scheduling/ra_scheduler.h @@ -18,6 +18,7 @@ #include "srsran/adt/mpmc_queue.h" #include "srsran/ran/prach/prach_configuration.h" #include "srsran/scheduler/config/scheduler_expert_config.h" +#include "srsran/scheduler/scheduler_feedback_handler.h" #include "srsran/srslog/srslog.h" #include @@ -25,6 +26,7 @@ namespace srsran { class scheduler_event_logger; class cell_metrics_handler; +struct ul_crc_indication; /// Get MSG3 Delay. /// \param[in] pusch_td_res_alloc PUSCH-TimeDomainResourceAllocation. diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 391f8f52a8..7f2daf89bb 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -10,6 +10,7 @@ #include "../config/cell_configuration.h" #include "scheduler_metrics_handler.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/scheduler/scheduler_configurator.h" #include "srsran/srslog/srslog.h" diff --git a/lib/scheduler/logging/scheduler_result_logger.cpp b/lib/scheduler/logging/scheduler_result_logger.cpp index cd0a3d5368..94e01b719c 100644 --- a/lib/scheduler/logging/scheduler_result_logger.cpp +++ b/lib/scheduler/logging/scheduler_result_logger.cpp @@ -10,6 +10,7 @@ #include "scheduler_result_logger.h" #include "srsran/ran/csi_report/csi_report_formatters.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/srslog/srslog.h" #include "srsran/support/format/fmt_to_c_str.h" diff --git a/lib/scheduler/logging/scheduler_result_logger.h b/lib/scheduler/logging/scheduler_result_logger.h index 1ba7658e55..bd65c209b2 100644 --- a/lib/scheduler/logging/scheduler_result_logger.h +++ b/lib/scheduler/logging/scheduler_result_logger.h @@ -10,11 +10,13 @@ #pragma once -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/ran/pci.h" #include "srsran/srslog/logger.h" namespace srsran { +struct sched_result; + class scheduler_result_logger { public: diff --git a/lib/scheduler/srs/srs_scheduler_impl.h b/lib/scheduler/srs/srs_scheduler_impl.h index e48f4db356..533f196a8e 100644 --- a/lib/scheduler/srs/srs_scheduler_impl.h +++ b/lib/scheduler/srs/srs_scheduler_impl.h @@ -18,6 +18,7 @@ namespace srsran { struct cell_resource_allocator; struct cell_slot_resource_allocator; +struct srs_info; class srs_scheduler_impl : public srs_scheduler { diff --git a/lib/scheduler/support/dmrs_helpers.h b/lib/scheduler/support/dmrs_helpers.h index b63d1ba317..2dae3b1e04 100644 --- a/lib/scheduler/support/dmrs_helpers.h +++ b/lib/scheduler/support/dmrs_helpers.h @@ -15,7 +15,7 @@ #include "srsran/ran/dmrs.h" #include "srsran/ran/pdsch/pdsch_antenna_ports_mapping.h" #include "srsran/scheduler/config/dmrs.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/dmrs_info.h" #include "srsran/support/error_handling.h" namespace srsran { diff --git a/lib/scheduler/support/mcs_tbs_calculator.h b/lib/scheduler/support/mcs_tbs_calculator.h index d17a7d6bff..34e5ae8926 100644 --- a/lib/scheduler/support/mcs_tbs_calculator.h +++ b/lib/scheduler/support/mcs_tbs_calculator.h @@ -11,7 +11,7 @@ #pragma once #include "srsran/ran/sch/sch_mcs.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include namespace srsran { diff --git a/lib/scheduler/support/sch_pdu_builder.h b/lib/scheduler/support/sch_pdu_builder.h index 076039c55c..99491a4a0d 100644 --- a/lib/scheduler/support/sch_pdu_builder.h +++ b/lib/scheduler/support/sch_pdu_builder.h @@ -13,8 +13,7 @@ #include "../config/ue_configuration.h" #include "../ue_context/ue_channel_state_manager.h" #include "mcs_tbs_calculator.h" -#include "srsran/scheduler/harq_id.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pusch_info.h" namespace srsran { diff --git a/lib/scheduler/ue_context/dl_logical_channel_manager.h b/lib/scheduler/ue_context/dl_logical_channel_manager.h index 1fef82ae91..8303ac8350 100644 --- a/lib/scheduler/ue_context/dl_logical_channel_manager.h +++ b/lib/scheduler/ue_context/dl_logical_channel_manager.h @@ -13,8 +13,9 @@ #include "srsran/mac/mac_pdu_format.h" #include "srsran/ran/logical_channel/lcid_dl_sch.h" #include "srsran/scheduler/config/logical_channel_config.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pdsch_info.h" #include +#include namespace srsran { diff --git a/lib/scheduler/ue_context/ue_channel_state_manager.h b/lib/scheduler/ue_context/ue_channel_state_manager.h index b4049ace87..9d39a84c98 100644 --- a/lib/scheduler/ue_context/ue_channel_state_manager.h +++ b/lib/scheduler/ue_context/ue_channel_state_manager.h @@ -19,7 +19,7 @@ #include "srsran/scheduler/config/scheduler_expert_config.h" #include "srsran/scheduler/config/serving_cell_config.h" #include "srsran/scheduler/resource_grid_util.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pdsch_info.h" #include "srsran/srslog/logger.h" #include "srsran/support/math/accumulators.h" diff --git a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp index ed4935d768..e2bcbb47f6 100644 --- a/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_multi_ue_benchmark.cpp @@ -14,6 +14,7 @@ #include "tests/unittests/scheduler/test_utils/config_generators.h" #include "srsran/adt/circular_array.h" #include "srsran/du/du_cell_config_helpers.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/scheduler/scheduler_factory.h" #include "srsran/srslog/srslog.h" #include "srsran/support/benchmark_utils.h" diff --git a/tests/benchmarks/scheduler/scheduler_no_ues_benchmark.cpp b/tests/benchmarks/scheduler/scheduler_no_ues_benchmark.cpp index c19f500515..a5c9b189c4 100644 --- a/tests/benchmarks/scheduler/scheduler_no_ues_benchmark.cpp +++ b/tests/benchmarks/scheduler/scheduler_no_ues_benchmark.cpp @@ -13,6 +13,7 @@ #include "tests/test_doubles/scheduler/scheduler_config_helper.h" #include "tests/unittests/scheduler/test_utils/config_generators.h" #include "tests/unittests/scheduler/test_utils/indication_generators.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/scheduler/scheduler_factory.h" #include "srsran/srslog/srslog.h" #include "srsran/support/benchmark_utils.h" diff --git a/tests/test_doubles/mac/dummy_mac_result_notifier.h b/tests/test_doubles/mac/dummy_mac_result_notifier.h index 0594f0d357..6709339ebc 100644 --- a/tests/test_doubles/mac/dummy_mac_result_notifier.h +++ b/tests/test_doubles/mac/dummy_mac_result_notifier.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/mac/mac_cell_result.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/support/executors/task_executor.h" namespace srsran { diff --git a/tests/test_doubles/mac/mac_test_messages.cpp b/tests/test_doubles/mac/mac_test_messages.cpp index 34fd959fac..9e79d425de 100644 --- a/tests/test_doubles/mac/mac_test_messages.cpp +++ b/tests/test_doubles/mac/mac_test_messages.cpp @@ -9,7 +9,8 @@ */ #include "mac_test_messages.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pucch_info.h" +#include "srsran/scheduler/result/pusch_info.h" using namespace srsran; diff --git a/tests/test_doubles/mac/mac_test_messages.h b/tests/test_doubles/mac/mac_test_messages.h index 0e28ae5070..b5887907ea 100644 --- a/tests/test_doubles/mac/mac_test_messages.h +++ b/tests/test_doubles/mac/mac_test_messages.h @@ -18,6 +18,8 @@ namespace srsran { struct pucch_info; +struct uci_info; +struct ul_sched_info; namespace test_helpers { diff --git a/tests/test_doubles/scheduler/scheduler_result_test.h b/tests/test_doubles/scheduler/scheduler_result_test.h index 208248e440..4a87481150 100644 --- a/tests/test_doubles/scheduler/scheduler_result_test.h +++ b/tests/test_doubles/scheduler/scheduler_result_test.h @@ -10,7 +10,7 @@ #pragma once -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/sched_result.h" namespace srsran { diff --git a/tests/unittests/fapi_adaptor/mac/messages/helpers.h b/tests/unittests/fapi_adaptor/mac/messages/helpers.h index d61603892a..3015d8bf4e 100644 --- a/tests/unittests/fapi_adaptor/mac/messages/helpers.h +++ b/tests/unittests/fapi_adaptor/mac/messages/helpers.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/mac/mac_cell_result.h" +#include "srsran/scheduler/result/sched_result.h" namespace srsran { namespace unittests { diff --git a/tests/unittests/mac/mac_test_helpers.h b/tests/unittests/mac/mac_test_helpers.h index ae326b0112..4b8f9b394d 100644 --- a/tests/unittests/mac/mac_test_helpers.h +++ b/tests/unittests/mac/mac_test_helpers.h @@ -19,6 +19,7 @@ #include "srsran/pcap/dlt_pcap.h" #include "srsran/pcap/rlc_pcap.h" #include "srsran/scheduler/mac_scheduler.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/support/test_utils.h" #include "srsran/support/timers.h" diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index d511475ca0..1aaf2ab439 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -9,6 +9,7 @@ */ #include "lib/scheduler/cell/cell_harq_manager.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/test_utils.h" #include diff --git a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp index 3d7a33435f..ef7b74cc80 100644 --- a/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp +++ b/tests/unittests/scheduler/scheduler_metrics_handler_test.cpp @@ -12,6 +12,7 @@ #include "lib/scheduler/logging/scheduler_metrics_handler.h" #include "tests/test_doubles/scheduler/scheduler_config_helper.h" #include "srsran/scheduler/config/scheduler_expert_config_factory.h" +#include "srsran/scheduler/result/sched_result.h" #include "srsran/support/test_utils.h" #include diff --git a/tests/unittests/scheduler/test_utils/indication_generators.cpp b/tests/unittests/scheduler/test_utils/indication_generators.cpp index 7356fbeac7..a42ad875de 100644 --- a/tests/unittests/scheduler/test_utils/indication_generators.cpp +++ b/tests/unittests/scheduler/test_utils/indication_generators.cpp @@ -9,7 +9,7 @@ */ #include "indication_generators.h" -#include "srsran/scheduler/scheduler_slot_handler.h" +#include "srsran/scheduler/result/pucch_info.h" using namespace srsran; From 2faa270ecdf9178157c5cd702ab65c1ba9dda59b Mon Sep 17 00:00:00 2001 From: frankist Date: Fri, 13 Dec 2024 17:31:01 +0100 Subject: [PATCH 192/227] sched: move sched headers to scheduler/result folder --- include/srsran/scheduler/config/bwp_configuration.h | 4 +--- .../{scheduler_pucch_format.h => result/pucch_format.h} | 0 include/srsran/scheduler/result/pucch_info.h | 2 +- include/srsran/scheduler/result/pusch_info.h | 2 +- include/srsran/scheduler/{ => result}/resource_block_group.h | 0 include/srsran/scheduler/{ => result}/vrb_alloc.h | 2 +- include/srsran/scheduler/sched_consts.h | 3 --- lib/du/du_high/adapters/f1ap_adapters.h | 1 + .../ran_resource_management/du_pucch_resource_manager.cpp | 2 +- lib/mac/mac_dl/dl_sch_pdu_assembler.cpp | 1 + lib/mac/mac_dl/dl_sch_pdu_assembler.h | 2 -- lib/mac/mac_dl/sib_pdu_assembler.h | 1 - lib/scheduler/cell/cell_harq_manager.h | 2 +- lib/scheduler/cell/resource_block_group.cpp | 2 +- lib/scheduler/cell/scheduler_prb.cpp | 2 +- lib/scheduler/cell/scheduler_prb.h | 2 +- lib/scheduler/cell/vrb_alloc.cpp | 4 ++-- lib/scheduler/common_scheduling/ssb_scheduler.h | 1 - lib/scheduler/config/cell_configuration.h | 1 + lib/scheduler/logging/scheduler_metrics_handler.h | 2 +- lib/scheduler/pdcch_scheduling/pdcch_resource_allocator.h | 1 - lib/scheduler/pucch_scheduling/pucch_allocator.h | 1 - lib/scheduler/support/rb_helper.h | 2 +- lib/scheduler/support/sched_result_helpers.h | 3 +-- tests/test_doubles/mac/mac_test_messages.h | 1 - tests/unittests/mac/dl_sch_pdu_assembler_test.cpp | 2 +- tests/unittests/scheduler/cell/cell_harq_manager_test.cpp | 1 - tests/unittests/scheduler/multiple_ue_sched_test.cpp | 1 - tests/unittests/scheduler/test_utils/result_test_helpers.h | 1 - .../scheduler/test_utils/scheduler_output_test_helpers.h | 4 +++- tests/unittests/scheduler/test_utils/scheduler_test_suite.h | 1 - 31 files changed, 21 insertions(+), 33 deletions(-) rename include/srsran/scheduler/{scheduler_pucch_format.h => result/pucch_format.h} (100%) rename include/srsran/scheduler/{ => result}/resource_block_group.h (100%) rename include/srsran/scheduler/{ => result}/vrb_alloc.h (98%) diff --git a/include/srsran/scheduler/config/bwp_configuration.h b/include/srsran/scheduler/config/bwp_configuration.h index 3e6a650fa3..91e6b64f5a 100644 --- a/include/srsran/scheduler/config/bwp_configuration.h +++ b/include/srsran/scheduler/config/bwp_configuration.h @@ -10,7 +10,6 @@ #pragma once -#include "srsran/adt/slotted_array.h" #include "srsran/ran/band_helper.h" #include "srsran/ran/cyclic_prefix.h" #include "srsran/ran/frame_types.h" @@ -23,8 +22,7 @@ #include "srsran/ran/resource_allocation/ofdm_symbol_range.h" #include "srsran/ran/resource_block.h" #include "srsran/scheduler/config/dmrs.h" -#include "srsran/scheduler/vrb_alloc.h" -#include +#include "srsran/scheduler/result/vrb_alloc.h" #include namespace srsran { diff --git a/include/srsran/scheduler/scheduler_pucch_format.h b/include/srsran/scheduler/result/pucch_format.h similarity index 100% rename from include/srsran/scheduler/scheduler_pucch_format.h rename to include/srsran/scheduler/result/pucch_format.h diff --git a/include/srsran/scheduler/result/pucch_info.h b/include/srsran/scheduler/result/pucch_info.h index d228bb117c..0e52f391b2 100644 --- a/include/srsran/scheduler/result/pucch_info.h +++ b/include/srsran/scheduler/result/pucch_info.h @@ -12,7 +12,7 @@ #include "srsran/ran/csi_report/csi_report_configuration.h" #include "srsran/ran/pucch/pucch_mapping.h" -#include "srsran/scheduler/scheduler_pucch_format.h" +#include "srsran/scheduler/result/pucch_format.h" namespace srsran { diff --git a/include/srsran/scheduler/result/pusch_info.h b/include/srsran/scheduler/result/pusch_info.h index 5e07d98bca..1f3b342d13 100644 --- a/include/srsran/scheduler/result/pusch_info.h +++ b/include/srsran/scheduler/result/pusch_info.h @@ -14,7 +14,7 @@ #include "srsran/ran/pusch/pusch_mcs.h" #include "srsran/ran/uci/uci_configuration.h" #include "srsran/scheduler/result/dmrs_info.h" -#include "srsran/scheduler/vrb_alloc.h" +#include "srsran/scheduler/result/vrb_alloc.h" namespace srsran { diff --git a/include/srsran/scheduler/resource_block_group.h b/include/srsran/scheduler/result/resource_block_group.h similarity index 100% rename from include/srsran/scheduler/resource_block_group.h rename to include/srsran/scheduler/result/resource_block_group.h diff --git a/include/srsran/scheduler/vrb_alloc.h b/include/srsran/scheduler/result/vrb_alloc.h similarity index 98% rename from include/srsran/scheduler/vrb_alloc.h rename to include/srsran/scheduler/result/vrb_alloc.h index 47f7d90f0a..9d853e3b1e 100644 --- a/include/srsran/scheduler/vrb_alloc.h +++ b/include/srsran/scheduler/result/vrb_alloc.h @@ -14,7 +14,7 @@ #include "srsran/ran/resource_allocation/rb_interval.h" #include "srsran/ran/resource_allocation/sliv.h" #include "srsran/ran/resource_block.h" -#include "srsran/scheduler/resource_block_group.h" +#include "srsran/scheduler/result/resource_block_group.h" namespace srsran { diff --git a/include/srsran/scheduler/sched_consts.h b/include/srsran/scheduler/sched_consts.h index bd933f7f5f..d3ae78e587 100644 --- a/include/srsran/scheduler/sched_consts.h +++ b/include/srsran/scheduler/sched_consts.h @@ -10,9 +10,6 @@ #pragma once -#include "srsran/ran/resource_block.h" -#include - namespace srsran { /// SSB constants. diff --git a/lib/du/du_high/adapters/f1ap_adapters.h b/lib/du/du_high/adapters/f1ap_adapters.h index f0e40bc193..40be8ae565 100644 --- a/lib/du/du_high/adapters/f1ap_adapters.h +++ b/lib/du/du_high/adapters/f1ap_adapters.h @@ -10,6 +10,7 @@ #pragma once +#include "srsran/adt/slotted_array.h" #include "srsran/du/du_high/du_manager/du_manager.h" #include "srsran/f1ap/du/f1ap_du.h" #include "srsran/support/timers.h" diff --git a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index 8ef0b569fd..ab6ca6d721 100644 --- a/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du/du_high/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -12,7 +12,7 @@ #include "srsran/ran/csi_report/csi_report_config_helpers.h" #include "srsran/ran/csi_report/csi_report_on_pucch_helpers.h" #include "srsran/ran/pucch/pucch_info.h" -#include "srsran/scheduler/scheduler_pucch_format.h" +#include "srsran/scheduler/result/pucch_format.h" #include using namespace srsran; diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp index a925578118..ccae3eba21 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.cpp @@ -10,6 +10,7 @@ #include "dl_sch_pdu_assembler.h" #include "cell_dl_harq_buffer_pool.h" +#include "srsran/mac/mac_pdu_format.h" #include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/scheduler/result/pdsch_info.h" #include "srsran/support/error_handling.h" diff --git a/lib/mac/mac_dl/dl_sch_pdu_assembler.h b/lib/mac/mac_dl/dl_sch_pdu_assembler.h index a342c3f409..ef67dfd196 100644 --- a/lib/mac/mac_dl/dl_sch_pdu_assembler.h +++ b/lib/mac/mac_dl/dl_sch_pdu_assembler.h @@ -11,10 +11,8 @@ #pragma once #include "mac_dl_ue_repository.h" -#include "srsran/mac/mac_pdu_format.h" #include "srsran/ran/logical_channel/lcid_dl_sch.h" #include "srsran/scheduler/harq_id.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { diff --git a/lib/mac/mac_dl/sib_pdu_assembler.h b/lib/mac/mac_dl/sib_pdu_assembler.h index e7f2ff5fa0..b5da20b27f 100644 --- a/lib/mac/mac_dl/sib_pdu_assembler.h +++ b/lib/mac/mac_dl/sib_pdu_assembler.h @@ -11,7 +11,6 @@ #pragma once #include "srsran/mac/mac_cell_manager.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { diff --git a/lib/scheduler/cell/cell_harq_manager.h b/lib/scheduler/cell/cell_harq_manager.h index 989ff6d0f4..77c423aa09 100644 --- a/lib/scheduler/cell/cell_harq_manager.h +++ b/lib/scheduler/cell/cell_harq_manager.h @@ -21,7 +21,7 @@ #include "srsran/ran/slot_point.h" #include "srsran/scheduler/harq_id.h" #include "srsran/scheduler/result/dci_info.h" -#include "srsran/scheduler/vrb_alloc.h" +#include "srsran/scheduler/result/vrb_alloc.h" #include "srsran/srslog/srslog.h" namespace srsran { diff --git a/lib/scheduler/cell/resource_block_group.cpp b/lib/scheduler/cell/resource_block_group.cpp index 67d2413386..749df97dc5 100644 --- a/lib/scheduler/cell/resource_block_group.cpp +++ b/lib/scheduler/cell/resource_block_group.cpp @@ -8,7 +8,7 @@ * */ -#include "srsran/scheduler/resource_block_group.h" +#include "srsran/scheduler/result/resource_block_group.h" using namespace srsran; diff --git a/lib/scheduler/cell/scheduler_prb.cpp b/lib/scheduler/cell/scheduler_prb.cpp index ca100de151..88149a447f 100644 --- a/lib/scheduler/cell/scheduler_prb.cpp +++ b/lib/scheduler/cell/scheduler_prb.cpp @@ -9,7 +9,7 @@ */ #include "scheduler_prb.h" -#include "srsran/scheduler/resource_block_group.h" +#include "srsran/scheduler/result/resource_block_group.h" using namespace srsran; diff --git a/lib/scheduler/cell/scheduler_prb.h b/lib/scheduler/cell/scheduler_prb.h index 5a71421c46..e687e599fd 100644 --- a/lib/scheduler/cell/scheduler_prb.h +++ b/lib/scheduler/cell/scheduler_prb.h @@ -13,7 +13,7 @@ #include "../support/rb_helper.h" #include "srsran/adt/bounded_bitset.h" #include "srsran/adt/interval.h" -#include "srsran/scheduler/vrb_alloc.h" +#include "srsran/scheduler/result/vrb_alloc.h" namespace srsran { diff --git a/lib/scheduler/cell/vrb_alloc.cpp b/lib/scheduler/cell/vrb_alloc.cpp index ae26df30ed..8b2469c249 100644 --- a/lib/scheduler/cell/vrb_alloc.cpp +++ b/lib/scheduler/cell/vrb_alloc.cpp @@ -8,8 +8,8 @@ * */ -#include "srsran/scheduler/vrb_alloc.h" -#include "srsran/scheduler/resource_block_group.h" +#include "srsran/scheduler/result/vrb_alloc.h" +#include "srsran/scheduler/result/resource_block_group.h" using namespace srsran; diff --git a/lib/scheduler/common_scheduling/ssb_scheduler.h b/lib/scheduler/common_scheduling/ssb_scheduler.h index ed14bec569..bf3ed1c663 100644 --- a/lib/scheduler/common_scheduling/ssb_scheduler.h +++ b/lib/scheduler/common_scheduling/ssb_scheduler.h @@ -14,7 +14,6 @@ #include "../config/cell_configuration.h" #include "srsran/adt/static_vector.h" #include "srsran/ran/slot_point.h" -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/srslog/logger.h" namespace srsran { diff --git a/lib/scheduler/config/cell_configuration.h b/lib/scheduler/config/cell_configuration.h index 547aaa1523..b5017b2f38 100644 --- a/lib/scheduler/config/cell_configuration.h +++ b/lib/scheduler/config/cell_configuration.h @@ -12,6 +12,7 @@ #include "../support/rb_helper.h" #include "srsran/adt/expected.h" +#include "srsran/adt/slotted_array.h" #include "srsran/scheduler/config/scheduler_expert_config.h" #include "srsran/scheduler/scheduler_configurator.h" diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index a3925569b4..1ed4e2c172 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -14,7 +14,6 @@ #include "srsran/scheduler/scheduler_dl_buffer_state_indication_handler.h" #include "srsran/scheduler/scheduler_feedback_handler.h" #include "srsran/scheduler/scheduler_metrics.h" -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/math/stats.h" #include @@ -22,6 +21,7 @@ namespace srsran { class cell_configuration; struct rach_indication_message; +struct sched_result; ///\brief Handler of scheduler slot metrics for a given cell. class cell_metrics_handler final : public sched_metrics_ue_configurator diff --git a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator.h b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator.h index 9ea20b2643..dbaf6f45f1 100644 --- a/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator.h +++ b/lib/scheduler/pdcch_scheduling/pdcch_resource_allocator.h @@ -3,7 +3,6 @@ #include "../cell/resource_grid.h" #include "../config/ue_configuration.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator.h b/lib/scheduler/pucch_scheduling/pucch_allocator.h index 9178a4f5f5..1646e802cd 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator.h @@ -13,7 +13,6 @@ #include "../cell/resource_grid.h" #include "../config/ue_configuration.h" #include "../ue_context/ue.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { diff --git a/lib/scheduler/support/rb_helper.h b/lib/scheduler/support/rb_helper.h index 5b0cc283b3..a5dac447d4 100644 --- a/lib/scheduler/support/rb_helper.h +++ b/lib/scheduler/support/rb_helper.h @@ -14,7 +14,7 @@ #include "srsran/ran/pdcch/search_space.h" #include "srsran/ran/rnti.h" #include "srsran/scheduler/config/bwp_configuration.h" -#include "srsran/scheduler/vrb_alloc.h" +#include "srsran/scheduler/result/vrb_alloc.h" #include "srsran/support/error_handling.h" namespace srsran { diff --git a/lib/scheduler/support/sched_result_helpers.h b/lib/scheduler/support/sched_result_helpers.h index 9ef6b51ce0..8b7793a7b6 100644 --- a/lib/scheduler/support/sched_result_helpers.h +++ b/lib/scheduler/support/sched_result_helpers.h @@ -11,7 +11,6 @@ #pragma once #include "srsran/scheduler/config/scheduler_expert_config.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { @@ -71,4 +70,4 @@ get_space_left_for_pusch_pdus(const sched_result& result, rnti_t crnti, const sc return std::min(space, space2); } -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/test_doubles/mac/mac_test_messages.h b/tests/test_doubles/mac/mac_test_messages.h index b5887907ea..f8b75ddc32 100644 --- a/tests/test_doubles/mac/mac_test_messages.h +++ b/tests/test_doubles/mac/mac_test_messages.h @@ -13,7 +13,6 @@ #include "srsran/mac/mac_cell_control_information_handler.h" #include "srsran/mac/mac_pdu_handler.h" #include "srsran/scheduler/harq_id.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { diff --git a/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp b/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp index 57b8bb6c4c..e3ccdfc270 100644 --- a/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp +++ b/tests/unittests/mac/dl_sch_pdu_assembler_test.cpp @@ -11,7 +11,7 @@ #include "lib/mac/mac_dl/cell_dl_harq_buffer_pool.h" #include "lib/mac/mac_dl/dl_sch_pdu_assembler.h" #include "mac_test_helpers.h" -#include "srsran/mac/config/mac_config_helpers.h" +#include "srsran/mac/mac_pdu_format.h" #include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/support/bit_encoding.h" #include "srsran/support/executors/manual_task_worker.h" diff --git a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp index 1aaf2ab439..a6cbece92b 100644 --- a/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp +++ b/tests/unittests/scheduler/cell/cell_harq_manager_test.cpp @@ -10,7 +10,6 @@ #include "lib/scheduler/cell/cell_harq_manager.h" #include "srsran/scheduler/result/sched_result.h" -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/test_utils.h" #include diff --git a/tests/unittests/scheduler/multiple_ue_sched_test.cpp b/tests/unittests/scheduler/multiple_ue_sched_test.cpp index 62aec773f6..acb41e0784 100644 --- a/tests/unittests/scheduler/multiple_ue_sched_test.cpp +++ b/tests/unittests/scheduler/multiple_ue_sched_test.cpp @@ -19,7 +19,6 @@ #include "srsran/ran/pdcch/search_space.h" #include "srsran/scheduler/config/logical_channel_config_factory.h" #include "srsran/scheduler/result/dci_info.h" -#include "srsran/scheduler/scheduler_slot_handler.h" #include "srsran/support/test_utils.h" #include #include diff --git a/tests/unittests/scheduler/test_utils/result_test_helpers.h b/tests/unittests/scheduler/test_utils/result_test_helpers.h index a75bd7971a..a9a6170e0d 100644 --- a/tests/unittests/scheduler/test_utils/result_test_helpers.h +++ b/tests/unittests/scheduler/test_utils/result_test_helpers.h @@ -12,7 +12,6 @@ #include "tests/test_doubles/scheduler/scheduler_result_test.h" #include "srsran/scheduler/scheduler_feedback_handler.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { diff --git a/tests/unittests/scheduler/test_utils/scheduler_output_test_helpers.h b/tests/unittests/scheduler/test_utils/scheduler_output_test_helpers.h index 33326ab8d6..3cc07a1718 100644 --- a/tests/unittests/scheduler/test_utils/scheduler_output_test_helpers.h +++ b/tests/unittests/scheduler/test_utils/scheduler_output_test_helpers.h @@ -11,10 +11,12 @@ #pragma once #include "lib/scheduler/cell/resource_grid.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { +struct dl_sched_result; +struct ul_sched_result; + /// Parameters of a grant allocation in the cell resource grid. struct test_grant_info { diff --git a/tests/unittests/scheduler/test_utils/scheduler_test_suite.h b/tests/unittests/scheduler/test_utils/scheduler_test_suite.h index 3e10603e51..a0bfc9342e 100644 --- a/tests/unittests/scheduler/test_utils/scheduler_test_suite.h +++ b/tests/unittests/scheduler/test_utils/scheduler_test_suite.h @@ -17,7 +17,6 @@ #pragma once #include "lib/scheduler/cell/resource_grid.h" -#include "srsran/scheduler/scheduler_slot_handler.h" namespace srsran { From ff3a4254b5a88a16f778a87422e8153ed4b74891 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 12:22:11 +0100 Subject: [PATCH 193/227] sched: fix comments in sched_result.h --- include/srsran/scheduler/result/sched_result.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/srsran/scheduler/result/sched_result.h b/include/srsran/scheduler/result/sched_result.h index 34d6cdc6a0..803f495c22 100644 --- a/include/srsran/scheduler/result/sched_result.h +++ b/include/srsran/scheduler/result/sched_result.h @@ -24,25 +24,18 @@ namespace srsran { struct dl_sched_result { /// Number of DL symbols active for this slot. unsigned nof_dl_symbols; - /// Allocated DL PDCCHs. Includes both SIB, RAR and Data PDCCHs. pdcch_dl_info_list dl_pdcchs; - /// Allocated UL PDCCHs. pdcch_ul_info_list ul_pdcchs; - /// Allocation of SSB and SIBs. dl_broadcast_allocation bc; - /// Allocation of dedicated RARs. static_vector rar_grants; - /// Allocation of Paging messages. static_vector paging_grants; - /// Allocation of dedicated UE messages. static_vector ue_grants; - /// Allocation of CSI-RS messages. static_vector csi_rs; }; @@ -63,8 +56,11 @@ struct ul_sched_result { /// Scheduler decision made for DL and UL in a given slot. struct sched_result { + /// Whether the scheduling for the given slot was successful. bool success; + /// DL allocations for the given slot. dl_sched_result dl; + /// UL allocations for the given slot. ul_sched_result ul; }; From ccd45de809e52c2c75be63bf295fdcbc09e76b2e Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 16:06:12 +0100 Subject: [PATCH 194/227] clang-format --- include/srsran/scheduler/result/sched_result.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/srsran/scheduler/result/sched_result.h b/include/srsran/scheduler/result/sched_result.h index 803f495c22..2eb64d19de 100644 --- a/include/srsran/scheduler/result/sched_result.h +++ b/include/srsran/scheduler/result/sched_result.h @@ -57,7 +57,7 @@ struct ul_sched_result { /// Scheduler decision made for DL and UL in a given slot. struct sched_result { /// Whether the scheduling for the given slot was successful. - bool success; + bool success; /// DL allocations for the given slot. dl_sched_result dl; /// UL allocations for the given slot. From 7b10489aa5e7b4005fcabaa7a9a2c800c12d25b6 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 21:11:30 +0100 Subject: [PATCH 195/227] sched: fix failing unit test for the DL logical channel manager --- .../scheduler/ue_scheduling/logical_channel_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp index 6304b96fd4..a73072f2db 100644 --- a/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/logical_channel_test.cpp @@ -218,9 +218,9 @@ TEST(dl_logical_channel_test, mac_sdu_is_scheduled_if_tb_has_space) // RLC overhead. const unsigned RLC_SEGMENTATION_OVERHEAD = 4; unsigned req_bytes = get_mac_sdu_required_bytes(rem_sdu_size); - if (req_bytes == 256) { + if (req_bytes == 258) { // Note: account for ambiguity in transition between MAC subheader sizes. - req_bytes++; + req_bytes = 259; } ASSERT_EQ(req_bytes, lch_mng.total_pending_bytes() - RLC_SEGMENTATION_OVERHEAD) << "incorrect calculation of remaining pending tx bytes"; From ad3dbc9d0e43c4a76ee5bb11f0defa36ace371d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 16 Dec 2024 15:49:24 +0100 Subject: [PATCH 196/227] ci,infra: change retina runner --- .gitlab/ci-shared/e2e.yml | 10 +++++----- .gitlab/ci/e2e.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitlab/ci-shared/e2e.yml b/.gitlab/ci-shared/e2e.yml index b458f3a430..57e53d712e 100644 --- a/.gitlab/ci-shared/e2e.yml +++ b/.gitlab/ci-shared/e2e.yml @@ -69,16 +69,16 @@ variables: TRANSFER_METER_FREQUENCY: 5s ARTIFACT_COMPRESSION_LEVEL: slowest RUNNER_AFTER_SCRIPT_TIMEOUT: 1m - KUBERNETES_CPU_REQUEST: 2 - KUBERNETES_CPU_LIMIT: 2 + KUBERNETES_CPU_REQUEST: 1 + KUBERNETES_CPU_LIMIT: 1 KUBERNETES_MEMORY_REQUEST: 2Gi KUBERNETES_MEMORY_LIMIT: 2Gi - KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "20G" - KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "20G" + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "10G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "10G" <<: *setup_kube_variables GROUP: zmq tags: - - "${RETINA_TAG}" + - retina-e2e-amd64 artifacts: paths: - ${SRSRANDIR}/tests/e2e/log diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index b6ca7925bc..ab47749162 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -573,7 +573,7 @@ retina setup: name: ${RETINA_REGISTRY_PREFIX}/launcher:${RETINA_VERSION} entrypoint: ["/bin/sh", "-c"] tags: - - "${RETINA_TAG}" + - retina-e2e-amd64 script: - | retina-garbage-collector --mode demolition From 33861e7228b17318433fc3897a833c12c77eba0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Mon, 16 Dec 2024 17:55:26 +0100 Subject: [PATCH 197/227] ci: make custom e2e non-interruptible --- .gitlab/ci/e2e.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index ab47749162..d64d5ec142 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -79,6 +79,7 @@ custom e2e: - *retina-needs - custom build - build trx driver + interruptible: false # Web jobs are standalone ################################################################################ # ZMQ @@ -164,7 +165,7 @@ amari 1UE 4x4 mimo: amari 4UE deb: extends: .zmq rules: - - if: $CI_DESCRIPTION =~ /Nightly E2E Tests OpenSource/ + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests OpenSource/ variables: TESTBED: "zmq_deb" MARKERS: "smoke" From 451c5a7ee2d457e25470ae22b790e306880ce1fc Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Tue, 17 Dec 2024 09:22:04 +0100 Subject: [PATCH 198/227] ci: add cu-cp inactivity timer to ci test configuration --- .gitlab/ci/e2e/.env | 2 +- tests/e2e/tests/steps/configuration.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 0d13a79dd8..a5d83e4afe 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.58.7 +RETINA_VERSION=0.58.8 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/tests/steps/configuration.py b/tests/e2e/tests/steps/configuration.py index 4000d77597..e650798781 100644 --- a/tests/e2e/tests/steps/configuration.py +++ b/tests/e2e/tests/steps/configuration.py @@ -48,6 +48,7 @@ def configure_test_parameters( enable_drx: bool = False, pdsch_mcs_table: str = "qam256", pusch_mcs_table: str = "qam256", + cu_cp_inactivity_timer: int = -1, ): """ Configure test parameters @@ -90,6 +91,7 @@ def configure_test_parameters( "enable_drx": enable_drx, "pdsch_mcs_table": pdsch_mcs_table, "pusch_mcs_table": pusch_mcs_table, + "cu_cp_inactivity_timer": cu_cp_inactivity_timer, }, }, "5gc": {"parameters": {"ims_mode": ims_mode}}, From 3e1caf05c36faa5f89b6ba04b0a44974e04742b5 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 16:00:53 +0100 Subject: [PATCH 199/227] sched: use uci allocator for dedicated UCI allocation in fallback scheduler --- .../ue_scheduling/ue_fallback_scheduler.cpp | 21 ++++++++++++++----- .../ue_scheduling/ue_fallback_scheduler.h | 7 +++++-- .../ue_scheduling/ue_scheduler_impl.cpp | 7 ++++++- .../ue_scheduling/fallback_scheduler_test.cpp | 2 +- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index da9e42d677..7a0937d424 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -26,11 +26,13 @@ ue_fallback_scheduler::ue_fallback_scheduler(const scheduler_ue_expert_config& e const cell_configuration& cell_cfg_, pdcch_resource_allocator& pdcch_sch_, pucch_allocator& pucch_alloc_, + uci_allocator& uci_alloc_, ue_repository& ues_) : expert_cfg(expert_cfg_), cell_cfg(cell_cfg_), pdcch_sch(pdcch_sch_), pucch_alloc(pucch_alloc_), + uci_alloc(uci_alloc_), ues(ues_), initial_active_dl_bwp(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params), ss_cfg(cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common @@ -413,6 +415,7 @@ static std::pair, std::optional> allocate_ue_fallback_pucch(ue& u, cell_resource_allocator& res_alloc, pucch_allocator& pucch_alloc, + uci_allocator& uci_alloc, const pdcch_dl_information& pdcch_info, span k1_values, slot_point pdsch_slot, @@ -420,8 +423,19 @@ allocate_ue_fallback_pucch(ue& u, bool common_alloc, bool ded_alloc) { + srsran_assert(ded_alloc or common_alloc, "Invalid params passed to this function"); const unsigned pdsch_delay = pdsch_slot - res_alloc.slot_tx(); + if (not common_alloc and ded_alloc) { + // UE dedicated-only PUCCH allocation. + std::optional uci = + uci_alloc.alloc_uci_harq_ue(res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_values); + if (uci.has_value()) { + return std::make_pair(uci.value().pucch_res_indicator, uci.value().k1); + } + return std::make_pair(std::nullopt, std::nullopt); + } + std::optional last_valid_k1; for (uint8_t k1_candidate : k1_values) { if (pdsch_slot + k1_candidate <= min_ack_slot) { @@ -439,13 +453,9 @@ allocate_ue_fallback_pucch(ue& u, if (common_alloc and ded_alloc) { pucch_res_indicator = pucch_alloc.alloc_common_and_ded_harq_res( res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate, pdcch_info); - } else if (common_alloc) { - pucch_res_indicator = - pucch_alloc.alloc_common_pucch_harq_ack_ue(res_alloc, u.crnti, pdsch_delay, k1_candidate, pdcch_info); } else { - srsran_assert(ded_alloc, "Invalid params passed to this function"); pucch_res_indicator = - pucch_alloc.alloc_ded_pucch_harq_ack_ue(res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate); + pucch_alloc.alloc_common_pucch_harq_ack_ue(res_alloc, u.crnti, pdsch_delay, k1_candidate, pdcch_info); } if (pucch_res_indicator.has_value()) { return std::make_pair(*pucch_res_indicator, k1_candidate); @@ -598,6 +608,7 @@ ue_fallback_scheduler::alloc_grant(ue& u, auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, res_alloc, pucch_alloc, + uci_alloc, *pdcch, dci_1_0_k1_values, pdsch_alloc.slot, diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index f6c268d1ab..c2e6528dcc 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -24,8 +24,10 @@ class ue_fallback_scheduler explicit ue_fallback_scheduler(const scheduler_ue_expert_config& expert_cfg_, const cell_configuration& cell_cfg_, pdcch_resource_allocator& pdcch_sch_, - pucch_allocator& pucch_alloc_, - ue_repository& ues_); + // TODO: Remove and depend only on pucch_alloc + pucch_allocator& pucch_alloc_, + uci_allocator& uci_alloc_, + ue_repository& ues_); /// Handles DL buffer state reported by upper layers. /// \param[in] ue_index UE's DU Index for which SRB0 message needs to be scheduled. @@ -195,6 +197,7 @@ class ue_fallback_scheduler unsigned sched_attempts_cnt = 0; pdcch_resource_allocator& pdcch_sch; pucch_allocator& pucch_alloc; + uci_allocator& uci_alloc; ue_repository& ues; bwp_configuration initial_active_dl_bwp; diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 1a9ddb68f1..9fdd853b53 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -250,7 +250,12 @@ ue_scheduler_impl::cell::cell(const scheduler_ue_expert_config& expert_cfg, cell_harq_manager::DEFAULT_ACK_TIMEOUT_SLOTS, params.cell_res_alloc->cfg.ntn_cs_koffset), uci_sched(params.cell_res_alloc->cfg, *params.uci_alloc, ues), - fallback_sched(expert_cfg, params.cell_res_alloc->cfg, *params.pdcch_sched, *params.pucch_alloc, ues), + fallback_sched(expert_cfg, + params.cell_res_alloc->cfg, + *params.pdcch_sched, + *params.pucch_alloc, + *params.uci_alloc, + ues), slice_sched(params.cell_res_alloc->cfg, ues), srs_sched(params.cell_res_alloc->cfg, ues) { diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 579d624f65..fcfee95ae3 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -97,7 +97,7 @@ struct test_bench { builder_params{builder_params_}, cell_cfg{*[&]() { return cfg_mng.add_cell(cell_req); }()}, ue_alloc(expert_cfg, ue_db, srslog::fetch_basic_logger("SCHED", true)), - fallback_sched(expert_cfg, cell_cfg, pdcch_sch, pucch_alloc, ue_db), + fallback_sched(expert_cfg, cell_cfg, pdcch_sch, pucch_alloc, uci_alloc, ue_db), csi_rs_sched(cell_cfg) { srslog::fetch_basic_logger("SCHED", true).set_level(srslog::basic_levels::debug); From 3140bf2df6f02b18c03f6c779b92fc84903ab19b Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 16:14:59 +0100 Subject: [PATCH 200/227] sched: fix comment --- lib/scheduler/ue_scheduling/ue_fallback_scheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index c2e6528dcc..7716653418 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -24,7 +24,7 @@ class ue_fallback_scheduler explicit ue_fallback_scheduler(const scheduler_ue_expert_config& expert_cfg_, const cell_configuration& cell_cfg_, pdcch_resource_allocator& pdcch_sch_, - // TODO: Remove and depend only on pucch_alloc + // TODO: Remove pucch_alloc and depend only on uci_alloc pucch_allocator& pucch_alloc_, uci_allocator& uci_alloc_, ue_repository& ues_); From ad330ec37670bfe70b25f37a79ee829766e6ae0a Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 17 Dec 2024 11:54:44 +0100 Subject: [PATCH 201/227] sched: fix harq-bit-index setting during ue fallback --- .../ue_scheduling/ue_fallback_scheduler.cpp | 96 +++++++++---------- .../ue_scheduling/ue_fallback_scheduler.h | 3 +- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp index 7a0937d424..44face07bf 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.cpp @@ -411,17 +411,16 @@ static dci_dl_rnti_config_type get_dci_type(const ue& u, const std::optional, std::optional> -allocate_ue_fallback_pucch(ue& u, - cell_resource_allocator& res_alloc, - pucch_allocator& pucch_alloc, - uci_allocator& uci_alloc, - const pdcch_dl_information& pdcch_info, - span k1_values, - slot_point pdsch_slot, - slot_point min_ack_slot, - bool common_alloc, - bool ded_alloc) +static std::optional allocate_ue_fallback_pucch(ue& u, + cell_resource_allocator& res_alloc, + pucch_allocator& pucch_alloc, + uci_allocator& uci_alloc, + const pdcch_dl_information& pdcch_info, + span k1_values, + slot_point pdsch_slot, + slot_point min_ack_slot, + bool common_alloc, + bool ded_alloc) { srsran_assert(ded_alloc or common_alloc, "Invalid params passed to this function"); const unsigned pdsch_delay = pdsch_slot - res_alloc.slot_tx(); @@ -430,10 +429,7 @@ allocate_ue_fallback_pucch(ue& u, // UE dedicated-only PUCCH allocation. std::optional uci = uci_alloc.alloc_uci_harq_ue(res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_values); - if (uci.has_value()) { - return std::make_pair(uci.value().pucch_res_indicator, uci.value().k1); - } - return std::make_pair(std::nullopt, std::nullopt); + return uci; } std::optional last_valid_k1; @@ -450,7 +446,7 @@ allocate_ue_fallback_pucch(ue& u, last_valid_k1 = k1_candidate; std::optional pucch_res_indicator; - if (common_alloc and ded_alloc) { + if (ded_alloc) { pucch_res_indicator = pucch_alloc.alloc_common_and_ded_harq_res( res_alloc, u.crnti, u.get_pcell().cfg(), pdsch_delay, k1_candidate, pdcch_info); } else { @@ -458,10 +454,13 @@ allocate_ue_fallback_pucch(ue& u, pucch_alloc.alloc_common_pucch_harq_ack_ue(res_alloc, u.crnti, pdsch_delay, k1_candidate, pdcch_info); } if (pucch_res_indicator.has_value()) { - return std::make_pair(*pucch_res_indicator, k1_candidate); + return uci_allocation{k1_candidate, 0, pucch_res_indicator}; } } - return std::make_pair(std::nullopt, last_valid_k1); + if (last_valid_k1.has_value()) { + return uci_allocation{last_valid_k1.value(), 0, std::nullopt}; + } + return std::nullopt; } std::optional @@ -605,18 +604,18 @@ ue_fallback_scheduler::alloc_grant(ue& u, // don't use the PUCCH ded. resources. const bool use_common = not u.is_reconfig_ongoing(); const bool use_dedicated = u.is_reconfig_ongoing() or (u.ue_cfg_dedicated()->is_ue_cfg_complete() and is_retx); - auto [pucch_res_indicator, chosen_k1] = allocate_ue_fallback_pucch(u, - res_alloc, - pucch_alloc, - uci_alloc, - *pdcch, - dci_1_0_k1_values, - pdsch_alloc.slot, - most_recent_ack_slot, - use_common, - use_dedicated); - if (not pucch_res_indicator.has_value()) { - if (chosen_k1.has_value()) { + std::optional uci = allocate_ue_fallback_pucch(u, + res_alloc, + pucch_alloc, + uci_alloc, + *pdcch, + dci_1_0_k1_values, + pdsch_alloc.slot, + most_recent_ack_slot, + use_common, + use_dedicated); + if (not uci.has_value() or not uci.value().pucch_res_indicator.has_value()) { + if (uci.has_value() and not uci.value().pucch_res_indicator.has_value()) { // Note: Only log if there was at least one valid k1 candidate for this PDSCH slot. logger.debug("rnti={}: Failed to allocate fallback PDSCH for slot={}. Cause: No space in PUCCH", u.crnti, @@ -639,9 +638,8 @@ ue_fallback_scheduler::alloc_grant(ue& u, *pdcch, dci_type, pdsch_alloc.result.dl.ue_grants.emplace_back(), - pucch_res_indicator.value(), + uci.value(), pdsch_time_res, - chosen_k1.value(), mcs_idx, ue_grant_crbs, pdsch_cfg, @@ -747,23 +745,20 @@ dl_harq_process_handle ue_fallback_scheduler::fill_dl_srb_grant(ue& pdcch_dl_information& pdcch, dci_dl_rnti_config_type dci_type, dl_msg_alloc& msg, - unsigned pucch_res_indicator, - unsigned pdsch_time_res, - unsigned k1, - sch_mcs_index mcs_idx, - const crb_interval& ue_grant_crbs, - const pdsch_config_params& pdsch_params, - unsigned tbs_bytes, - bool is_retx) + const uci_allocation& uci, + unsigned pdsch_time_res, + sch_mcs_index mcs_idx, + const crb_interval& ue_grant_crbs, + const pdsch_config_params& pdsch_params, + unsigned tbs_bytes, + bool is_retx) { // Allocate DL HARQ. // NOTE: We do not multiplex the SRB1 PUCCH with existing PUCCH HARQs, thus both DAI and HARQ-ACK bit index are 0. - static constexpr uint8_t srb_dai = 0; if (not is_retx) { - h_dl = u.get_pcell().harqs.alloc_dl_harq(pdsch_slot, k1, expert_cfg.max_nof_harq_retxs, srb_dai); + h_dl = u.get_pcell().harqs.alloc_dl_harq(pdsch_slot, uci.k1, expert_cfg.max_nof_harq_retxs, uci.harq_bit_idx); } else { - const unsigned harq_bit_idx = 0U; - bool result = h_dl->new_retx(pdsch_slot, k1, harq_bit_idx); + bool result = h_dl->new_retx(pdsch_slot, uci.k1, uci.harq_bit_idx); srsran_sanity_check(result, "Unable to allocate HARQ retx"); } @@ -775,22 +770,23 @@ dl_harq_process_handle ue_fallback_scheduler::fill_dl_srb_grant(ue& cell_cfg.dl_cfg_common.init_dl_bwp, ue_grant_crbs, pdsch_time_res, - k1, - pucch_res_indicator, + uci.k1, + uci.pucch_res_indicator.value(), mcs_idx, msg4_rv, *h_dl); break; } case dci_dl_rnti_config_type::c_rnti_f1_0: { + const unsigned DAI_MOD = 4U; build_dci_f1_0_c_rnti(pdcch.dci, u.get_pcell().cfg().search_space(pdcch.ctx.context.ss_id), cell_cfg.dl_cfg_common.init_dl_bwp, ue_grant_crbs, pdsch_time_res, - k1, - pucch_res_indicator, - srb_dai, + uci.k1, + uci.pucch_res_indicator.value(), + uci.harq_bit_idx % DAI_MOD, mcs_idx, msg4_rv, *h_dl); @@ -803,7 +799,7 @@ dl_harq_process_handle ue_fallback_scheduler::fill_dl_srb_grant(ue& // Fill PDSCH PDU. msg.context.ue_index = u.ue_index; - msg.context.k1 = k1; + msg.context.k1 = uci.k1; msg.context.ss_id = pdcch.ctx.context.ss_id; msg.context.nof_retxs = h_dl->nof_retxs(); msg.context.olla_offset = 0; diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index 7716653418..f67d5d2a40 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -124,9 +124,8 @@ class ue_fallback_scheduler pdcch_dl_information& pdcch, dci_dl_rnti_config_type dci_type, dl_msg_alloc& msg, - unsigned pucch_res_indicator, + const uci_allocation& uci, unsigned pdsch_time_res, - unsigned k1, sch_mcs_index mcs_idx, const crb_interval& ue_grant_crbs, const pdsch_config_params& pdsch_params, From 2b23f95e8079f0e45cf1a2e11eae983ea6d6e159 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 17 Dec 2024 12:19:42 +0100 Subject: [PATCH 202/227] sched: fix failing slice_scheduler_test --- tests/unittests/scheduler/slicing/slice_scheduler_test.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index cfe5173c26..e7a8e42935 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -329,6 +329,7 @@ TEST_F(rb_ratio_slice_scheduler_test, run_slot(); auto next_dl_slice = slice_sched.get_next_dl_candidate(); + ASSERT_TRUE(next_dl_slice.has_value()); // Default SRB slice has very high priority. We ignore it as candidate for this test. if (next_dl_slice->id() == default_srb_slice_id) { next_dl_slice = slice_sched.get_next_dl_candidate(); @@ -340,9 +341,6 @@ TEST_F(rb_ratio_slice_scheduler_test, // No more slices to schedule. next_dl_slice = slice_sched.get_next_dl_candidate(); - if (next_dl_slice->id() == default_srb_slice_id) { - next_dl_slice = slice_sched.get_next_dl_candidate(); - } ASSERT_FALSE(next_dl_slice.has_value()); } From 2f04478016e2a01e74b2fccccc0805fd64f55d09 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 17 Dec 2024 09:31:52 +0100 Subject: [PATCH 203/227] sched: fix UL DCI size derivation --- lib/scheduler/config/ue_configuration.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/scheduler/config/ue_configuration.cpp b/lib/scheduler/config/ue_configuration.cpp index a3b06030ff..d6acd7b1e8 100644 --- a/lib/scheduler/config/ue_configuration.cpp +++ b/lib/scheduler/config/ue_configuration.cpp @@ -222,10 +222,10 @@ static dci_size_config get_dci_size_config(const ue_cell_configuration& ue_cell_ if (opt_pusch_sc_cfg.has_value() and opt_pusch_sc_cfg.value().cbg_tx.has_value()) { dci_sz_cfg.max_cbg_tb_pusch = static_cast(opt_pusch_sc_cfg.value().cbg_tx.value().max_cgb_per_tb); } - if (opt_pusch_cfg->tx_cfg.has_value() && - std::holds_alternative(opt_pusch_cfg->tx_cfg.value())) { - // TODO: Set value based on maxMIMO-Layers config in PUSCH-ServingCellConfig or UE capability. - dci_sz_cfg.pusch_max_layers = 1; + dci_sz_cfg.pusch_max_layers = 1; + if (opt_pusch_cfg->tx_cfg.has_value() and + std::holds_alternative(opt_ul_cfg->init_ul_bwp.pusch_cfg.value().tx_cfg.value())) { + dci_sz_cfg.pusch_max_layers = std::get(opt_pusch_cfg->tx_cfg.value()).max_rank.value(); } } if (dci_sz_cfg.pdsch_harq_ack_cb == pdsch_harq_ack_codebook::dynamic) { From a8f98cf25d3e9bd3b413c47cc6b68cd5f11893bb Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 17 Dec 2024 09:39:02 +0100 Subject: [PATCH 204/227] sched: set PUSCH MCS table to 256qam as a default --- apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h | 2 +- .../o_du_high/du_high/du_high_config_cli11_schema.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h index efd405f322..caebde4825 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h @@ -185,7 +185,7 @@ struct du_high_unit_pusch_config { /// 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; + pusch_mcs_table mcs_table = pusch_mcs_table::qam256; /// \c msg3-DeltaPreamble, TS 38.331. Values: {-1,...,6}. int msg3_delta_preamble = 6; /// \c p0-NominalWithGrant, TS 38.331. Value in dBm. Only even values allowed within {-202,...,24}. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index d324efc6eb..f3f28fad53 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -666,7 +666,7 @@ static void configure_cli11_pusch_args(CLI::App& app, du_high_unit_pusch_config& } }, "MCS table to use PUSCH") - ->default_str("qam64") + ->default_str("qam256") ->check(CLI::IsMember({"qam64", "qam256"}, CLI::ignore_case)); add_option(app, "--max_rank", From 8e2344d04613572b6a776ac9bc24605b01af5c68 Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 17 Dec 2024 12:09:21 +0100 Subject: [PATCH 205/227] use to_string conversion for PUSCH MCS table --- .../du_high/du_high_config_cli11_schema.cpp | 2 +- include/srsran/ran/pusch/pusch_mcs.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index f3f28fad53..82655af1f6 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -666,7 +666,7 @@ static void configure_cli11_pusch_args(CLI::App& app, du_high_unit_pusch_config& } }, "MCS table to use PUSCH") - ->default_str("qam256") + ->default_str(pusch_mcs_table_to_string(pusch_params.mcs_table)) ->check(CLI::IsMember({"qam64", "qam256"}, CLI::ignore_case)); add_option(app, "--max_rank", diff --git a/include/srsran/ran/pusch/pusch_mcs.h b/include/srsran/ran/pusch/pusch_mcs.h index 92ddb908dd..d7f434d978 100644 --- a/include/srsran/ran/pusch/pusch_mcs.h +++ b/include/srsran/ran/pusch/pusch_mcs.h @@ -27,6 +27,22 @@ enum class pusch_mcs_table { qam64LowSe = 2, }; +/// Convert PUSCH MCS table to string. +constexpr const char* pusch_mcs_table_to_string(pusch_mcs_table table) +{ + switch (table) { + case pusch_mcs_table::qam64: + return "qam64"; + case pusch_mcs_table::qam256: + return "qam256"; + case pusch_mcs_table::qam64LowSe: + return "qam64LowSe"; + default: + break; + } + return "invalid"; +} + /// \brief Gets the Modulation and Coding Scheme configuration for PUSCH. /// /// Reserved target code rates and spectral efficiencies are indicated with zero. From 6795e3c8780f3ccf80f0898f6eb0e19b20954f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Tue, 17 Dec 2024 10:16:16 +0100 Subject: [PATCH 206/227] ci: increase timeout --- .gitlab/ci/e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index d64d5ec142..ceb171cd0a 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -217,6 +217,7 @@ amari 8UE: variables: MARKERS: "zmq and not smoke" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=False gnb.all.enable_integrity_protection=True" + timeout: 4h parallel: matrix: - KEYWORDS: From b7b6161831fa48dddf759f844f90ffea16639ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Fri, 13 Dec 2024 11:54:05 +0100 Subject: [PATCH 207/227] ci: format requests --- .gitlab/ci/e2e/retina_request_android_callbox.yml | 2 +- .gitlab/ci/e2e/retina_request_android_n300.yml | 2 +- .gitlab/ci/e2e/retina_request_android_x300.yml | 2 +- .gitlab/ci/e2e/retina_request_test_mode.yml | 4 ++-- .gitlab/ci/e2e/retina_request_test_mode_acc100.yml | 4 ++-- .gitlab/ci/e2e/retina_request_zmq.yml | 6 +++--- .gitlab/ci/e2e/retina_request_zmq_cudu.yml | 6 +++--- .gitlab/ci/e2e/retina_request_zmq_deb.yml | 6 +++--- .gitlab/ci/e2e/retina_request_zmq_ric.yml | 6 +++--- .gitlab/ci/e2e/retina_request_zmq_smoke.yml | 6 +++--- .gitlab/ci/e2e/retina_request_zmq_uesim.yml | 8 ++++---- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.gitlab/ci/e2e/retina_request_android_callbox.yml b/.gitlab/ci/e2e/retina_request_android_callbox.yml index 93971c9554..707c890f67 100644 --- a/.gitlab/ci/e2e/retina_request_android_callbox.yml +++ b/.gitlab/ci/e2e/retina_request_android_callbox.yml @@ -38,7 +38,7 @@ ephemeral-storage: requests: "6G" limits: "6G" - labels: + labels: - kubernetes.io/hostname=sdr6 resources: - type: sdr diff --git a/.gitlab/ci/e2e/retina_request_android_n300.yml b/.gitlab/ci/e2e/retina_request_android_n300.yml index 5fb8cf921f..f8a3b77082 100644 --- a/.gitlab/ci/e2e/retina_request_android_n300.yml +++ b/.gitlab/ci/e2e/retina_request_android_n300.yml @@ -38,7 +38,7 @@ ephemeral-storage: requests: "6G" limits: "6G" - labels: + labels: - kubernetes.io/hostname=sdr6 resources: - type: sdr diff --git a/.gitlab/ci/e2e/retina_request_android_x300.yml b/.gitlab/ci/e2e/retina_request_android_x300.yml index ad8cda89bb..1980886b2d 100644 --- a/.gitlab/ci/e2e/retina_request_android_x300.yml +++ b/.gitlab/ci/e2e/retina_request_android_x300.yml @@ -38,7 +38,7 @@ ephemeral-storage: requests: "6G" limits: "6G" - labels: + labels: - kubernetes.io/hostname=sdr6 resources: - type: sdr diff --git a/.gitlab/ci/e2e/retina_request_test_mode.yml b/.gitlab/ci/e2e/retina_request_test_mode.yml index d12c59a545..840e156f9b 100644 --- a/.gitlab/ci/e2e/retina_request_test_mode.yml +++ b/.gitlab/ci/e2e/retina_request_test_mode.yml @@ -9,7 +9,7 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -42,5 +42,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml b/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml index 2f579aa22b..c3c7595b4c 100644 --- a/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml +++ b/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml @@ -45,5 +45,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_0} \ No newline at end of file + labels: + - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq.yml b/.gitlab/ci/e2e/retina_request_zmq.yml index 3695b2bb00..0956886350 100644 --- a/.gitlab/ci/e2e/retina_request_zmq.yml +++ b/.gitlab/ci/e2e/retina_request_zmq.yml @@ -9,7 +9,7 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} nof_ports: 64 requirements: @@ -35,7 +35,7 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -71,5 +71,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_cudu.yml b/.gitlab/ci/e2e/retina_request_zmq_cudu.yml index 8aa9318a95..7423499970 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_cudu.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_cudu.yml @@ -9,7 +9,7 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} nof_ports: 64 requirements: @@ -35,7 +35,7 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srscudu:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -72,5 +72,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_deb.yml b/.gitlab/ci/e2e/retina_request_zmq_deb.yml index 253f1910c5..22f56fbdef 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_deb.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_deb.yml @@ -9,7 +9,7 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} nof_ports: 4 requirements: @@ -35,7 +35,7 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/agent-ubuntu-${UBUNTU_VERSION}:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -69,5 +69,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_ric.yml b/.gitlab/ci/e2e/retina_request_zmq_ric.yml index 458afcc7c5..0049e7b907 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_ric.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_ric.yml @@ -30,7 +30,7 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} requirements: arch: amd64 @@ -66,7 +66,7 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} - name: flexric-ric @@ -83,5 +83,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/flexric:${FLEXRIC_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_0} diff --git a/.gitlab/ci/e2e/retina_request_zmq_smoke.yml b/.gitlab/ci/e2e/retina_request_zmq_smoke.yml index 65c52c8dd7..66292d777a 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_smoke.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_smoke.yml @@ -9,7 +9,7 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_1} nof_ports: 4 requirements: @@ -35,7 +35,7 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_1} requirements: arch: amd64 @@ -71,5 +71,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: + labels: - ${ZMQ_HOSTLABEL_1} diff --git a/.gitlab/ci/e2e/retina_request_zmq_uesim.yml b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml index df4b3ea154..0a0a05f5aa 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_uesim.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml @@ -10,7 +10,7 @@ type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue-remote:${RETINA_VERSION} taints: ["machine=srskit2"] - labels: + labels: - ${ZMQ_HOSTLABEL_1} nof_ports: 32 requirements: @@ -37,7 +37,7 @@ type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} taints: ["machine=srskit2"] - labels: + labels: - ${ZMQ_HOSTLABEL_1} force_external_ip: true requirements: @@ -74,5 +74,5 @@ requests: "6G" limits: "6G" image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: - - ${ZMQ_HOSTLABEL_1} \ No newline at end of file + labels: + - ${ZMQ_HOSTLABEL_1} From 739048931365de710335daf8d10f5d6f052fdeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Thu, 12 Dec 2024 13:58:09 +0100 Subject: [PATCH 208/227] ci: add mimo to iperf smoke tests --- tests/e2e/tests/iperf.py | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 63452f8d9d..23a106dcba 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -522,21 +522,13 @@ def test_zmq_4x4_mimo( @mark.parametrize( - "direction", + "direction, nof_antennas", ( - param(IPerfDir.DOWNLINK, id="downlink", marks=mark.downlink), - param(IPerfDir.UPLINK, id="uplink", marks=mark.uplink), - param(IPerfDir.BIDIRECTIONAL, id="bidirectional", marks=mark.bidirectional), + param(IPerfDir.DOWNLINK, 1, id="downlink", marks=mark.downlink), + param(IPerfDir.UPLINK, 1, id="uplink", marks=mark.uplink), + param(IPerfDir.BIDIRECTIONAL, 4, id="bidirectional 4x4 mimo", marks=mark.bidirectional), ), ) -@mark.parametrize( - "protocol", - (param(IPerfProto.UDP, id="udp", marks=mark.udp),), -) -@mark.parametrize( - "band, common_scs, bandwidth, bitrate", - (param(41, 30, 20, LOW_BITRATE, id=ZMQ_ID),), -) @mark.zmq @mark.smoke # pylint: disable=too-many-arguments,too-many-positional-arguments @@ -546,12 +538,8 @@ def test_smoke( ue_4: Tuple[UEStub, ...], fivegc: FiveGCStub, gnb: GNBStub, - band: int, - common_scs: int, - bandwidth: int, - bitrate: int, - protocol: IPerfProto, direction: IPerfDir, + nof_antennas: int, ): """ ZMQ IPerfs @@ -563,14 +551,16 @@ def test_smoke( ue_array=ue_4, gnb=gnb, fivegc=fivegc, - band=band, - common_scs=common_scs, - bandwidth=bandwidth, + band=41, + common_scs=30, + bandwidth=20, sample_rate=None, # default from testbed iperf_duration=TINY_DURATION, - bitrate=bitrate, - protocol=protocol, + bitrate=LOW_BITRATE, + protocol=IPerfProto.UDP, direction=direction, + nof_antennas_dl=nof_antennas, + nof_antennas_ul=nof_antennas, global_timing_advance=0, time_alignment_calibration=0, always_download_artifacts=False, From 9873a98edb45b3973fbddd2f5f32b4d1a89760fb Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Mon, 16 Dec 2024 17:54:53 +0100 Subject: [PATCH 209/227] mac: support pucch format 3 in pucch_allocator --- .../srsran/ran/pucch/pucch_configuration.h | 2 +- include/srsran/ran/pucch/pucch_info.h | 38 + .../pucch_scheduling/pucch_allocator_impl.cpp | 722 ++++++++++++------ .../pucch_scheduling/pucch_allocator_impl.h | 34 +- 4 files changed, 544 insertions(+), 252 deletions(-) diff --git a/include/srsran/ran/pucch/pucch_configuration.h b/include/srsran/ran/pucch/pucch_configuration.h index af14b24147..edf2619d1f 100644 --- a/include/srsran/ran/pucch/pucch_configuration.h +++ b/include/srsran/ran/pucch/pucch_configuration.h @@ -118,7 +118,7 @@ struct pucch_format_1_cfg { bool operator!=(const pucch_format_1_cfg& rhs) const { return !(rhs == *this); } }; -/// Configuration for \c PUCCH-format2, in \c PUCCH-Config, TS 38.331. +/// Configuration for \c PUCCH-format2 or \c PUCCH-format3, in \c PUCCH-Config, TS 38.331. struct pucch_format_2_3_cfg { uint8_t nof_prbs; uint8_t nof_symbols; diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index 4e422371f6..68c32e843a 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -193,6 +193,44 @@ unsigned get_pucch_format3_max_nof_prbs(unsigned nof_pay bool additional_dmrs, bool pi2_bpsk); +/// \brief Calculates the num. of PRBs (capped to the configured max nof PRBs) given the PUCCH Format 3 payload size. +/// +/// With respect to \ref get_pucch_format3_max_nof_prbs, this function caps the number of PRBs to the value configured +/// for PUCCH resource Format 3, which can be less than 16. Note that the returned number of PRBs might not be enough to +/// allocate the payload size. +/// +/// \param[in] nof_payload_bits Total number of payload bits. +/// \param[in] max_nof_prbs Maximum PUCCH format 3 bandwidth in PRB; it corresponds to \c nrofPRBs, part of +/// \c PUCCH-format3, TS 38.331. +/// \param[in] nof_symbols Transmission duration in symbols. +/// \param[in] max_code_rate Maximum code rate for PUCCH format 3; it corresponds to \c maxCodeRate, part of +/// \c PUCCH-FormatConfig, TS 38.331. +/// \param[in] intraslot_freq_hopping Flag indicating if intra slot frequency hopping is enabled. +/// \param[in] additional_dmrs Flag indicating if additional DM-RS is enabled. +/// \param[in] pi2_bpsk Flag indicating if pi/2-BPSK modulation is used. +/// \return The number of PRBs for the PUCCH format 3 resource. Note that the returned number of PRBs might not be +/// enough to allocate the payload size; it's the caller's responsibility to perform this check. +inline unsigned get_pucch_format3_nof_prbs(unsigned nof_payload_bits, + unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) +{ + if (nof_payload_bits == 0 or nof_symbols == 0) { + return 0; + } + if (max_nof_prbs == 1) { + return 1; + } + + const unsigned estimated_nof_prbs = get_pucch_format3_max_nof_prbs( + nof_payload_bits, nof_symbols, max_code_rate, intraslot_freq_hopping, additional_dmrs, pi2_bpsk); + + return std::min(estimated_nof_prbs, max_nof_prbs); +} + /// \brief Calculates the maximum payload for a PUCCH Format 3 transmission. /// \param[in] max_nof_prbs Transmission bandwidth in PRBs. /// \param[in] nof_symbols Transmission duration in symbols. diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 5ae8af66fb..d5f0c2dcd1 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -23,7 +23,7 @@ using namespace srsran; static unsigned get_n_id0_scrambling(const ue_cell_configuration& ue_cell_cfg, unsigned cell_pci) { - // As per TS 38.211, Section 6.4.1.3.2.1, "N_{ID}^0 is given by the higher-layer parameter scramblingID0 in the + // As per TS 38.211, Section 6.4.1.3.2.1, N_{ID}^0 is given by the higher-layer parameter scramblingID0 in the // DMRS-UplinkConfig IE if provided and by N_{ID}^{cell} otherwise. If a UE is configured with both // dmrs-UplinkForPUSCH-MappingTypeA and dmrs-UplinkForPUSCH-MappingTypeB, scramblingID0 is obtained from // dmrs-UplinkForPUSCH-MappingTypeB. @@ -129,9 +129,10 @@ std::optional pucch_allocator_impl::alloc_common_pucch_harq_ack_ue(cel return std::nullopt; } - // If there are existing PUCCH grants that are either F2 for CSI or F1 for SR, allocate the PUCCH common grant anyway - // without multiplexing it with the existing one. Otherwise, if the existing grant is F1 for HARQ-ACK, do not allocate - // on the same slot. + // TODO: why F2 or F1? + // If there are existing PUCCH grants that are either F2 for CSI or F1 for SR, allocate the PUCCH common + // grant anyway without multiplexing it with the existing one. Otherwise, if the existing grant is F1 for HARQ-ACK, + // do not allocate on the same slot. const bool has_existing_ded_harq_grants = grants_ue_it != pucch_grants_slot.end() and grants_ue_it->pucch_grants.harq_resource.has_value(); const bool has_existing_common_grants = grants_ue_it != pucch_grants_slot.end() and grants_ue_it->has_common_pucch; @@ -207,6 +208,7 @@ std::optional pucch_allocator_impl::alloc_common_and_ded_harq_res(cell ue_grants_it->pucch_grants.csi_resource.has_value()), "It is expected that there are either no grants, or at most 1 PUCCH grant (SR grant or CSI grant)"); + // TODO: why F2 or F1? // If there are no existing grants or if the existing one is for SR with Format 1, we need to add 2 additional PUCCH // grants: 1 on common resources and 1 on dedicated resources (for HARQ-ACK bit). // In the case of CSI, the number of PUCCH additional grants depends on the PUCCH resources configuration, but it will @@ -351,7 +353,7 @@ void pucch_allocator_impl::pucch_allocate_sr_opportunity(cell_slot_resource_allo } // NOTE: This check can be removed in future refactors, it's not required by the SR allocator. At the moment, we // schedule the SRs before anything else, therefore we don't expect to find any existing PUCCH grant. - if (not existing_grant_it->pucch_grants.is_emtpy()) { + if (not existing_grant_it->pucch_grants.is_empty()) { logger.info("No PUCCH grants are expected before allocating a new SR grant", crnti, pucch_slot_alloc.slot); return; } @@ -370,7 +372,7 @@ void pucch_allocator_impl::pucch_allocate_sr_opportunity(cell_slot_resource_allo const pucch_format format = pucch_sr_res->format; // Allocate PUCCH SR grant only. - const unsigned harq_ack_bits_increment = 0U; + constexpr unsigned harq_ack_bits_increment = 0U; if (format == pucch_format::FORMAT_0) { fill_pucch_ded_format0_grant(pucch_slot_alloc.result.ul.pucchs.emplace_back(), crnti, @@ -426,7 +428,7 @@ void pucch_allocator_impl::pucch_allocate_csi_opportunity(cell_slot_resource_all return; } - if (existing_grant_it != pucch_grants_alloc_grid[sl_tx.to_uint()].end() and existing_grant_it->has_common_pucch) { + if (existing_grant_it->has_common_pucch) { // Allocation of dedicated + common resources are handled by allocating PUCCH common on existing CSI, not the // other way around. If the function enters the path, it means it too early to start scheduling the CSI. logger.info("rnti={}: CSI occasion allocation for slot={} skipped. Cause: There is a PUCCH common grant" @@ -459,8 +461,8 @@ pucch_uci_bits pucch_allocator_impl::remove_ue_uci_from_pucch(cell_slot_resource // Get the PUCCH grants for the slot. auto& ue_pucchs = pucch_grants_alloc_grid[sl_uci.to_uint()]; - auto* grant_it = - std::find_if(ue_pucchs.begin(), ue_pucchs.end(), [crnti](ue_grants& grants) { return grants.rnti == crnti; }); + auto* grant_it = std::find_if( + ue_pucchs.begin(), ue_pucchs.end(), [crnti](const ue_grants& grants) { return grants.rnti == crnti; }); // Get the bits from the PUCCH grants and remove the item from the list. if (grant_it != ue_pucchs.end()) { @@ -531,13 +533,14 @@ void pucch_allocator_impl::pucch_grant::set_res_config(const pucch_resource& res symbols.set(f1.starting_sym_idx, f1.starting_sym_idx + f1.nof_symbols); break; } - case pucch_format::FORMAT_2: { - const auto& f2 = std::get(res_cfg.format_params); - symbols.set(f2.starting_sym_idx, f2.starting_sym_idx + f2.nof_symbols); + case pucch_format::FORMAT_2: + case pucch_format::FORMAT_3: { + const auto& f23 = std::get(res_cfg.format_params); + symbols.set(f23.starting_sym_idx, f23.starting_sym_idx + f23.nof_symbols); break; } default: - srsran_assertion_failure("Only PUCCH format 0, 1 and 2 are currentl supported"); + srsran_assertion_failure("Invalid PUCCH format"); } } @@ -582,7 +585,7 @@ pucch_uci_bits pucch_allocator_impl::pucch_grant_list::get_uci_bits() const return bits; } -bool pucch_allocator_impl::pucch_grant_list::is_emtpy() const +bool pucch_allocator_impl::pucch_grant_list::is_empty() const { return not sr_resource.has_value() and not harq_resource.has_value() and not csi_resource.has_value(); } @@ -629,11 +632,11 @@ class existing_pucch_pdus_handler void remove_unused_pdus(static_vector& pucchs, rnti_t rnti) const; void update_sr_pdu_bits(sr_nof_bits sr_bits, unsigned harq_ack_bits); void update_csi_pdu_bits(unsigned csi_part1_bits, sr_nof_bits sr_bits); - void update_harq_pdu_bits(unsigned harq_ack_bits, - sr_nof_bits sr_bits, - unsigned csi_part1_bits, - const pucch_resource& pucch_res_cfg, - float max_pucch_code_rate = 1.0F); + void update_harq_pdu_bits(unsigned harq_ack_bits, + sr_nof_bits sr_bits, + unsigned csi_part1_bits, + const pucch_resource& pucch_res_cfg, + const std::optional& common_params); pucch_info* sr_pdu{nullptr}; pucch_info* harq_pdu{nullptr}; @@ -653,9 +656,9 @@ existing_pucch_pdus_handler::existing_pucch_pdus_handler(rnti_t c if (pucch.crnti == crnti and not pucch.pdu_context.is_common) { pucch.pdu_context.id = MAX_PUCCH_PDUS_PER_SLOT; - if (pucch.format == srsran::pucch_format::FORMAT_0) { + if (pucch.format == pucch_format::FORMAT_0) { // With Format 0, when there are both HARQ bits and SR bits in the same PDU (this means that the PUCCH HARQ - // reource and SR resource have overlapping symbols), we only use the HARQ-ACK resource; the only case when the + // resource and SR resource have overlapping symbols), we only use the HARQ-ACK resource; the only case when the // SR PUCCH F0 is used is when there are only SR bits. if (pucch.format_0.sr_bits != sr_nof_bits::no_sr and pucch.format_0.harq_ack_nof_bits == 0U) { sr_pdu = &pucch; @@ -668,7 +671,7 @@ existing_pucch_pdus_handler::existing_pucch_pdus_handler(rnti_t c } } - else if (pucch.format == srsran::pucch_format::FORMAT_1) { + else if (pucch.format == pucch_format::FORMAT_1) { if (pucch.format_1.sr_bits == sr_nof_bits::one and pucch_res_cfg != nullptr and sr_id_match(*pucch_res_cfg, pucch)) { sr_pdu = &pucch; @@ -678,7 +681,7 @@ existing_pucch_pdus_handler::existing_pucch_pdus_handler(rnti_t c ++pdus_cnt; } - else if (pucch.format == srsran::pucch_format::FORMAT_2) { + else if (pucch.format == pucch_format::FORMAT_2) { if (pucch.format_2.csi_part1_bits != 0U and pucch.format_2.harq_ack_nof_bits == 0U) { csi_pdu = &pucch; } else { @@ -686,6 +689,15 @@ existing_pucch_pdus_handler::existing_pucch_pdus_handler(rnti_t c } ++pdus_cnt; } + + else if (pucch.format == pucch_format::FORMAT_3) { + if (pucch.format_3.csi_part1_bits != 0U and pucch.format_3.harq_ack_nof_bits == 0U) { + csi_pdu = &pucch; + } else { + harq_pdu = &pucch; + } + ++pdus_cnt; + } } } } @@ -764,31 +776,32 @@ void existing_pucch_pdus_handler::update_csi_pdu_bits(unsigned csi_part1_bits, s // Once the grant is updated, set the pointer to null, as we don't want to process this again. csi_pdu = nullptr; --pdus_cnt; + } else if (csi_pdu->format == pucch_format::FORMAT_3) { + csi_pdu->format_3.csi_part1_bits = csi_part1_bits; + csi_pdu->format_3.sr_bits = sr_bits; + csi_pdu->pdu_context.id = pdu_id++; + // Once the grant is updated, set the pointer to null, as we don't want to process this again. + csi_pdu = nullptr; + --pdus_cnt; } else { - srsran_assertion_failure("Only PUCCH Format 2 currently supported for CSI grant"); + srsran_assertion_failure("Only PUCCH Formats 2, 3 and 4 can be used for CSI grant"); } } -void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned harq_ack_bits, - sr_nof_bits sr_bits, - unsigned csi_part1_bits, - const pucch_resource& pucch_res_cfg, - float max_pucch_code_rate) +void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned harq_ack_bits, + sr_nof_bits sr_bits, + unsigned csi_part1_bits, + const pucch_resource& pucch_res_cfg, + const std::optional& common_params) { if (harq_pdu->format == pucch_format::FORMAT_0) { harq_pdu->format_0.harq_ack_nof_bits = harq_ack_bits; harq_pdu->format_0.sr_bits = sr_bits; harq_pdu->pdu_context.id = pdu_id++; - // Once the grant is updated, set the pointer to null, as we don't want to process this again. - harq_pdu = nullptr; - --pdus_cnt; } else if (harq_pdu->format == pucch_format::FORMAT_1) { harq_pdu->format_1.harq_ack_nof_bits = harq_ack_bits; harq_pdu->format_1.sr_bits = sr_bits; harq_pdu->pdu_context.id = pdu_id++; - // Once the grant is updated, set the pointer to null, as we don't want to process this again. - harq_pdu = nullptr; - --pdus_cnt; } else if (harq_pdu->format == pucch_format::FORMAT_2) { harq_pdu->format_2.harq_ack_nof_bits = harq_ack_bits; harq_pdu->format_2.sr_bits = sr_bits; @@ -800,18 +813,38 @@ void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned har const unsigned nof_prbs = get_pucch_format2_nof_prbs(harq_ack_bits + sr_nof_bits_to_uint(sr_bits) + csi_part1_bits, f2_cfg.nof_prbs, f2_cfg.nof_symbols, - max_pucch_code_rate); + to_max_code_rate_float(common_params->max_c_rate)); + harq_pdu->resources.prbs.set(pucch_res_cfg.starting_prb, pucch_res_cfg.starting_prb + nof_prbs); + if (pucch_res_cfg.second_hop_prb.has_value()) { + harq_pdu->resources.second_hop_prbs.set(pucch_res_cfg.second_hop_prb.value(), + pucch_res_cfg.second_hop_prb.value() + nof_prbs); + } + } else if (harq_pdu->format == pucch_format::FORMAT_3) { + harq_pdu->format_3.harq_ack_nof_bits = harq_ack_bits; + harq_pdu->format_3.sr_bits = sr_bits; + harq_pdu->format_3.csi_part1_bits = csi_part1_bits; + harq_pdu->pdu_context.id = pdu_id++; + // After updating the UCI bits, we need to recompute the number of PRBs for PUCCH format 3, as per TS 38.213, + // Section 9.2.5.2. + const auto& f3_cfg = std::get(pucch_res_cfg.format_params); + const unsigned nof_prbs = get_pucch_format3_nof_prbs(harq_ack_bits + sr_nof_bits_to_uint(sr_bits) + csi_part1_bits, + f3_cfg.nof_prbs, + f3_cfg.nof_symbols, + to_max_code_rate_float(common_params->max_c_rate), + pucch_res_cfg.second_hop_prb.has_value(), + common_params->additional_dmrs, + common_params->pi_2_bpsk); harq_pdu->resources.prbs.set(pucch_res_cfg.starting_prb, pucch_res_cfg.starting_prb + nof_prbs); if (pucch_res_cfg.second_hop_prb.has_value()) { harq_pdu->resources.second_hop_prbs.set(pucch_res_cfg.second_hop_prb.value(), pucch_res_cfg.second_hop_prb.value() + nof_prbs); } - // Once the grant is updated, set the pointer to null, as we don't want to process this again. - harq_pdu = nullptr; - --pdus_cnt; } else { - srsran_assertion_failure("Only PUCCH Format 0, 1, and 2 currently supported"); + srsran_assertion_failure("Only PUCCH Format 0, 1, 2 and 3 currently supported"); } + // Once the grant is updated, set the pointer to null, as we don't want to process this again. + harq_pdu = nullptr; + --pdus_cnt; } ////////////// Private functions ////////////// @@ -819,13 +852,13 @@ void existing_pucch_pdus_handler::update_harq_pdu_bits(unsigned har // The function returns an available common PUCCH resource (i.e., not used by other UEs); it returns a null optional // if no resource is available. std::optional -pucch_allocator_impl::alloc_pucch_common_res_harq(cell_slot_resource_allocator& pucch_alloc, - const dci_context_information& dci_info) +pucch_allocator_impl::alloc_pucch_common_res_harq(const cell_slot_resource_allocator& pucch_alloc, + const dci_context_information& dci_info) { // As per Section 9.2.1, TS 38.213, this is the max value of \f$\Delta_{PRI}\f$, which is a 3-bit unsigned. - const unsigned max_d_pri = 7; + constexpr unsigned max_d_pri = 7; // As per Section 9.2.1, TS 38.213, r_pucch can take values within {0,...,15}. - const unsigned r_pucch_invalid = 16; + constexpr unsigned r_pucch_invalid = 16; // Get the parameter N_bwp_size, which is the Initial UL BWP size in PRBs, as per TS 38.213, Section 9.2.1. const unsigned size_ul_bwp = cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.length(); @@ -999,7 +1032,7 @@ void pucch_allocator_impl::compute_pucch_common_params_and_alloc(cell_slot_resou void pucch_allocator_impl::fill_pucch_harq_common_grant(pucch_info& pucch_info, rnti_t rnti, - const pucch_res_alloc_cfg& pucch_res) + const pucch_res_alloc_cfg& pucch_res) const { pucch_info.crnti = rnti; pucch_info.format = pucch_res.format; @@ -1043,7 +1076,7 @@ void pucch_allocator_impl::fill_pucch_harq_common_grant(pucch_info& break; } default: - srsran_assert(false, "PUCCH Format must from 0 to 4, but only 0 and 1 are currently supported"); + srsran_assert(false, "PUCCH Format must be from 0 to 4, but only 0 and 1 are currently supported"); } } @@ -1061,7 +1094,7 @@ pucch_allocator_impl::find_common_and_ded_harq_res_available(cell_slot_resource_ const unsigned start_cce_idx = dci_info.cces.ncce; // As per Section 9.2.1, TS 38.213, this is the max value of \f$\Delta_{PRI}\f$, which is a 3-bit unsigned. - const unsigned max_d_pri = 7; + constexpr unsigned max_d_pri = 7; for (unsigned d_pri = 0; d_pri != max_d_pri + 1; ++d_pri) { // The PUCCH allocation may result in a temporary reservation of PUCCH resources, which need to be released in // case of failure or in case the multiplexing results in a different final PUCCH resource. If we don't reset the @@ -1146,14 +1179,14 @@ std::optional pucch_allocator_impl::allocate_harq_grant(cell_slot_reso } // Allocate the new grant on PUCCH F1 resources for HARQ-ACK bits (without SR). - pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); - const unsigned HARQ_BITS_IN_NEW_PUCCH_GRANT = 1; + pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); + constexpr unsigned harq_bits_in_new_pucch_grant = 1; if (pucch_harq_res_info.pucch_res->format == pucch_format::FORMAT_0) { fill_pucch_ded_format0_grant( - pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, HARQ_BITS_IN_NEW_PUCCH_GRANT, sr_nof_bits::no_sr); + pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, harq_bits_in_new_pucch_grant, sr_nof_bits::no_sr); } else if (pucch_harq_res_info.pucch_res->format == pucch_format::FORMAT_1) { fill_pucch_ded_format1_grant( - pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, HARQ_BITS_IN_NEW_PUCCH_GRANT, sr_nof_bits::no_sr); + pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, harq_bits_in_new_pucch_grant, sr_nof_bits::no_sr); } else { srsran_assertion_failure("Only PUCCH Format 0 or 1 can be used for UCI with only 1 HARQ-ACK bit"); } @@ -1165,7 +1198,7 @@ std::optional pucch_allocator_impl::allocate_harq_grant(cell_slot_reso grants.pucch_grants.harq_resource.value().set_res_config(*pucch_harq_res_info.pucch_res); grants.pucch_grants.harq_resource.value().harq_id.pucch_set_idx = pucch_res_set_idx::set_0; grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind = pucch_res_indicator; - grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = HARQ_BITS_IN_NEW_PUCCH_GRANT; + grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = harq_bits_in_new_pucch_grant; return pucch_res_indicator; } @@ -1175,13 +1208,13 @@ void pucch_allocator_impl::allocate_csi_grant(cell_slot_resource_allocator& pucc const ue_cell_configuration& ue_cell_cfg, unsigned csi_part1_bits) { - srsran_assert(csi_part1_bits != 0, "This function can only be called to allocate a PUCCH F2 resource for CSI"); + srsran_assert(csi_part1_bits != 0, "This function can only be called to allocate a PUCCH F2/F3/F4 resource for CSI"); const slot_point sl_tx = pucch_slot_alloc.slot; // [Implementation-defined] We only allow a max number of PUCCH + PUSCH grants per slot. if (pucch_slot_alloc.result.ul.pucchs.size() >= get_max_pucch_grants(static_cast(pucch_slot_alloc.result.ul.puschs.size()))) { - logger.warning("rnti={}: CSI allocation on PUCCH Format2 for slot={} skipped. Cause: UL grants reached", + logger.warning("rnti={}: CSI allocation on PUCCH F2/F3/F4 for slot={} skipped. Cause: UL grants reached", crnti, pucch_slot_alloc.slot); return; @@ -1194,45 +1227,62 @@ void pucch_allocator_impl::allocate_csi_grant(cell_slot_resource_allocator& pucc return; } - // Get the F2 resource specific for with CSI. - const pucch_resource* csi_f2_res = resource_manager.reserve_csi_resource(pucch_slot_alloc.slot, crnti, ue_cell_cfg); + // Get the F2/F3/F4 resource specific for with CSI. + const pucch_resource* csi_f2_f3_f4_res = + resource_manager.reserve_csi_resource(pucch_slot_alloc.slot, crnti, ue_cell_cfg); - if (csi_f2_res == nullptr) { - logger.warning( - "rnti={}: CSI could not be allocated on PUCCH Format2 for slot={}. Cause: PUCCH F2 resource not available", - crnti, - pucch_slot_alloc.slot); + if (csi_f2_f3_f4_res == nullptr) { + logger.warning("rnti={}: CSI could not be allocated for slot={}. Cause: PUCCH F2/F3/F4 resource not available", + crnti, + pucch_slot_alloc.slot); return; } // When this function is called, it means that there are no SR grants to be multiplexed with CSI; thus, the CSI bits // are the only UCI bits to be considered. - // It's the validator that should make sure the CSI bits fit into a PUCCH Format 2 resource. + // It's the validator that should make sure the CSI bits fit into a PUCCH Format 2/3/4 resource. const unsigned max_payload = - ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().get_max_payload(csi_f2_res->format); + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().get_max_payload( + csi_f2_f3_f4_res->format); srsran_assert(csi_part1_bits <= max_payload, - "rnti={}: PUCCH F2 max payload {} is insufficient for {} candidate UCI bits", + "rnti={}: PUCCH F2/F3/F4 max payload {} is insufficient for {} candidate UCI bits", crnti, max_payload, csi_part1_bits); // Allocate a PUCCH PDU in the list and fill it with the parameters. pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); - // Neither HARQ-ACK bits - const unsigned harq_ack_bits_only_csi = 0U; - const sr_nof_bits sr_bits_only_csi = sr_nof_bits::no_sr; - fill_pucch_format2_grant(pucch_pdu, - crnti, - *csi_f2_res, - ue_cell_cfg, - std::get(csi_f2_res->format_params).nof_prbs, - harq_ack_bits_only_csi, - sr_bits_only_csi, - csi_part1_bits); + // Neither HARQ-ACK bits. + constexpr unsigned harq_ack_bits_only_csi = 0U; + constexpr sr_nof_bits sr_bits_only_csi = sr_nof_bits::no_sr; + switch (csi_f2_f3_f4_res->format) { + case pucch_format::FORMAT_2: + fill_pucch_format2_grant(pucch_pdu, + crnti, + *csi_f2_f3_f4_res, + ue_cell_cfg, + std::get(csi_f2_f3_f4_res->format_params).nof_prbs, + harq_ack_bits_only_csi, + sr_bits_only_csi, + csi_part1_bits); + break; + case pucch_format::FORMAT_3: + fill_pucch_format3_grant(pucch_pdu, + crnti, + *csi_f2_f3_f4_res, + ue_cell_cfg, + std::get(csi_f2_f3_f4_res->format_params).nof_prbs, + harq_ack_bits_only_csi, + sr_bits_only_csi, + csi_part1_bits); + break; + default: + srsran_assertion_failure("PUCCH resource for CSI must be of Formats 2, 3 or 4"); + } // Save the info in the scheduler list of PUCCH grants. auto& csi_pucch_grant = pucch_grants_alloc_grid[sl_tx.to_uint()].emplace_back(ue_grants{.rnti = crnti}); csi_pucch_grant.pucch_grants.csi_resource.emplace(pucch_grant{.type = pucch_grant_type::csi}); - csi_pucch_grant.pucch_grants.csi_resource.value().set_res_config(*csi_f2_res); + csi_pucch_grant.pucch_grants.csi_resource.value().set_res_config(*csi_f2_f3_f4_res); csi_pucch_grant.pucch_grants.csi_resource.value().bits.csi_part1_nof_bits = csi_part1_bits; } @@ -1240,7 +1290,7 @@ void pucch_allocator_impl::fill_pucch_ded_format0_grant(pucch_info& pu rnti_t crnti, const pucch_resource& pucch_ded_res_cfg, unsigned harq_ack_bits, - sr_nof_bits sr_bits) + sr_nof_bits sr_bits) const { pucch_pdu.crnti = crnti; @@ -1272,7 +1322,7 @@ void pucch_allocator_impl::fill_pucch_ded_format1_grant(pucch_info& pu rnti_t crnti, const pucch_resource& pucch_ded_res_cfg, unsigned harq_ack_bits, - sr_nof_bits sr_bits) + sr_nof_bits sr_bits) const { pucch_pdu.crnti = crnti; pucch_pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; @@ -1309,16 +1359,16 @@ void pucch_allocator_impl::fill_pucch_format2_grant(pucch_info& unsigned nof_prbs, unsigned harq_ack_bits, sr_nof_bits sr_bits, - unsigned csi_part1_bits) + unsigned csi_part1_bits) const { + const auto& res_f2 = std::get(pucch_ded_res_cfg.format_params); + pucch_pdu.crnti = crnti; pucch_pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; pucch_pdu.format = pucch_format::FORMAT_2; // Set PRBs and symbols, first. - // The number of PRBs is not explicitly stated in the TS, but it can be inferred it's 1. pucch_pdu.resources.prbs.set(pucch_ded_res_cfg.starting_prb, pucch_ded_res_cfg.starting_prb + nof_prbs); - const auto& res_f2 = std::get(pucch_ded_res_cfg.format_params); pucch_pdu.resources.symbols.set(res_f2.starting_sym_idx, res_f2.starting_sym_idx + res_f2.nof_symbols); if (pucch_ded_res_cfg.second_hop_prb.has_value()) { pucch_pdu.resources.second_hop_prbs.set(pucch_ded_res_cfg.second_hop_prb.value(), @@ -1347,6 +1397,68 @@ void pucch_allocator_impl::fill_pucch_format2_grant(pucch_info& } } +void pucch_allocator_impl::fill_pucch_format3_grant(pucch_info& pucch_pdu, + rnti_t crnti, + const pucch_resource& pucch_ded_res_cfg, + const ue_cell_configuration& ue_cell_cfg, + unsigned nof_prbs, + unsigned harq_ack_bits, + sr_nof_bits sr_bits, + unsigned csi_part1_bits) const +{ + const auto& res_f3 = std::get(pucch_ded_res_cfg.format_params); + + pucch_pdu.crnti = crnti; + pucch_pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_pdu.format = pucch_format::FORMAT_3; + + // Set PRBs and symbols, first. + pucch_pdu.resources.prbs.set(pucch_ded_res_cfg.starting_prb, pucch_ded_res_cfg.starting_prb + nof_prbs); + pucch_pdu.resources.symbols.set(res_f3.starting_sym_idx, res_f3.starting_sym_idx + res_f3.nof_symbols); + if (pucch_ded_res_cfg.second_hop_prb.has_value()) { + pucch_pdu.resources.second_hop_prbs.set(pucch_ded_res_cfg.second_hop_prb.value(), + pucch_ded_res_cfg.second_hop_prb.value() + nof_prbs); + } + + pucch_pdu.format_3.sr_bits = sr_bits; + pucch_pdu.format_3.harq_ack_nof_bits = harq_ack_bits; + pucch_pdu.format_3.csi_part1_bits = csi_part1_bits; + + pucch_pdu.format_3.group_hopping = cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->group_hopping; + pucch_pdu.format_3.n_id_hopping = cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->hopping_id.has_value() + ? cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->hopping_id.value() + : cell_cfg.pci; + // [Implementation-defined] We do not implement PUCCH over several slots. + pucch_pdu.format_3.slot_repetition = pucch_repetition_tx_slot::no_multi_slot; + // \f$n_{ID}\f$ as per Section 6.3.2.5.1 and 6.3.2.6.1, TS 38.211. + pucch_pdu.format_3.n_id_scrambling = + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pusch_cfg.value().data_scrambling_id_pusch.has_value() + ? ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pusch_cfg.value().data_scrambling_id_pusch.value() + : cell_cfg.pci; + pucch_pdu.format_3.n_id_0_scrambling = get_n_id0_scrambling(ue_cell_cfg, cell_cfg.pci); + pucch_pdu.format_3.pi_2_bpsk = ue_cell_cfg.cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .format_3_common_param.value() + .pi_2_bpsk; + pucch_pdu.format_3.additional_dmrs = ue_cell_cfg.cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .format_3_common_param.value() + .additional_dmrs; + // \f$N_{ID}^0\f$ as per TS 38.211, Section 6.4.1.3.2.1. + pucch_pdu.format_3.max_code_rate = ue_cell_cfg.cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .format_3_common_param.value() + .max_c_rate; + + // Generate CSI report configuration if there are CSI bits in UCI. + if (csi_part1_bits > 0) { + pucch_pdu.csi_rep_cfg = create_csi_report_configuration(*ue_cell_cfg.cfg_dedicated().csi_meas_cfg); + } +} + bool pucch_allocator_impl::has_common_pucch_grant(rnti_t rnti, slot_point sl_tx) const { return std::find_if(pucch_grants_alloc_grid[sl_tx.to_uint()].begin(), @@ -1355,15 +1467,15 @@ bool pucch_allocator_impl::has_common_pucch_grant(rnti_t rnti, slot_point sl_tx) pucch_grants_alloc_grid[sl_tx.to_uint()].end(); } -unsigned pucch_allocator_impl::get_max_pucch_grants(unsigned currently_allocated_puschs) +unsigned pucch_allocator_impl::get_max_pucch_grants(unsigned currently_allocated_puschs) const { return std::min(max_pucch_grants_per_slot, max_ul_grants_per_slot - currently_allocated_puschs); } -void pucch_allocator_impl::remove_unsed_pucch_res(slot_point sl_tx, - pucch_grant_list grants_to_tx, - ue_grants& existing_pucchs, - const ue_cell_configuration& ue_cell_cfg) +void pucch_allocator_impl::remove_unused_pucch_res(slot_point sl_tx, + const pucch_grant_list& grants_to_tx, + const ue_grants& existing_pucchs, + const ue_cell_configuration& ue_cell_cfg) { // Remove the PUCCH resources by evaluating the difference between the previously allocated resources and the current // ones. @@ -1420,7 +1532,7 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& pucch_grant_list grants_to_tx = multiplex_resources(sl_ack, current_grants.rnti, candidate_grants.value(), ue_cell_cfg, preserve_res_indicator); - if (grants_to_tx.is_emtpy()) { + if (grants_to_tx.is_empty()) { return std::nullopt; } @@ -1428,6 +1540,7 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& return allocate_grants(pucch_slot_alloc, current_grants, current_grants.rnti, grants_to_tx, ue_cell_cfg); } +// TODO: check how to handle F0+F3/F4 static unsigned get_pucch_resource_ind_f0_sr_csi(pucch_uci_bits bits, const pucch_config& pucch_cfg) { // With Format 0, with HARQ-ACK bits <= 2, pick a resource from PUCCH resource set 0. @@ -1526,8 +1639,12 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point std::find_if(pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), [](const auto& pucch_res) { return pucch_res.format == pucch_format::FORMAT_0; }) != pucch_cfg.pucch_res_list.end(); + const bool has_format_2 = + std::find_if(pucch_cfg.pucch_res_list.begin(), pucch_cfg.pucch_res_list.end(), [](const auto& pucch_res) { + return pucch_res.format == pucch_format::FORMAT_2; + }) != pucch_cfg.pucch_res_list.end(); const bool ue_with_f0_sr_csi_allocation = - has_format_0 and (new_bits.sr_bits != sr_nof_bits::no_sr or new_bits.csi_part1_nof_bits != 0U); + has_format_0 and has_format_2 and (new_bits.sr_bits != sr_nof_bits::no_sr or new_bits.csi_part1_nof_bits != 0U); candidate_resources.harq_resource.emplace(pucch_grant{.type = pucch_grant_type::harq_ack}); pucch_grant& harq_candidate_grant = candidate_resources.harq_resource.value(); @@ -1620,6 +1737,7 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator // If the HARQ PDU uses F0, there can be 1 HARQ PDU + an optional SR (F0) or CSI (F2). In any case, we only need to // update the HARQ-ACK bits in the HARQ-ACK PDU. + // TODO: handle F0+F3/F4 if (existing_pdus.harq_pdu->format == pucch_format::FORMAT_0) { const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_0_res_by_res_indicator( sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); @@ -1633,8 +1751,11 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator existing_pdus.harq_pdu->resources.symbols, new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits); - existing_pdus.update_harq_pdu_bits( - new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, 0U, *pucch_res_cfg); + existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, + current_grants.pucch_grants.harq_resource.value().bits.sr_bits, + 0U, + *pucch_res_cfg, + std::nullopt); // Update the current grant with the new UCI (HARQ) bits. current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; } @@ -1655,7 +1776,10 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator existing_pdus.harq_pdu->format_1.time_domain_occ, new_bits.harq_ack_nof_bits, existing_pdus.harq_pdu->format_1.sr_bits); - existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, sr_nof_bits::no_sr, 0U, *pucch_res_cfg); + const auto& common_params = + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().format_1_common_param; + existing_pdus.update_harq_pdu_bits( + new_bits.harq_ack_nof_bits, sr_nof_bits::no_sr, 0U, *pucch_res_cfg, common_params); // Update the current grants with the new UCI (HARQ) bits. current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; if (existing_pdus.sr_pdu != nullptr) { @@ -1700,14 +1824,46 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits); + const auto& common_params = + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().format_2_common_param; existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits, *pucch_res_cfg, - to_max_code_rate_float(ue_cell_cfg.cfg_dedicated() - .ul_config.value() - .init_ul_bwp.pucch_cfg.value() - .format_2_common_param->max_c_rate)); + common_params); + current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; + // If the HARQ PDU uses F3, there can be 1 HARQ PDU + an optional CSI (F3). In any case, we only need to update the + // HARQ-ACK bits in the HARQ-ACK PDU. + } else if (existing_pdus.harq_pdu->format == pucch_format::FORMAT_3) { + if (current_grants.pucch_grants.get_uci_bits().get_total_bits() >= + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().get_max_payload( + pucch_format::FORMAT_3)) { + logger.debug("rnti={}: PUCCH allocation (HARQ-ACK) for slot={} skipped. Cause: UCI bits exceed PUCCH payload", + current_grants.rnti, + sl_tx); + return std::nullopt; + } + const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_1_res_by_res_indicator( + sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); + srsran_assert(pucch_res_cfg != nullptr, "rnti={}: PUCCH expected resource not available", current_grants.rnti); + logger.debug("rnti={}: PUCCH PDU on F3 HARQ resource updated: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " + "sr_bits={} csi1_bits={}", + current_grants.rnti, + pucch_slot_alloc.slot, + current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, + existing_pdus.harq_pdu->format, + existing_pdus.harq_pdu->resources.prbs, + existing_pdus.harq_pdu->resources.symbols, + new_bits.harq_ack_nof_bits, + current_grants.pucch_grants.harq_resource.value().bits.sr_bits, + current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits); + const auto& common_params = + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().format_3_common_param; + existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, + current_grants.pucch_grants.harq_resource.value().bits.sr_bits, + current_grants.pucch_grants.harq_resource.value().bits.csi_part1_nof_bits, + *pucch_res_cfg, + common_params); current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; } else { srsran_assertion_failure("rnti={}: unexpected PUCCH format", current_grants.rnti); @@ -1773,7 +1929,7 @@ pucch_allocator_impl::multiplex_resources(slot_point sl_tx, return {}; } // Remove the old resources that got merged from the set. - // TODO: check if, by using a different data structure, we can achive the deletion more efficiently. + // TODO: check if, by using a different data structure, we can achieve the deletion more efficiently. resource_set_q.erase(resource_set_q.begin() + j_cnt - o_cnt, resource_set_q.begin() + j_cnt + 1); // Add the new resource (resulting from the previous merge) to the set. @@ -1793,6 +1949,7 @@ pucch_allocator_impl::multiplex_resources(slot_point sl_tx, // The PUCCH resource multiplexing algorithm above is specified from the UE's perspective. In the GNB, we need to add // an extra resource Format 1 if slot there is a SR opportunity and HARQ bits to be reported with PUCCH Format 1. + // TODO: why? if (resource_set_q.size() == 1 and resource_set_q.front().format == pucch_format::FORMAT_1 and resource_set_q.front().bits.harq_ack_nof_bits != 0 and resource_set_q.front().bits.sr_bits != sr_nof_bits::no_sr) { @@ -1826,11 +1983,11 @@ pucch_allocator_impl::multiplex_resources(slot_point sl_tx, } std::optional -pucch_allocator_impl::merge_pucch_resources(span resources_to_merge, - slot_point slot_harq, - rnti_t crnti, - const pucch_config& pucch_cfg, - std::optional preserve_res_indicator) +pucch_allocator_impl::merge_pucch_resources(span resources_to_merge, + slot_point slot_harq, + rnti_t crnti, + const pucch_config& pucch_cfg, + std::optional preserve_res_indicator) { // This function implements the merging rules for HARQ-ACK, SR and CSI defined in Section 9.2.5.1 and 9.2.5.2, // TS 38.213. @@ -2070,9 +2227,11 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource bool harq_grant_alloc_completed = false; bool sr_grant_alloc_completed = false; bool csi_grant_alloc_completed = false; + // If there was a CSI grant, re-use the previous one and update the UCI bits with SR. if (grants_to_tx.csi_resource.has_value() and existing_pucchs.pucch_grants.csi_resource.has_value() and existing_pdus.csi_pdu != nullptr) { + const auto& csi_res = grants_to_tx.csi_resource.value(); logger.debug( "rnti={}: PUCCH PDU allocated on CSI resource: slot={} prbs={} sym={} h_bits={} sr_bits={} csi1_bits={}", crnti, @@ -2080,171 +2239,256 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource existing_pdus.csi_pdu->resources.prbs, existing_pdus.csi_pdu->resources.symbols, existing_pdus.csi_pdu->format_2.harq_ack_nof_bits, - grants_to_tx.csi_resource.value().bits.sr_bits, - grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits); - existing_pdus.update_csi_pdu_bits(grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits, - grants_to_tx.csi_resource.value().bits.sr_bits); + csi_res.bits.sr_bits, + csi_res.bits.csi_part1_nof_bits); + existing_pdus.update_csi_pdu_bits(csi_res.bits.csi_part1_nof_bits, csi_res.bits.sr_bits); csi_grant_alloc_completed = true; } // If there was a SR grant, re-use the previous one and update UCI bits with HARQ bits. else if (grants_to_tx.sr_resource.has_value() and existing_pucchs.pucch_grants.sr_resource.has_value() and existing_pdus.sr_pdu != nullptr) { - if (grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_0) { - logger.debug("rnti={}: PUCCH PDU allocated on SR FO resource (updated): slot={} prbs={} sym={} " - "h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - existing_pdus.sr_pdu->resources.prbs, - existing_pdus.sr_pdu->resources.symbols, - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.sr_resource.value().bits.sr_bits); - } else { - logger.debug("rnti={}: PUCCH PDU allocated on SR F1 resource (updated): slot={} prbs={} sym={} cs={} occ={} " - "h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - existing_pdus.sr_pdu->resources.prbs, - existing_pdus.sr_pdu->resources.symbols, - existing_pdus.sr_pdu->format_1.initial_cyclic_shift, - existing_pdus.sr_pdu->format_1.time_domain_occ, - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.sr_resource.value().bits.sr_bits); + const auto& sr_res = grants_to_tx.sr_resource.value(); + switch (sr_res.format) { + case pucch_format::FORMAT_0: + logger.debug("rnti={}: PUCCH PDU allocated on SR FO resource (updated): slot={} prbs={} sym={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + existing_pdus.sr_pdu->resources.prbs, + existing_pdus.sr_pdu->resources.symbols, + sr_res.bits.harq_ack_nof_bits, + sr_res.bits.sr_bits); + break; + case pucch_format::FORMAT_1: + logger.debug("rnti={}: PUCCH PDU allocated on SR F1 resource (updated): slot={} prbs={} sym={} cs={} occ={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + existing_pdus.sr_pdu->resources.prbs, + existing_pdus.sr_pdu->resources.symbols, + existing_pdus.sr_pdu->format_1.initial_cyclic_shift, + existing_pdus.sr_pdu->format_1.time_domain_occ, + sr_res.bits.harq_ack_nof_bits, + sr_res.bits.sr_bits); + break; + default: + srsran_assertion_failure("Invalid PUCCH Format for SR (should be 0 or 1)"); + break; } - existing_pdus.update_sr_pdu_bits(grants_to_tx.sr_resource.value().bits.sr_bits, - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits); + existing_pdus.update_sr_pdu_bits(sr_res.bits.sr_bits, sr_res.bits.harq_ack_nof_bits); sr_grant_alloc_completed = true; } pucch_uci_bits bits = grants_to_tx.get_uci_bits(); if (grants_to_tx.csi_resource.has_value() and not csi_grant_alloc_completed) { - pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); + const auto& csi_res = grants_to_tx.csi_resource.value(); + pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); srsran_assert(grant != nullptr, "The return grant cannot be nullptr"); - const unsigned nof_prbs = - std::get(grants_to_tx.csi_resource.value().pucch_res_cfg->format_params).nof_prbs; - fill_pucch_format2_grant(*grant, - crnti, - *grants_to_tx.csi_resource.value().pucch_res_cfg, - ue_cell_cfg, - nof_prbs, - 0U, - grants_to_tx.csi_resource.value().bits.sr_bits, - grants_to_tx.csi_resource.value().bits.csi_part1_nof_bits); - logger.debug( - "rnti={}: PUCCH PDU allocated on CSI resource: slot={} prbs={} sym={} h_bits={} sr_bits={} csi1_bits={}", - crnti, - pucch_slot_alloc.slot, - grant->resources.prbs, - grant->resources.symbols, - grant->format_2.harq_ack_nof_bits, - grant->format_2.sr_bits, - grant->format_2.csi_part1_bits); + + switch (csi_res.format) { + case pucch_format::FORMAT_2: { + const unsigned nof_prbs = std::get(csi_res.pucch_res_cfg->format_params).nof_prbs; + fill_pucch_format2_grant(*grant, + crnti, + *csi_res.pucch_res_cfg, + ue_cell_cfg, + nof_prbs, + 0U, + csi_res.bits.sr_bits, + csi_res.bits.csi_part1_nof_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on CSI F2 resource: slot={} prbs={} sym={} h_bits={} sr_bits={} csi1_bits={}", + crnti, + pucch_slot_alloc.slot, + grant->resources.prbs, + grant->resources.symbols, + grant->format_2.harq_ack_nof_bits, + grant->format_2.sr_bits, + grant->format_2.csi_part1_bits); + } break; + case pucch_format::FORMAT_3: { + const unsigned nof_prbs = std::get(csi_res.pucch_res_cfg->format_params).nof_prbs; + fill_pucch_format3_grant(*grant, + crnti, + *csi_res.pucch_res_cfg, + ue_cell_cfg, + nof_prbs, + 0U, + csi_res.bits.sr_bits, + csi_res.bits.csi_part1_nof_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on CSI F3 resource: slot={} prbs={} sym={} h_bits={} sr_bits={} csi1_bits={}", + crnti, + pucch_slot_alloc.slot, + grant->resources.prbs, + grant->resources.symbols, + grant->format_3.harq_ack_nof_bits, + grant->format_3.sr_bits, + grant->format_3.csi_part1_bits); + } break; + default: + srsran_assertion_failure("Invalid PUCCH Format for CSI (should be 2, 3, or 4)"); + break; + } } + if (grants_to_tx.sr_resource.has_value() and not sr_grant_alloc_completed) { - pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); + const auto& sr_res = grants_to_tx.sr_resource.value(); + pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); srsran_assert(grant != nullptr, "The return grant cannot be nullptr"); - if (grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_0) { - fill_pucch_ded_format0_grant(*grant, - crnti, - *grants_to_tx.sr_resource.value().pucch_res_cfg, - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.sr_resource.value().bits.sr_bits); - } else if (grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_1) { - fill_pucch_ded_format1_grant(*grant, - crnti, - *grants_to_tx.sr_resource.value().pucch_res_cfg, - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.sr_resource.value().bits.sr_bits); + + switch (sr_res.format) { + case pucch_format::FORMAT_0: { + fill_pucch_ded_format0_grant(*grant, + crnti, + *grants_to_tx.sr_resource.value().pucch_res_cfg, + grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.sr_resource.value().bits.sr_bits); + logger.debug("rnti={}: PUCCH PDU allocated on SR F0 resource: slot={} prbs={} sym={} h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + grant->resources.prbs, + grant->resources.symbols, + grant->format_0.harq_ack_nof_bits, + grant->format_0.sr_bits); + } break; + case pucch_format::FORMAT_1: { + fill_pucch_ded_format1_grant(*grant, + crnti, + *grants_to_tx.sr_resource.value().pucch_res_cfg, + grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.sr_resource.value().bits.sr_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on SR F1 resource: slot={} prbs={} sym={} cs={} occ={} h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + grant->resources.prbs, + grant->resources.symbols, + grant->format_1.initial_cyclic_shift, + grant->format_1.time_domain_occ, + grant->format_1.harq_ack_nof_bits, + grant->format_1.sr_bits); + } break; + default: + srsran_assertion_failure("Invalid PUCCH Format for SR (should be 0 or 1)"); + break; } - logger.debug( - "rnti={}: PUCCH PDU allocated on SR resource: slot={} prbs={} sym={} cs={} occ={} h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - grant->resources.prbs, - grant->resources.symbols, - grant->format_1.initial_cyclic_shift, - grant->format_1.time_domain_occ, - grant->format_1.harq_ack_nof_bits, - grant->format_1.sr_bits); } + if (grants_to_tx.harq_resource.has_value() and not harq_grant_alloc_completed) { - pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); - if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_0) { - fill_pucch_ded_format0_grant(*grant, - crnti, - *grants_to_tx.harq_resource.value().pucch_res_cfg, - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits); - } else if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_1) { - fill_pucch_ded_format1_grant(*grant, - crnti, - *grants_to_tx.harq_resource.value().pucch_res_cfg, - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits); - } else { - const auto& f2_cfg = - std::get(grants_to_tx.harq_resource.value().pucch_res_cfg->format_params); - const float max_pucch_code_rate = to_max_code_rate_float(ue_cell_cfg.cfg_dedicated() - .ul_config.value() - .init_ul_bwp.pucch_cfg.value() - .format_2_common_param.value() - .max_c_rate); - const unsigned nof_prbs = - get_pucch_format2_nof_prbs(bits.get_total_bits(), f2_cfg.nof_prbs, f2_cfg.nof_symbols, max_pucch_code_rate); - fill_pucch_format2_grant(*grant, - crnti, - *grants_to_tx.harq_resource.value().pucch_res_cfg, - ue_cell_cfg, - nof_prbs, - grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.harq_resource.value().bits.sr_bits, - grants_to_tx.harq_resource.value().bits.csi_part1_nof_bits); - } - if (grant->format == pucch_format::FORMAT_0) { - logger.debug("rnti={}: PUCCH PDU allocated on F0 HARQ resource: slot={} p_ind={} prbs={} sym={} " - "h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, - grant->resources.prbs, - grant->resources.symbols, - grant->format_0.harq_ack_nof_bits, - grant->format_0.sr_bits); - } else if (grant->format == pucch_format::FORMAT_1) { - logger.debug("rnti={}: PUCCH PDU allocated on F1 HARQ resource: slot={} p_ind={} prbs={} sym={} cs={} occ={} " - "h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, - grant->resources.prbs, - grant->resources.symbols, - grant->format_1.initial_cyclic_shift, - grant->format_1.time_domain_occ, - grant->format_1.harq_ack_nof_bits, - grant->format_1.sr_bits); - } else { - logger.debug( - "rnti={}: PUCCH PDU allocated on F2 HARQ resource: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " - "sr_bits={} csi1_bits={}", - crnti, - pucch_slot_alloc.slot, - grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, - grant->format, - grant->resources.prbs, - grant->resources.symbols, - grant->format_2.harq_ack_nof_bits, - grant->format_2.sr_bits, - grant->format_2.csi_part1_bits); + // Allocate HARQ-ACK grant. + pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); + const auto& harq_res = grants_to_tx.harq_resource.value(); + switch (harq_res.format) { + case pucch_format::FORMAT_0: + fill_pucch_ded_format0_grant( + *grant, crnti, *harq_res.pucch_res_cfg, harq_res.bits.harq_ack_nof_bits, harq_res.bits.sr_bits); + logger.debug("rnti={}: PUCCH PDU allocated on F0 HARQ resource: slot={} p_ind={} prbs={} sym={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + harq_res.harq_id.pucch_res_ind, + grant->resources.prbs, + grant->resources.symbols, + grant->format_0.harq_ack_nof_bits, + grant->format_0.sr_bits); + break; + case pucch_format::FORMAT_1: + fill_pucch_ded_format1_grant( + *grant, crnti, *harq_res.pucch_res_cfg, harq_res.bits.harq_ack_nof_bits, harq_res.bits.sr_bits); + logger.debug("rnti={}: PUCCH PDU allocated on F1 HARQ resource: slot={} p_ind={} prbs={} sym={} cs={} occ={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + harq_res.harq_id.pucch_res_ind, + grant->resources.prbs, + grant->resources.symbols, + grant->format_1.initial_cyclic_shift, + grant->format_1.time_domain_occ, + grant->format_1.harq_ack_nof_bits, + grant->format_1.sr_bits); + break; + case pucch_format::FORMAT_2: { + const auto& f2_cfg = std::get(harq_res.pucch_res_cfg->format_params); + const float max_pucch_code_rate = to_max_code_rate_float(ue_cell_cfg.cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .format_2_common_param.value() + .max_c_rate); + const unsigned nof_prbs = + get_pucch_format2_nof_prbs(bits.get_total_bits(), f2_cfg.nof_prbs, f2_cfg.nof_symbols, max_pucch_code_rate); + fill_pucch_format2_grant(*grant, + crnti, + *harq_res.pucch_res_cfg, + ue_cell_cfg, + nof_prbs, + harq_res.bits.harq_ack_nof_bits, + harq_res.bits.sr_bits, + harq_res.bits.csi_part1_nof_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on F2 HARQ resource: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " + "sr_bits={} csi1_bits={}", + crnti, + pucch_slot_alloc.slot, + harq_res.harq_id.pucch_res_ind, + grant->format, + grant->resources.prbs, + grant->resources.symbols, + grant->format_2.harq_ack_nof_bits, + grant->format_2.sr_bits, + grant->format_2.csi_part1_bits); + } break; + case pucch_format::FORMAT_3: { + const auto& f3 = std::get(harq_res.pucch_res_cfg->format_params); + const float max_pucch_code_rate = to_max_code_rate_float(ue_cell_cfg.cfg_dedicated() + .ul_config.value() + .init_ul_bwp.pucch_cfg.value() + .format_3_common_param.value() + .max_c_rate); + const auto& common_param = + ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().format_3_common_param.value(); + const unsigned nof_prbs = get_pucch_format3_nof_prbs(bits.get_total_bits(), + f3.nof_prbs, + f3.nof_symbols, + max_pucch_code_rate, + harq_res.pucch_res_cfg->second_hop_prb.has_value(), + common_param.additional_dmrs, + common_param.pi_2_bpsk); + fill_pucch_format3_grant(*grant, + crnti, + *harq_res.pucch_res_cfg, + ue_cell_cfg, + nof_prbs, + harq_res.bits.harq_ack_nof_bits, + harq_res.bits.sr_bits, + harq_res.bits.csi_part1_nof_bits); + logger.debug( + "rnti={}: PUCCH PDU allocated on F3 HARQ resource: slot={} p_ind={} format={} prbs={} sym={} h_bits={} " + "sr_bits={} csi1_bits={}", + crnti, + pucch_slot_alloc.slot, + harq_res.harq_id.pucch_res_ind, + grant->format, + grant->resources.prbs, + grant->resources.symbols, + grant->format_3.harq_ack_nof_bits, + grant->format_3.sr_bits, + grant->format_3.csi_part1_bits); + } break; + default: + srsran_assertion_failure("Unexpected PUCCH Format"); + break; } } slot_point sl_tx = pucch_slot_alloc.slot; - // Remove unsed PUCCH PDU, if any. + // Remove unused PUCCH PDU, if any. existing_pdus.remove_unused_pdus(pucch_pdus, crnti); // Remove the previously allocated PUCCH resources which are not needed after the new allocation. - remove_unsed_pucch_res(sl_tx, grants_to_tx, existing_pucchs, ue_cell_cfg); + remove_unused_pucch_res(sl_tx, grants_to_tx, existing_pucchs, ue_cell_cfg); // Update the new grants to the UE allocation record. existing_pucchs.pucch_grants = grants_to_tx; diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h index 79115d31b6..968d142112 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h @@ -124,7 +124,7 @@ class pucch_allocator_impl final : public pucch_allocator std::optional csi_resource; [[nodiscard]] pucch_uci_bits get_uci_bits() const; - [[nodiscard]] bool is_emtpy() const; + [[nodiscard]] bool is_empty() const; [[nodiscard]] unsigned get_nof_grants() const; }; @@ -142,8 +142,8 @@ class pucch_allocator_impl final : public pucch_allocator /// //////////// Main private functions ////////////// // Allocates the PUCCH (common) resource for HARQ-(N)-ACK. - std::optional alloc_pucch_common_res_harq(cell_slot_resource_allocator& pucch_alloc, - const dci_context_information& dci_info); + std::optional alloc_pucch_common_res_harq(const cell_slot_resource_allocator& pucch_alloc, + const dci_context_information& dci_info); void compute_pucch_common_params_and_alloc(cell_slot_resource_allocator& pucch_alloc, rnti_t rnti, @@ -208,21 +208,21 @@ class pucch_allocator_impl final : public pucch_allocator const ue_cell_configuration& ue_cell_cfg); // Fills the PUCCH HARQ PDU for common resources. - void fill_pucch_harq_common_grant(pucch_info& pucch_info, rnti_t rnti, const pucch_res_alloc_cfg& pucch_res); + void fill_pucch_harq_common_grant(pucch_info& pucch_info, rnti_t rnti, const pucch_res_alloc_cfg& pucch_res) const; // Fills the PUCCH Format 0 PDU. void fill_pucch_ded_format0_grant(pucch_info& pucch_grant, rnti_t crnti, const pucch_resource& pucch_ded_res_cfg, unsigned harq_ack_bits, - sr_nof_bits sr_bits); + sr_nof_bits sr_bits) const; // Fills the PUCCH Format 1 PDU. void fill_pucch_ded_format1_grant(pucch_info& pucch_grant, rnti_t crnti, const pucch_resource& pucch_ded_res_cfg, unsigned harq_ack_bits, - sr_nof_bits sr_bits); + sr_nof_bits sr_bits) const; // Fills the PUCCH Format 2 PDU. void fill_pucch_format2_grant(pucch_info& pucch_grant, @@ -232,16 +232,26 @@ class pucch_allocator_impl final : public pucch_allocator unsigned nof_prbs, unsigned harq_ack_bits, sr_nof_bits sr_bits, - unsigned csi_part1_bits); + unsigned csi_part1_bits) const; + + // Fills the PUCCH Format 3 PDU. + void fill_pucch_format3_grant(pucch_info& pucch_grant, + rnti_t crnti, + const pucch_resource& pucch_ded_res_cfg, + const ue_cell_configuration& ue_cell_cfg, + unsigned nof_prbs, + unsigned harq_ack_bits, + sr_nof_bits sr_bits, + unsigned csi_part1_bits) const; /// //////////// Private helpers ////////////// - void remove_unsed_pucch_res(slot_point sl_tx, - pucch_grant_list grants_to_tx, - ue_grants& existing_pucchs, - const ue_cell_configuration& ue_cell_cfg); + void remove_unused_pucch_res(slot_point sl_tx, + const pucch_grant_list& grants_to_tx, + const ue_grants& existing_pucchs, + const ue_cell_configuration& ue_cell_cfg); - unsigned get_max_pucch_grants(unsigned currently_allocated_puschs); + unsigned get_max_pucch_grants(unsigned currently_allocated_puschs) const; // \brief Ring of PUCCH allocations indexed by slot. circular_array pucch_grants_alloc_grid; From 6d600280e27aaaebac4dc61911da80822704f5aa Mon Sep 17 00:00:00 2001 From: Jonathan Pichel Carrera Date: Tue, 17 Dec 2024 14:56:23 +0100 Subject: [PATCH 210/227] mac: review support pucch format 3 in pucch_allocator --- include/srsran/ran/pucch/pucch_info.h | 43 ++++-------------- lib/ran/pucch/pucch_info.cpp | 38 ++++++++++++++++ .../pucch_scheduling/pucch_allocator_impl.cpp | 44 +++++++++---------- 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/include/srsran/ran/pucch/pucch_info.h b/include/srsran/ran/pucch/pucch_info.h index 68c32e843a..e3adb38939 100644 --- a/include/srsran/ran/pucch/pucch_info.h +++ b/include/srsran/ran/pucch/pucch_info.h @@ -132,20 +132,8 @@ unsigned get_pucch_format2_max_nof_prbs(unsigned nof_payload_bits, unsigned nof_ /// \c PUCCH-FormatConfig, TS 38.331. /// \return The number of PRBs for the PUCCH format 2 resource. Note that the returned number of PRBs might not be /// enough to allocate the payload size; it's the caller's responsibility to perform this check. -inline unsigned -get_pucch_format2_nof_prbs(unsigned nof_payload_bits, unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate) -{ - if (nof_payload_bits == 0 or nof_symbols == 0) { - return 0; - } - if (max_nof_prbs == 1) { - return 1; - } - - const unsigned estimated_nof_prbs = get_pucch_format2_max_nof_prbs(nof_payload_bits, nof_symbols, max_code_rate); - - return std::min(estimated_nof_prbs, max_nof_prbs); -} +unsigned +get_pucch_format2_nof_prbs(unsigned nof_payload_bits, unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate); /// \brief Calculates the maximum payload for a PUCCH Format 2 transmission. /// \param[in] max_nof_prbs Transmission bandwidth in PRBs. @@ -210,26 +198,13 @@ unsigned get_pucch_format3_max_nof_prbs(unsigned nof_pay /// \param[in] pi2_bpsk Flag indicating if pi/2-BPSK modulation is used. /// \return The number of PRBs for the PUCCH format 3 resource. Note that the returned number of PRBs might not be /// enough to allocate the payload size; it's the caller's responsibility to perform this check. -inline unsigned get_pucch_format3_nof_prbs(unsigned nof_payload_bits, - unsigned max_nof_prbs, - unsigned nof_symbols, - float max_code_rate, - bool intraslot_freq_hopping, - bool additional_dmrs, - bool pi2_bpsk) -{ - if (nof_payload_bits == 0 or nof_symbols == 0) { - return 0; - } - if (max_nof_prbs == 1) { - return 1; - } - - const unsigned estimated_nof_prbs = get_pucch_format3_max_nof_prbs( - nof_payload_bits, nof_symbols, max_code_rate, intraslot_freq_hopping, additional_dmrs, pi2_bpsk); - - return std::min(estimated_nof_prbs, max_nof_prbs); -} +unsigned get_pucch_format3_nof_prbs(unsigned nof_payload_bits, + unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk); /// \brief Calculates the maximum payload for a PUCCH Format 3 transmission. /// \param[in] max_nof_prbs Transmission bandwidth in PRBs. diff --git a/lib/ran/pucch/pucch_info.cpp b/lib/ran/pucch/pucch_info.cpp index e0e9e4cc7a..9874fe7ca4 100644 --- a/lib/ran/pucch/pucch_info.cpp +++ b/lib/ran/pucch/pucch_info.cpp @@ -36,6 +36,23 @@ unsigned srsran::get_pucch_format2_max_nof_prbs(unsigned nof_payload_bits, unsig (static_cast(pucch_constants::FORMAT2_NOF_DATA_SC * nof_symbols * nof_bits_qpsk_symbol) * max_code_rate))); } +unsigned srsran::get_pucch_format2_nof_prbs(unsigned nof_payload_bits, + unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate) +{ + if (nof_payload_bits == 0 or nof_symbols == 0) { + return 0; + } + if (max_nof_prbs == 1) { + return 1; + } + + const unsigned estimated_nof_prbs = get_pucch_format2_max_nof_prbs(nof_payload_bits, nof_symbols, max_code_rate); + + return std::min(estimated_nof_prbs, max_nof_prbs); +} + unsigned srsran::get_pucch_format2_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate) { constexpr unsigned nof_bits_qpsk_symbol = 2; @@ -140,6 +157,27 @@ unsigned srsran::get_pucch_format3_max_nof_prbs(unsigned return nof_prbs; } +unsigned srsran::get_pucch_format3_nof_prbs(unsigned nof_payload_bits, + unsigned max_nof_prbs, + unsigned nof_symbols, + float max_code_rate, + bool intraslot_freq_hopping, + bool additional_dmrs, + bool pi2_bpsk) +{ + if (nof_payload_bits == 0 or nof_symbols == 0) { + return 0; + } + if (max_nof_prbs == 1) { + return 1; + } + + const unsigned estimated_nof_prbs = get_pucch_format3_max_nof_prbs( + nof_payload_bits, nof_symbols, max_code_rate, intraslot_freq_hopping, additional_dmrs, pi2_bpsk); + + return std::min(estimated_nof_prbs, max_nof_prbs); +} + unsigned srsran::get_pucch_format3_max_payload(unsigned max_nof_prbs, unsigned nof_symbols, float max_code_rate, diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index d5f0c2dcd1..f47545d47d 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -129,9 +129,8 @@ std::optional pucch_allocator_impl::alloc_common_pucch_harq_ack_ue(cel return std::nullopt; } - // TODO: why F2 or F1? - // If there are existing PUCCH grants that are either F2 for CSI or F1 for SR, allocate the PUCCH common - // grant anyway without multiplexing it with the existing one. Otherwise, if the existing grant is F1 for HARQ-ACK, + // If there are existing PUCCH grants that are either F2/F3/F4 for CSI or F0/F1 for SR, allocate the PUCCH common + // grant anyway without multiplexing it with the existing one. Otherwise, if the existing grant is F0/F1 for HARQ-ACK, // do not allocate on the same slot. const bool has_existing_ded_harq_grants = grants_ue_it != pucch_grants_slot.end() and grants_ue_it->pucch_grants.harq_resource.has_value(); @@ -208,8 +207,7 @@ std::optional pucch_allocator_impl::alloc_common_and_ded_harq_res(cell ue_grants_it->pucch_grants.csi_resource.has_value()), "It is expected that there are either no grants, or at most 1 PUCCH grant (SR grant or CSI grant)"); - // TODO: why F2 or F1? - // If there are no existing grants or if the existing one is for SR with Format 1, we need to add 2 additional PUCCH + // If there are no existing grants or if the existing one is for SR with Format 0/1, we need to add 2 additional PUCCH // grants: 1 on common resources and 1 on dedicated resources (for HARQ-ACK bit). // In the case of CSI, the number of PUCCH additional grants depends on the PUCCH resources configuration, but it will // never be more than 2. The exact number cannot be known at this point. @@ -372,7 +370,7 @@ void pucch_allocator_impl::pucch_allocate_sr_opportunity(cell_slot_resource_allo const pucch_format format = pucch_sr_res->format; // Allocate PUCCH SR grant only. - constexpr unsigned harq_ack_bits_increment = 0U; + static constexpr unsigned harq_ack_bits_increment = 0U; if (format == pucch_format::FORMAT_0) { fill_pucch_ded_format0_grant(pucch_slot_alloc.result.ul.pucchs.emplace_back(), crnti, @@ -856,9 +854,9 @@ pucch_allocator_impl::alloc_pucch_common_res_harq(const cell_slot_resource_alloc const dci_context_information& dci_info) { // As per Section 9.2.1, TS 38.213, this is the max value of \f$\Delta_{PRI}\f$, which is a 3-bit unsigned. - constexpr unsigned max_d_pri = 7; + static constexpr unsigned max_d_pri = 7; // As per Section 9.2.1, TS 38.213, r_pucch can take values within {0,...,15}. - constexpr unsigned r_pucch_invalid = 16; + static constexpr unsigned r_pucch_invalid = 16; // Get the parameter N_bwp_size, which is the Initial UL BWP size in PRBs, as per TS 38.213, Section 9.2.1. const unsigned size_ul_bwp = cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.length(); @@ -1076,7 +1074,7 @@ void pucch_allocator_impl::fill_pucch_harq_common_grant(pucch_info& break; } default: - srsran_assert(false, "PUCCH Format must be from 0 to 4, but only 0 and 1 are currently supported"); + srsran_assert(false, "Only PUCCH Format 0 and 1 can be used for PUCCH common resources"); } } @@ -1094,7 +1092,7 @@ pucch_allocator_impl::find_common_and_ded_harq_res_available(cell_slot_resource_ const unsigned start_cce_idx = dci_info.cces.ncce; // As per Section 9.2.1, TS 38.213, this is the max value of \f$\Delta_{PRI}\f$, which is a 3-bit unsigned. - constexpr unsigned max_d_pri = 7; + static constexpr unsigned max_d_pri = 7; for (unsigned d_pri = 0; d_pri != max_d_pri + 1; ++d_pri) { // The PUCCH allocation may result in a temporary reservation of PUCCH resources, which need to be released in // case of failure or in case the multiplexing results in a different final PUCCH resource. If we don't reset the @@ -1179,8 +1177,8 @@ std::optional pucch_allocator_impl::allocate_harq_grant(cell_slot_reso } // Allocate the new grant on PUCCH F1 resources for HARQ-ACK bits (without SR). - pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); - constexpr unsigned harq_bits_in_new_pucch_grant = 1; + pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); + static constexpr unsigned harq_bits_in_new_pucch_grant = 1; if (pucch_harq_res_info.pucch_res->format == pucch_format::FORMAT_0) { fill_pucch_ded_format0_grant( pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, harq_bits_in_new_pucch_grant, sr_nof_bits::no_sr); @@ -1252,8 +1250,8 @@ void pucch_allocator_impl::allocate_csi_grant(cell_slot_resource_allocator& pucc // Allocate a PUCCH PDU in the list and fill it with the parameters. pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); // Neither HARQ-ACK bits. - constexpr unsigned harq_ack_bits_only_csi = 0U; - constexpr sr_nof_bits sr_bits_only_csi = sr_nof_bits::no_sr; + static constexpr unsigned harq_ack_bits_only_csi = 0U; + static constexpr sr_nof_bits sr_bits_only_csi = sr_nof_bits::no_sr; switch (csi_f2_f3_f4_res->format) { case pucch_format::FORMAT_2: fill_pucch_format2_grant(pucch_pdu, @@ -1276,7 +1274,7 @@ void pucch_allocator_impl::allocate_csi_grant(cell_slot_resource_allocator& pucc csi_part1_bits); break; default: - srsran_assertion_failure("PUCCH resource for CSI must be of Formats 2, 3 or 4"); + srsran_assertion_failure("PUCCH resource for CSI must be of Formats 2, or 3"); } // Save the info in the scheduler list of PUCCH grants. @@ -1361,14 +1359,13 @@ void pucch_allocator_impl::fill_pucch_format2_grant(pucch_info& sr_nof_bits sr_bits, unsigned csi_part1_bits) const { - const auto& res_f2 = std::get(pucch_ded_res_cfg.format_params); - pucch_pdu.crnti = crnti; pucch_pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; pucch_pdu.format = pucch_format::FORMAT_2; // Set PRBs and symbols, first. pucch_pdu.resources.prbs.set(pucch_ded_res_cfg.starting_prb, pucch_ded_res_cfg.starting_prb + nof_prbs); + const auto& res_f2 = std::get(pucch_ded_res_cfg.format_params); pucch_pdu.resources.symbols.set(res_f2.starting_sym_idx, res_f2.starting_sym_idx + res_f2.nof_symbols); if (pucch_ded_res_cfg.second_hop_prb.has_value()) { pucch_pdu.resources.second_hop_prbs.set(pucch_ded_res_cfg.second_hop_prb.value(), @@ -1406,14 +1403,13 @@ void pucch_allocator_impl::fill_pucch_format3_grant(pucch_info& sr_nof_bits sr_bits, unsigned csi_part1_bits) const { - const auto& res_f3 = std::get(pucch_ded_res_cfg.format_params); - pucch_pdu.crnti = crnti; pucch_pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; pucch_pdu.format = pucch_format::FORMAT_3; // Set PRBs and symbols, first. pucch_pdu.resources.prbs.set(pucch_ded_res_cfg.starting_prb, pucch_ded_res_cfg.starting_prb + nof_prbs); + const auto& res_f3 = std::get(pucch_ded_res_cfg.format_params); pucch_pdu.resources.symbols.set(res_f3.starting_sym_idx, res_f3.starting_sym_idx + res_f3.nof_symbols); if (pucch_ded_res_cfg.second_hop_prb.has_value()) { pucch_pdu.resources.second_hop_prbs.set(pucch_ded_res_cfg.second_hop_prb.value(), @@ -1540,7 +1536,7 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& return allocate_grants(pucch_slot_alloc, current_grants, current_grants.rnti, grants_to_tx, ue_cell_cfg); } -// TODO: check how to handle F0+F3/F4 +// TODO: check how to handle F0+F3/F4. static unsigned get_pucch_resource_ind_f0_sr_csi(pucch_uci_bits bits, const pucch_config& pucch_cfg) { // With Format 0, with HARQ-ACK bits <= 2, pick a resource from PUCCH resource set 0. @@ -1737,7 +1733,8 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator // If the HARQ PDU uses F0, there can be 1 HARQ PDU + an optional SR (F0) or CSI (F2). In any case, we only need to // update the HARQ-ACK bits in the HARQ-ACK PDU. - // TODO: handle F0+F3/F4 + // TODO: handle F0+F3/F4. + static constexpr unsigned csi_bits_format_0_and_1 = 0U; if (existing_pdus.harq_pdu->format == pucch_format::FORMAT_0) { const pucch_resource* pucch_res_cfg = resource_manager.reserve_set_0_res_by_res_indicator( sl_tx, current_grants.rnti, current_grants.pucch_grants.harq_resource.value().harq_id.pucch_res_ind, pucch_cfg); @@ -1753,7 +1750,7 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator current_grants.pucch_grants.harq_resource.value().bits.sr_bits); existing_pdus.update_harq_pdu_bits(new_bits.harq_ack_nof_bits, current_grants.pucch_grants.harq_resource.value().bits.sr_bits, - 0U, + csi_bits_format_0_and_1, *pucch_res_cfg, std::nullopt); // Update the current grant with the new UCI (HARQ) bits. @@ -1779,7 +1776,7 @@ pucch_allocator_impl::allocate_without_multiplexing(cell_slot_resource_allocator const auto& common_params = ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value().format_1_common_param; existing_pdus.update_harq_pdu_bits( - new_bits.harq_ack_nof_bits, sr_nof_bits::no_sr, 0U, *pucch_res_cfg, common_params); + new_bits.harq_ack_nof_bits, sr_nof_bits::no_sr, csi_bits_format_0_and_1, *pucch_res_cfg, common_params); // Update the current grants with the new UCI (HARQ) bits. current_grants.pucch_grants.harq_resource.value().bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; if (existing_pdus.sr_pdu != nullptr) { @@ -1949,7 +1946,6 @@ pucch_allocator_impl::multiplex_resources(slot_point sl_tx, // The PUCCH resource multiplexing algorithm above is specified from the UE's perspective. In the GNB, we need to add // an extra resource Format 1 if slot there is a SR opportunity and HARQ bits to be reported with PUCCH Format 1. - // TODO: why? if (resource_set_q.size() == 1 and resource_set_q.front().format == pucch_format::FORMAT_1 and resource_set_q.front().bits.harq_ack_nof_bits != 0 and resource_set_q.front().bits.sr_bits != sr_nof_bits::no_sr) { From 491f2a4f0a3420dcccb2ad8418eeae01c6a8c5be Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 16:35:30 +0100 Subject: [PATCH 211/227] improve log metric formatting for UE bitrate and crc delay --- .../du_high_scheduler_cell_metrics_consumers.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp index f61de9aa58..9b388fdbf8 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -304,7 +304,7 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr fmt::format_to(buffer, "Cell Scheduler Metrics:"); fmt::format_to( buffer, - " total_dl_bitrate_kbps={} total_ul_bitrate_kbps={} error_indications={} mean_latency={}usec latency_hist=[{}]", + " total_dl_brate={}bps total_ul_brate={}bps error_indications={} mean_latency={}usec latency_hist=[{}]", float_to_eng_string(sum_dl_bitrate_kbps * 1e3, 1, false), float_to_eng_string(sum_ul_bitrate_kbps * 1e3, 1, false), metrics.nof_error_indications, @@ -346,9 +346,9 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr fmt::format_to(buffer, " dl_mcs={}", int(ue.dl_mcs.to_uint())); if (ue.dl_brate_kbps > 0) { - fmt::format_to(buffer, " dl_brate_kbps={}", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, false)); + fmt::format_to(buffer, " dl_brate={}bps", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, false)); } else { - fmt::format_to(buffer, " dl_brate_kbps={}", 0); + fmt::format_to(buffer, " dl_brate={}bps", 0); } fmt::format_to(buffer, " dl_nof_ok={}", ue.dl_nof_ok); fmt::format_to(buffer, " dl_nof_nok={}", ue.dl_nof_nok); @@ -382,9 +382,9 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr fmt::format_to(buffer, " ul_mcs={}", ue.ul_mcs.to_uint()); if (ue.ul_brate_kbps > 0) { - fmt::format_to(buffer, " ul_brate_kbps={}", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, false)); + fmt::format_to(buffer, " ul_brate={}bps", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, false)); } else { - fmt::format_to(buffer, " ul_brate_kbps={}", 0); + fmt::format_to(buffer, " ul_brate={}bps", 0); } fmt::format_to(buffer, " ul_nof_ok={}", ue.ul_nof_ok); fmt::format_to(buffer, " ul_nof_nok={}", ue.ul_nof_nok); @@ -392,7 +392,7 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; if (ul_total > 0) { fmt::format_to(buffer, " ul_error_rate={}%", int((float)100 * ue.ul_nof_nok / ul_total)); - fmt::format_to(buffer, " crc_delay_ms={}", ue.ul_delay_ms); + fmt::format_to(buffer, " crc_delay_ms={:.3}", ue.ul_delay_ms); } else { fmt::format_to(buffer, " ul_error_rate={}%", 0); fmt::format_to(buffer, " crc_delay_ms=n/a"); From 9dff8605ddd2872ea57558e248046934ae800849 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 17:11:21 +0100 Subject: [PATCH 212/227] log proportion of PRBs allocated in the log metrics --- ..._high_scheduler_cell_metrics_consumers.cpp | 26 +++++++++++---- .../logging/scheduler_metric_handler.cpp | 32 ++++++++----------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp index 9b388fdbf8..907443e998 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -287,6 +287,12 @@ void scheduler_cell_metrics_consumer_json::handle_metric(const app_services::met log_chan(ctx); } +template +static ResultType to_percentage(unsigned numerator, unsigned denominator) +{ + return static_cast(100.0 * static_cast(numerator) / static_cast(denominator)); +} + void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metrics_set& metric) { const scheduler_cell_metrics& metrics = static_cast(metric).get_metrics(); @@ -353,13 +359,14 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr fmt::format_to(buffer, " dl_nof_ok={}", ue.dl_nof_ok); fmt::format_to(buffer, " dl_nof_nok={}", ue.dl_nof_nok); unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; - if (dl_total > 0) { - fmt::format_to(buffer, " dl_error_rate={}%", int((float)100 * ue.dl_nof_nok / dl_total)); - } else { - fmt::format_to(buffer, " dl_error_rate={}%", 0); - } + fmt::format_to(buffer, " dl_error_rate={}%", dl_total > 0 ? to_percentage(ue.dl_nof_nok, dl_total) : 0); fmt::format_to(buffer, " dl_bs={}", scaled_fmt_integer(ue.dl_bs, false)); - fmt::format_to(buffer, " dl_nof_prbs={}", ue.tot_dl_prbs_used); + fmt::format_to(buffer, + " dl_nof_prbs={} dl_prb_ratio={:.2}%", + ue.tot_dl_prbs_used, + metrics.nof_dl_slots > 0 + ? to_percentage(ue.tot_dl_prbs_used, metrics.nof_dl_slots * metrics.nof_prbs) + : 0); if (ue.last_dl_olla.has_value()) { fmt::format_to(buffer, " dl_olla={}", ue.last_dl_olla); } @@ -397,7 +404,12 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr fmt::format_to(buffer, " ul_error_rate={}%", 0); fmt::format_to(buffer, " crc_delay_ms=n/a"); } - fmt::format_to(buffer, " ul_nof_prbs={}", ue.tot_ul_prbs_used); + fmt::format_to(buffer, + " ul_nof_prbs={} ul_prb_ratio={:.2}%", + ue.tot_ul_prbs_used, + metrics.nof_ul_slots > 0 + ? to_percentage(ue.tot_ul_prbs_used, metrics.nof_ul_slots * metrics.nof_prbs) + : 0); fmt::format_to(buffer, " bsr={}", scaled_fmt_integer(ue.bsr, false)); fmt::format_to(buffer, " sr_count={}", ue.sr_count); if (ue.last_ul_olla.has_value()) { diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 7f2daf89bb..7be20ac4f9 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -264,10 +264,6 @@ void cell_metrics_handler::report_metrics() void cell_metrics_handler::handle_slot_result(const sched_result& slot_result, std::chrono::microseconds slot_decision_latency) { - // Count only full DL/UL slots. - bool full_dl_slot = (slot_result.dl.nof_dl_symbols == 14); - bool full_ul_slot = (slot_result.ul.nof_ul_symbols == 14); - for (const dl_msg_alloc& dl_grant : slot_result.dl.ue_grants) { auto it = rnti_to_ue_index_lookup.find(dl_grant.pdsch_cfg.rnti); if (it == rnti_to_ue_index_lookup.end()) { @@ -280,13 +276,12 @@ void cell_metrics_handler::handle_slot_result(const sched_result& slot_res u.data.nof_dl_cws++; } if (dl_grant.pdsch_cfg.rbs.is_type0()) { - u.data.tot_dl_prbs_used += full_dl_slot ? convert_rbgs_to_prbs(dl_grant.pdsch_cfg.rbs.type0(), - {0, cell_cfg.nof_dl_prbs}, - get_nominal_rbg_size(cell_cfg.nof_dl_prbs, true)) - .count() - : 0; + u.data.tot_dl_prbs_used += convert_rbgs_to_prbs(dl_grant.pdsch_cfg.rbs.type0(), + {0, cell_cfg.nof_dl_prbs}, + get_nominal_rbg_size(cell_cfg.nof_dl_prbs, true)) + .count(); } else if (dl_grant.pdsch_cfg.rbs.is_type1()) { - u.data.tot_dl_prbs_used += full_dl_slot ? (dl_grant.pdsch_cfg.rbs.type1().length()) : 0; + u.data.tot_dl_prbs_used += (dl_grant.pdsch_cfg.rbs.type1().length()); } u.last_dl_olla = dl_grant.context.olla_offset; } @@ -298,14 +293,12 @@ void cell_metrics_handler::handle_slot_result(const sched_result& slot_res continue; } if (ul_grant.pusch_cfg.rbs.is_type0()) { - ues[it->second].data.tot_ul_prbs_used += - full_ul_slot ? convert_rbgs_to_prbs(ul_grant.pusch_cfg.rbs.type0(), - {0, cell_cfg.nof_dl_prbs}, - get_nominal_rbg_size(cell_cfg.nof_dl_prbs, true)) - .count() - : 0; + ues[it->second].data.tot_ul_prbs_used += convert_rbgs_to_prbs(ul_grant.pusch_cfg.rbs.type0(), + {0, cell_cfg.nof_dl_prbs}, + get_nominal_rbg_size(cell_cfg.nof_dl_prbs, true)) + .count(); } else if (ul_grant.pusch_cfg.rbs.is_type1()) { - ues[it->second].data.tot_ul_prbs_used += full_ul_slot ? (ul_grant.pusch_cfg.rbs.type1().length()) : 0; + ues[it->second].data.tot_ul_prbs_used += (ul_grant.pusch_cfg.rbs.type1().length()); } ue_metric_context& u = ues[it->second]; u.data.ul_mcs += ul_grant.pusch_cfg.mcs_index.to_uint(); @@ -313,8 +306,9 @@ void cell_metrics_handler::handle_slot_result(const sched_result& slot_res u.data.nof_puschs++; } - nof_dl_slots += full_dl_slot; - nof_ul_slots += full_ul_slot; + // Count only full DL/UL slots. + nof_dl_slots += (slot_result.dl.nof_dl_symbols > 0); + nof_ul_slots += (slot_result.ul.nof_ul_symbols == 14); // Note: PUSCH in special slot not supported.; // Process latency. decision_latency_sum += slot_decision_latency; From 00e518a18e8a35475a5f4ad3d05986e4631aab41 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 17:13:57 +0100 Subject: [PATCH 213/227] log total number of DL and UL PRBs in a metric report --- ...u_high_scheduler_cell_metrics_consumers.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp index 907443e998..25ec7cc5df 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -308,14 +308,16 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr // log cell-wide metrics fmt::format_to(buffer, "Cell Scheduler Metrics:"); - fmt::format_to( - buffer, - " total_dl_brate={}bps total_ul_brate={}bps error_indications={} mean_latency={}usec latency_hist=[{}]", - float_to_eng_string(sum_dl_bitrate_kbps * 1e3, 1, false), - float_to_eng_string(sum_ul_bitrate_kbps * 1e3, 1, false), - metrics.nof_error_indications, - metrics.average_decision_latency.count(), - fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); + fmt::format_to(buffer, + " total_dl_brate={}bps total_ul_brate={}bps total_dl_prbs={} total_ul_prbs={} error_indications={} " + "mean_latency={}usec latency_hist=[{}]", + float_to_eng_string(sum_dl_bitrate_kbps * 1e3, 1, false), + float_to_eng_string(sum_ul_bitrate_kbps * 1e3, 1, false), + metrics.nof_dl_slots * metrics.nof_prbs, + metrics.nof_ul_slots * metrics.nof_prbs, + metrics.nof_error_indications, + metrics.average_decision_latency.count(), + fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); if (not metrics.events.empty()) { fmt::format_to(buffer, " events=["); bool first = true; From b521a3f19a12cf6612e6d7816903aac6986ad58d Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 17:25:14 +0100 Subject: [PATCH 214/227] metrics: log the total number of prbs and nof DL/UL slots --- ..._high_scheduler_cell_metrics_consumers.cpp | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp index 25ec7cc5df..f11eab2f3d 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -308,16 +308,18 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr // log cell-wide metrics fmt::format_to(buffer, "Cell Scheduler Metrics:"); - fmt::format_to(buffer, - " total_dl_brate={}bps total_ul_brate={}bps total_dl_prbs={} total_ul_prbs={} error_indications={} " - "mean_latency={}usec latency_hist=[{}]", - float_to_eng_string(sum_dl_bitrate_kbps * 1e3, 1, false), - float_to_eng_string(sum_ul_bitrate_kbps * 1e3, 1, false), - metrics.nof_dl_slots * metrics.nof_prbs, - metrics.nof_ul_slots * metrics.nof_prbs, - metrics.nof_error_indications, - metrics.average_decision_latency.count(), - fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); + fmt::format_to( + buffer, + " total_dl_brate={}bps total_ul_brate={}bps nof_prbs={} nof_dl_slots={} nof_ul_slots={} error_indications={} " + "mean_latency={}usec latency_hist=[{}]", + float_to_eng_string(sum_dl_bitrate_kbps * 1e3, 1, false), + float_to_eng_string(sum_ul_bitrate_kbps * 1e3, 1, false), + metrics.nof_prbs, + metrics.nof_dl_slots, + metrics.nof_ul_slots, + metrics.nof_error_indications, + metrics.average_decision_latency.count(), + fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); if (not metrics.events.empty()) { fmt::format_to(buffer, " events=["); bool first = true; @@ -363,12 +365,7 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; fmt::format_to(buffer, " dl_error_rate={}%", dl_total > 0 ? to_percentage(ue.dl_nof_nok, dl_total) : 0); fmt::format_to(buffer, " dl_bs={}", scaled_fmt_integer(ue.dl_bs, false)); - fmt::format_to(buffer, - " dl_nof_prbs={} dl_prb_ratio={:.2}%", - ue.tot_dl_prbs_used, - metrics.nof_dl_slots > 0 - ? to_percentage(ue.tot_dl_prbs_used, metrics.nof_dl_slots * metrics.nof_prbs) - : 0); + fmt::format_to(buffer, " dl_nof_prbs={}", ue.tot_dl_prbs_used); if (ue.last_dl_olla.has_value()) { fmt::format_to(buffer, " dl_olla={}", ue.last_dl_olla); } @@ -399,19 +396,13 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr fmt::format_to(buffer, " ul_nof_nok={}", ue.ul_nof_nok); unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; + fmt::format_to(buffer, " ul_error_rate={}%", ul_total > 0 ? to_percentage(ue.ul_nof_nok, ul_total) : 0); if (ul_total > 0) { - fmt::format_to(buffer, " ul_error_rate={}%", int((float)100 * ue.ul_nof_nok / ul_total)); fmt::format_to(buffer, " crc_delay_ms={:.3}", ue.ul_delay_ms); } else { - fmt::format_to(buffer, " ul_error_rate={}%", 0); fmt::format_to(buffer, " crc_delay_ms=n/a"); } - fmt::format_to(buffer, - " ul_nof_prbs={} ul_prb_ratio={:.2}%", - ue.tot_ul_prbs_used, - metrics.nof_ul_slots > 0 - ? to_percentage(ue.tot_ul_prbs_used, metrics.nof_ul_slots * metrics.nof_prbs) - : 0); + fmt::format_to(buffer, " ul_nof_prbs={}", ue.tot_ul_prbs_used); fmt::format_to(buffer, " bsr={}", scaled_fmt_integer(ue.bsr, false)); fmt::format_to(buffer, " sr_count={}", ue.sr_count); if (ue.last_ul_olla.has_value()) { From a4bdd7a623572836d2d171312f7f68d2017afdd7 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 18:35:53 +0100 Subject: [PATCH 215/227] sched: report average latency that it takes for a UL CE to reach the scheduler --- .../du_high_scheduler_cell_metrics_consumers.cpp | 5 +++++ include/srsran/scheduler/scheduler_metrics.h | 1 + lib/scheduler/logging/scheduler_metric_handler.cpp | 14 ++++++++++---- lib/scheduler/logging/scheduler_metrics_handler.h | 8 ++++++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp index f11eab2f3d..38655a05fd 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -423,6 +423,11 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr } else { fmt::format_to(buffer, " last_phr=n/a"); } + if (ue.mean_ce_delay_msec.has_value()) { + fmt::format_to(buffer, " ul_ce_delay={:.2}ms", ue.mean_ce_delay_msec.value()); + } else { + fmt::format_to(buffer, " ul_ce_delay=n/a"); + } logger.info("{}", to_c_str(buffer)); buffer.clear(); diff --git a/include/srsran/scheduler/scheduler_metrics.h b/include/srsran/scheduler/scheduler_metrics.h index 1a2f50a900..28ac8b2a3a 100644 --- a/include/srsran/scheduler/scheduler_metrics.h +++ b/include/srsran/scheduler/scheduler_metrics.h @@ -47,6 +47,7 @@ struct scheduler_ue_metrics { std::optional last_dl_olla; std::optional last_ul_olla; std::optional last_phr; + std::optional mean_ce_delay_msec; /// Time advance statistics in seconds. sample_statistics ta_stats; sample_statistics pusch_ta_stats; diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 7be20ac4f9..b581eb19fb 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -204,8 +204,10 @@ void cell_metrics_handler::handle_ul_phr_indication(const ul_phr_indication_mess // Store last PHR. if (not phr_ind.phr.get_phr().empty()) { // Log the floor of the average of the PH interval. - interval rg = phr_ind.phr.get_phr().front().ph; - u.last_phr = (rg.start() + rg.stop()) / 2; + interval rg = phr_ind.phr.get_phr().front().ph; + u.last_phr = (rg.start() + rg.stop()) / 2; + u.data.sum_ul_ce_delay_slots = last_slot_tx - phr_ind.slot_rx; + u.data.nof_ul_ces++; } } } @@ -229,7 +231,7 @@ void cell_metrics_handler::report_metrics() { for (ue_metric_context& ue : ues) { // Compute statistics of the UE metrics and push the result to the report. - scheduler_ue_metrics sched_ue_metrics = ue.compute_report(report_period); + scheduler_ue_metrics sched_ue_metrics = ue.compute_report(report_period, nof_slots_per_sf); sched_ue_metrics.mean_dl_prbs_used = nof_dl_slots > 0 ? static_cast(1.0 * sched_ue_metrics.tot_dl_prbs_used / nof_dl_slots) : 0; sched_ue_metrics.mean_ul_prbs_used = @@ -330,6 +332,7 @@ void cell_metrics_handler::push_result(slot_point sl_tx, { if (report_period_slots == 0) { // The SCS common is now known. + nof_slots_per_sf = get_nof_slots_per_subframe(to_subcarrier_spacing(sl_tx.numerology())); usecs slot_dur = usecs{1000U >> sl_tx.numerology()}; report_period_slots = usecs{report_period} / slot_dur; } @@ -346,7 +349,8 @@ void cell_metrics_handler::push_result(slot_point sl_tx, } scheduler_ue_metrics -cell_metrics_handler::ue_metric_context::compute_report(std::chrono::milliseconds metric_report_period) +cell_metrics_handler::ue_metric_context::compute_report(std::chrono::milliseconds metric_report_period, + unsigned nof_slots_per_sf) { scheduler_ue_metrics ret{}; ret.pci = pci; @@ -383,6 +387,8 @@ cell_metrics_handler::ue_metric_context::compute_report(std::chrono::millisecond ret.pucch_ta_stats = data.pucch_ta; ret.srs_ta_stats = data.srs_ta; ret.last_phr = last_phr; + ret.mean_ce_delay_msec = + data.nof_ul_ces > 0 ? (static_cast(data.sum_ul_ce_delay_slots) / (data.nof_ul_ces * nof_slots_per_sf)) : 0; // Reset UE stats metrics on every report. reset(); diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index 1ed4e2c172..c8175476b3 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -52,6 +52,8 @@ class cell_metrics_handler final : public sched_metrics_ue_configurator unsigned nof_pusch_rsrp_reports = 0; unsigned tot_dl_prbs_used = 0; unsigned tot_ul_prbs_used = 0; + unsigned sum_ul_ce_delay_slots = 0; + unsigned nof_ul_ces = 0; /// TA statistics over the metrics report interval, in seconds. sample_statistics ta; /// PUSCH TA statistics over the metrics report interval, in seconds. @@ -80,14 +82,16 @@ class cell_metrics_handler final : public sched_metrics_ue_configurator std::optional last_ul_olla; non_persistent_data data; - scheduler_ue_metrics compute_report(std::chrono::milliseconds metric_report_period); + scheduler_ue_metrics compute_report(std::chrono::milliseconds metric_report_period, unsigned nof_slots_per_sf); void reset(); }; scheduler_metrics_notifier& notifier; const std::chrono::milliseconds report_period; const cell_configuration& cell_cfg; - /// Derived value. + + // Derived values. + unsigned nof_slots_per_sf = 0; unsigned report_period_slots = 0; slot_point last_slot_tx; From 260487362ac0f5abfd879b773a835bb4132044a1 Mon Sep 17 00:00:00 2001 From: frankist Date: Mon, 16 Dec 2024 18:53:51 +0100 Subject: [PATCH 216/227] sched: remove redundant metrics --- include/srsran/scheduler/scheduler_metrics.h | 2 -- .../e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp | 12 ++++++++---- lib/scheduler/logging/scheduler_metric_handler.cpp | 7 +------ .../e2/e2sm_kpm_meas_provider_metrics_test.cpp | 4 +--- tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp | 8 -------- 5 files changed, 10 insertions(+), 23 deletions(-) diff --git a/include/srsran/scheduler/scheduler_metrics.h b/include/srsran/scheduler/scheduler_metrics.h index 28ac8b2a3a..69f8a72dd8 100644 --- a/include/srsran/scheduler/scheduler_metrics.h +++ b/include/srsran/scheduler/scheduler_metrics.h @@ -27,7 +27,6 @@ struct scheduler_ue_metrics { rnti_t rnti; sch_mcs_index dl_mcs; unsigned tot_dl_prbs_used; - double mean_dl_prbs_used; double dl_brate_kbps; unsigned dl_nof_ok; unsigned dl_nof_nok; @@ -36,7 +35,6 @@ struct scheduler_ue_metrics { float pucch_snr_db; sch_mcs_index ul_mcs; unsigned tot_ul_prbs_used; - double mean_ul_prbs_used; double ul_brate_kbps; double ul_delay_ms; unsigned ul_nof_ok; 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 1862061766..dda663c4aa 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 @@ -450,7 +450,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_used_dl(const asn1::e2sm::label_inf 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; - meas_record_item.set_integer() = last_ue_metrics[ue_idx].mean_dl_prbs_used; + unsigned ue_mean_dl_prbs_used = nof_dl_slots > 0 ? last_ue_metrics[ue_idx].tot_dl_prbs_used / nof_dl_slots : 0; + meas_record_item.set_integer() = ue_mean_dl_prbs_used; items.push_back(meas_record_item); meas_collected = true; } @@ -490,7 +491,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_used_ul(const asn1::e2sm::label_inf 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; - meas_record_item.set_integer() = last_ue_metrics[ue_idx].mean_ul_prbs_used; + unsigned ue_mean_ul_prbs_used = nof_ul_slots > 0 ? last_ue_metrics[ue_idx].tot_ul_prbs_used / nof_ul_slots : 0; + meas_record_item.set_integer() = ue_mean_ul_prbs_used; items.push_back(meas_record_item); meas_collected = true; } @@ -530,7 +532,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_dl(const asn1::e2sm::label 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; - meas_record_item.set_integer() = last_ue_metrics[ue_idx].mean_dl_prbs_used * 100 / nof_cell_prbs; + unsigned ue_mean_dl_prbs_used = nof_dl_slots > 0 ? last_ue_metrics[ue_idx].tot_dl_prbs_used / nof_dl_slots : 0; + meas_record_item.set_integer() = ue_mean_dl_prbs_used * 100 / nof_cell_prbs; items.push_back(meas_record_item); meas_collected = true; } @@ -569,7 +572,8 @@ bool e2sm_kpm_du_meas_provider_impl::get_prb_use_perc_ul(const asn1::e2sm::label 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; - meas_record_item.set_integer() = last_ue_metrics[ue_idx].mean_ul_prbs_used * 100 / nof_cell_prbs; + unsigned ue_mean_ul_prbs_used = nof_ul_slots > 0 ? last_ue_metrics[ue_idx].tot_ul_prbs_used / nof_ul_slots : 0; + meas_record_item.set_integer() = ue_mean_ul_prbs_used * 100 / nof_cell_prbs; items.push_back(meas_record_item); meas_collected = true; } diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index b581eb19fb..9f5de6a207 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -231,12 +231,7 @@ void cell_metrics_handler::report_metrics() { for (ue_metric_context& ue : ues) { // Compute statistics of the UE metrics and push the result to the report. - scheduler_ue_metrics sched_ue_metrics = ue.compute_report(report_period, nof_slots_per_sf); - sched_ue_metrics.mean_dl_prbs_used = - nof_dl_slots > 0 ? static_cast(1.0 * sched_ue_metrics.tot_dl_prbs_used / nof_dl_slots) : 0; - sched_ue_metrics.mean_ul_prbs_used = - nof_ul_slots > 0 ? static_cast(1.0 * sched_ue_metrics.tot_ul_prbs_used / nof_ul_slots) : 0; - next_report.ue_metrics.push_back(sched_ue_metrics); + next_report.ue_metrics.push_back(ue.compute_report(report_period, nof_slots_per_sf)); } next_report.nof_error_indications = error_indication_counter; diff --git a/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp b/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp index 2e0ba4560a..370662fe08 100644 --- a/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_metrics_test.cpp @@ -84,9 +84,7 @@ scheduler_cell_metrics generate_non_zero_sched_metrics() 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++) { @@ -310,4 +308,4 @@ TEST_F(e2sm_kpm_meas_provider_metrics_test, e2sm_kpm_return_e2_level_metric_with 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 c983dc6ddd..044ee876e2 100644 --- a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp @@ -243,16 +243,8 @@ scheduler_cell_metrics generate_sched_metrics(uint32_t ue_metrics.rnti = static_cast(0x1000 + ue_idx); ue_metrics.tot_dl_prbs_used = (ue_idx < dl_grants.size()) ? std::accumulate(dl_grants[ue_idx].begin(), dl_grants[ue_idx].end(), 0) : 0; - ue_metrics.mean_dl_prbs_used = - sched_metric.nof_dl_slots > 0 - ? static_cast(1.0 * ue_metrics.tot_dl_prbs_used / sched_metric.nof_dl_slots) - : 0; ue_metrics.tot_ul_prbs_used = (ue_idx < ul_grants.size()) ? std::accumulate(ul_grants[ue_idx].begin(), ul_grants[ue_idx].end(), 0) : 0; - ue_metrics.mean_ul_prbs_used = - sched_metric.nof_ul_slots > 0 - ? static_cast(1.0 * ue_metrics.tot_ul_prbs_used / sched_metric.nof_ul_slots) - : 0; sched_metric.ue_metrics.push_back(ue_metrics); } From 5e2b5fb70358e38ca827f18407c5bed63bc8830f Mon Sep 17 00:00:00 2001 From: frankist Date: Tue, 17 Dec 2024 16:50:08 +0100 Subject: [PATCH 217/227] sched: fix shadow variable --- lib/scheduler/logging/scheduler_metric_handler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index 9f5de6a207..44c868e3fa 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -345,7 +345,7 @@ void cell_metrics_handler::push_result(slot_point sl_tx, scheduler_ue_metrics cell_metrics_handler::ue_metric_context::compute_report(std::chrono::milliseconds metric_report_period, - unsigned nof_slots_per_sf) + unsigned slots_per_sf) { scheduler_ue_metrics ret{}; ret.pci = pci; @@ -383,7 +383,7 @@ cell_metrics_handler::ue_metric_context::compute_report(std::chrono::millisecond ret.srs_ta_stats = data.srs_ta; ret.last_phr = last_phr; ret.mean_ce_delay_msec = - data.nof_ul_ces > 0 ? (static_cast(data.sum_ul_ce_delay_slots) / (data.nof_ul_ces * nof_slots_per_sf)) : 0; + data.nof_ul_ces > 0 ? (static_cast(data.sum_ul_ce_delay_slots) / (data.nof_ul_ces * slots_per_sf)) : 0; // Reset UE stats metrics on every report. reset(); From b87dce46c1f217f89628e49fdded26eb2d639c5c Mon Sep 17 00:00:00 2001 From: faluco Date: Mon, 16 Dec 2024 19:26:19 +0100 Subject: [PATCH 218/227] [SUPPORT] Fix network gateway race conditions --- apps/cu/cu.cpp | 11 ++-- include/srsran/support/io/sctp_socket.h | 6 +- include/srsran/support/io/unique_fd.h | 3 + lib/gateways/sctp_network_client_impl.cpp | 34 ++++------ lib/gateways/sctp_network_client_impl.h | 3 - .../sctp_network_gateway_common_impl.cpp | 4 +- lib/gateways/sctp_network_gateway_impl.cpp | 10 +-- lib/gateways/sctp_network_server_impl.cpp | 12 ++-- lib/gateways/sctp_network_server_impl.h | 3 - lib/gateways/udp_network_gateway_impl.cpp | 64 ++++++++++++------- lib/gateways/udp_network_gateway_impl.h | 6 -- lib/support/network/io_broker_epoll.cpp | 13 ++-- lib/support/network/sctp_socket.cpp | 5 -- .../gateways/sctp_network_client_test.cpp | 5 +- 14 files changed, 92 insertions(+), 87 deletions(-) diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index b0bad2a2bb..520d25ceb9 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -296,13 +296,13 @@ int main(int argc, char** argv) std::unique_ptr e1_gw = create_e1_local_connector(e1_local_connector_config{*cu_up_dlt_pcaps.e1ap}); - // Create manager of timers for CU-CP and CU-UP, which will be - // driven by the system timer slot ticks. + // Create manager of timers for CU-CP and CU-UP, which will be driven by the system timer slot ticks. timer_manager app_timers{256}; timer_manager* cu_timers = &app_timers; - // Create time source that ticks the timers - io_timer_source time_source{app_timers, *epoll_broker, *workers.non_rt_hi_prio_exec, std::chrono::milliseconds{1}}; + // Create time source that ticks the timers. + std::optional time_source( + std::in_place_t{}, app_timers, *epoll_broker, *workers.non_rt_hi_prio_exec, std::chrono::milliseconds{1}); // Instantiate E2AP client gateway. std::unique_ptr e2_gw_cu_cp = create_e2_gateway_client( @@ -392,6 +392,9 @@ int main(int argc, char** argv) // Stop O-CU-CP activity. o_cucp_obj.get_cu_cp().stop(); + // Stop the timer source before stopping the workers. + time_source.reset(); + // Close PCAPs cu_logger.info("Closing PCAP files..."); cu_cp_dlt_pcaps.close(); diff --git a/include/srsran/support/io/sctp_socket.h b/include/srsran/support/io/sctp_socket.h index 65b2e21a3a..f96a12a524 100644 --- a/include/srsran/support/io/sctp_socket.h +++ b/include/srsran/support/io/sctp_socket.h @@ -44,13 +44,17 @@ class sctp_socket sctp_socket(); sctp_socket(sctp_socket&& other) noexcept = default; - ~sctp_socket(); sctp_socket& operator=(sctp_socket&& other) noexcept; bool close(); [[nodiscard]] bool is_open() const { return sock_fd.is_open(); } const unique_fd& fd() const { return sock_fd; } + void release() + { + int fd = sock_fd.release(); + sock_fd = unique_fd(fd, false); + } [[nodiscard]] bool bind(struct sockaddr& ai_addr, const socklen_t& ai_addrlen, const std::string& bind_interface); [[nodiscard]] bool connect(struct sockaddr& ai_addr, const socklen_t& ai_addrlen); diff --git a/include/srsran/support/io/unique_fd.h b/include/srsran/support/io/unique_fd.h index bbbc38d935..3cb6513e75 100644 --- a/include/srsran/support/io/unique_fd.h +++ b/include/srsran/support/io/unique_fd.h @@ -65,6 +65,9 @@ class unique_fd /// Returns the raw file descriptor value or -1 if the file descriptor is not open. [[nodiscard]] int value() const { return fd; } + /// Releases the ownership of the managed file descriptor. + [[nodiscard]] int release() { return std::exchange(fd, -1); } + private: /// Prints a close error message with the corresponding cause. void print_close_error_msg() diff --git a/lib/gateways/sctp_network_client_impl.cpp b/lib/gateways/sctp_network_client_impl.cpp index 6afee051a8..b1585382fe 100644 --- a/lib/gateways/sctp_network_client_impl.cpp +++ b/lib/gateways/sctp_network_client_impl.cpp @@ -119,10 +119,7 @@ class sctp_network_client_impl::sctp_send_notifier final : public sctp_associati sctp_network_client_impl::sctp_network_client_impl(const sctp_network_gateway_config& sctp_cfg, io_broker& broker_, task_executor& io_rx_executor_) : - sctp_network_gateway_common_impl(sctp_cfg), - broker(broker_), - io_rx_executor(io_rx_executor_), - temp_recv_buffer(network_gateway_sctp_max_len) + sctp_network_gateway_common_impl(sctp_cfg), broker(broker_), io_rx_executor(io_rx_executor_) { } @@ -180,6 +177,13 @@ sctp_network_client_impl::connect_to(const std::string& } } + // If a bind address is provided, create a socket here and bind it. + if (not node_cfg.bind_address.empty()) { + if (not create_and_bind_common()) { + return nullptr; + } + } + sockaddr_searcher searcher{dest_addr, dest_port, logger}; auto start = std::chrono::steady_clock::now(); // Create SCTP socket only if not created earlier during bind. Otherwise, reuse socket. @@ -247,8 +251,9 @@ sctp_network_client_impl::connect_to(const std::string& } // Register the socket in the IO broker. + socket.release(); io_sub = broker.register_fd( - unique_fd(socket.fd().value(), false), + unique_fd(socket.fd().value()), io_rx_executor, [this]() { receive(); }, [this](io_broker::error_code code) { @@ -276,8 +281,10 @@ sctp_network_client_impl::connect_to(const std::string& void sctp_network_client_impl::receive() { - struct sctp_sndrcvinfo sri = {}; - int msg_flags = 0; + struct sctp_sndrcvinfo sri = {}; + int msg_flags = 0; + std::array temp_recv_buffer; + // fromlen is an in/out variable in sctp_recvmsg. sockaddr_storage msg_src_addr; socklen_t msg_src_addrlen = sizeof(msg_src_addr); @@ -333,11 +340,6 @@ void sctp_network_client_impl::handle_sctp_shutdown_comp() // Unsubscribe from listening to new IO events. io_sub.reset(); - // Make sure to close any socket created and implicitly bound for any previous connection. - if (node_cfg.bind_address.empty()) { - socket.close(); - } - // Erase server_addr and notify dtor that connection is closed. std::unique_lock lock(connection_mutex); server_addr = {}; @@ -406,13 +408,5 @@ std::unique_ptr sctp_network_client_impl::create(const sctp // Create a SCTP client instance. std::unique_ptr client{new sctp_network_client_impl(sctp_cfg, broker_, io_rx_executor)}; - - // If a bind address is provided, create a socket here and bind it. - if (not sctp_cfg.bind_address.empty()) { - if (not client->create_and_bind_common()) { - return nullptr; - } - } - return client; } diff --git a/lib/gateways/sctp_network_client_impl.h b/lib/gateways/sctp_network_client_impl.h index 3a672c5a23..c454db8f98 100644 --- a/lib/gateways/sctp_network_client_impl.h +++ b/lib/gateways/sctp_network_client_impl.h @@ -61,9 +61,6 @@ class sctp_network_client_impl : public sctp_network_client, public sctp_network io_broker& broker; task_executor& io_rx_executor; - // Temporary buffer where read data is saved. - std::vector temp_recv_buffer; - // Handler of IO events. It is only accessed by the backend (io_broker), once the connection is set up. std::unique_ptr recv_handler; diff --git a/lib/gateways/sctp_network_gateway_common_impl.cpp b/lib/gateways/sctp_network_gateway_common_impl.cpp index 956a36080a..621e077225 100644 --- a/lib/gateways/sctp_network_gateway_common_impl.cpp +++ b/lib/gateways/sctp_network_gateway_common_impl.cpp @@ -69,9 +69,7 @@ bool sctp_network_gateway_common_impl::close_socket() { // Stop listening to new IO Rx events. io_sub.reset(); - - // Close SCTP socket. - return socket.close(); + return true; } expected sctp_network_gateway_common_impl::create_socket(int ai_family, int ai_socktype) const diff --git a/lib/gateways/sctp_network_gateway_impl.cpp b/lib/gateways/sctp_network_gateway_impl.cpp index cfd64f118c..39a43c9703 100644 --- a/lib/gateways/sctp_network_gateway_impl.cpp +++ b/lib/gateways/sctp_network_gateway_impl.cpp @@ -75,7 +75,8 @@ bool sctp_network_gateway_impl::create_and_connect() if (not socket.connect(*result->ai_addr, result->ai_addrlen)) { // connection failed, try next address - close_socket(); + io_sub.reset(); + socket.close(); continue; } @@ -115,11 +116,10 @@ void sctp_network_gateway_impl::receive() struct sctp_sndrcvinfo sri = {}; int msg_flags = 0; - // Fixme: consider class member on heap when sequential access is guaranteed - std::array tmp_mem; // no init + std::array temp_recv_buffer; int rx_bytes = ::sctp_recvmsg(socket.fd().value(), - tmp_mem.data(), + temp_recv_buffer.data(), network_gateway_sctp_max_len, (struct sockaddr*)&msg_src_addr, &msg_src_addrlen, @@ -134,7 +134,7 @@ void sctp_network_gateway_impl::receive() } } else { logger.debug("Received {} bytes on SCTP socket", rx_bytes); - span payload(tmp_mem.data(), rx_bytes); + span payload(temp_recv_buffer.data(), rx_bytes); if (msg_flags & MSG_NOTIFICATION) { // Received notification handle_notification(payload); diff --git a/lib/gateways/sctp_network_server_impl.cpp b/lib/gateways/sctp_network_server_impl.cpp index be8d57c72b..85bd62c1be 100644 --- a/lib/gateways/sctp_network_server_impl.cpp +++ b/lib/gateways/sctp_network_server_impl.cpp @@ -134,8 +134,7 @@ sctp_network_server_impl::sctp_network_server_impl(const srsran::sctp_network_ga sctp_network_gateway_common_impl(sctp_cfg_), broker(broker_), io_rx_executor(io_rx_executor_), - assoc_factory(assoc_factory_), - temp_recv_buffer(network_gateway_sctp_max_len) + assoc_factory(assoc_factory_) { } @@ -155,8 +154,10 @@ bool sctp_network_server_impl::create_and_bind() void sctp_network_server_impl::receive() { - struct sctp_sndrcvinfo sri = {}; - int msg_flags = 0; + struct sctp_sndrcvinfo sri = {}; + int msg_flags = 0; + std::array temp_recv_buffer; + // fromlen is an in/out variable in sctp_recvmsg. sockaddr_storage msg_src_addr; socklen_t msg_src_addrlen = sizeof(msg_src_addr); @@ -361,8 +362,9 @@ std::optional sctp_network_server_impl::get_listen_port() bool sctp_network_server_impl::subscribe_to_broker() { + socket.release(); io_sub = broker.register_fd( - unique_fd(socket.fd().value(), false), + unique_fd(socket.fd().value()), io_rx_executor, [this]() { receive(); }, [this](io_broker::error_code code) { diff --git a/lib/gateways/sctp_network_server_impl.h b/lib/gateways/sctp_network_server_impl.h index 59c1e7be22..94d1fda985 100644 --- a/lib/gateways/sctp_network_server_impl.h +++ b/lib/gateways/sctp_network_server_impl.h @@ -87,9 +87,6 @@ class sctp_network_server_impl : public sctp_network_server, public sctp_network sctp_network_association_factory& assoc_factory; association_map associations; - - // Temporary buffer where read data is saved. - std::vector temp_recv_buffer; }; } // namespace srsran diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index 747ba3cb38..a1f87a5724 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -33,17 +33,6 @@ udp_network_gateway_impl::udp_network_gateway_impl(udp_network_gateway_config io_rx_executor(io_rx_executor_) { logger.info("UDP GW configured. rx_max_mmsg={} pool_thres={}", config.rx_max_mmsg, config.pool_occupancy_threshold); - - // Allocate RX buffers - rx_mem.resize(config.rx_max_mmsg); - for (uint32_t i = 0; i < config.rx_max_mmsg; ++i) { - rx_mem[i].resize(network_gateway_udp_max_len); - } - - // Allocate context for recv_mmsg - rx_srcaddr.resize(config.rx_max_mmsg); - rx_msghdr.resize(config.rx_max_mmsg); - rx_iovecs.resize(config.rx_max_mmsg); } bool udp_network_gateway_impl::subscribe_to(io_broker& broker) @@ -205,26 +194,54 @@ bool udp_network_gateway_impl::create_and_bind() return true; } -void udp_network_gateway_impl::receive() +namespace { + +/// Receive context used by the recvmmsg syscall. +struct receive_context { + explicit receive_context(unsigned rx_max_mmsg); + + std::vector> rx_mem; + std::vector<::sockaddr_storage> rx_srcaddr; + std::vector<::mmsghdr> rx_msghdr; + std::vector<::iovec> rx_iovecs; +}; + +} // namespace + +receive_context::receive_context(unsigned rx_max_mmsg) { - if (!sock_fd.is_open()) { - logger.error("Cannot receive on UDP gateway: Socket is not initialized."); + // Allocate RX buffers. + rx_mem.resize(rx_max_mmsg); + for (unsigned i = 0; i != rx_max_mmsg; ++i) { + rx_mem[i].resize(network_gateway_udp_max_len); } - socklen_t src_addr_len = sizeof(struct sockaddr_storage); + // Allocate context for recv_mmsg. + rx_srcaddr.resize(rx_max_mmsg); + rx_msghdr.resize(rx_max_mmsg); + rx_iovecs.resize(rx_max_mmsg); - for (unsigned i = 0; i < config.rx_max_mmsg; ++i) { + for (unsigned i = 0; i != rx_max_mmsg; ++i) { rx_msghdr[i].msg_hdr = {}; rx_msghdr[i].msg_hdr.msg_name = &rx_srcaddr[i]; - rx_msghdr[i].msg_hdr.msg_namelen = src_addr_len; + rx_msghdr[i].msg_hdr.msg_namelen = sizeof(::sockaddr_storage); rx_iovecs[i].iov_base = rx_mem[i].data(); rx_iovecs[i].iov_len = network_gateway_udp_max_len; rx_msghdr[i].msg_hdr.msg_iov = &rx_iovecs[i]; rx_msghdr[i].msg_hdr.msg_iovlen = 1; } +} + +void udp_network_gateway_impl::receive() +{ + if (!sock_fd.is_open()) { + logger.error("Cannot receive on UDP gateway: Socket is not initialized."); + } + + thread_local receive_context rx_context(config.rx_max_mmsg); - int rx_msgs = recvmmsg(sock_fd.value(), rx_msghdr.data(), config.rx_max_mmsg, MSG_WAITFORONE, nullptr); + int rx_msgs = recvmmsg(sock_fd.value(), rx_context.rx_msghdr.data(), config.rx_max_mmsg, MSG_WAITFORONE, nullptr); srslog::fetch_basic_logger("IO-EPOLL").info("UDP rx {} packets, max is {}", rx_msgs, config.rx_max_mmsg); if (rx_msgs == -1 && errno != EAGAIN) { logger.error("Error reading from UDP socket: {}", strerror(errno)); @@ -249,15 +266,16 @@ void udp_network_gateway_impl::receive() logger.info("Buffer pool at {:.1f}% occupancy. Dropping {} packets", pool_occupancy * 100, rx_msgs - i); return; } - span payload(rx_mem[i].data(), rx_msghdr[i].msg_len); + span payload(rx_context.rx_mem[i].data(), rx_context.rx_msghdr[i].msg_len); byte_buffer pdu = {}; if (pdu.append(payload)) { - logger.debug( - "Received {} bytes on UDP socket. Pool occupancy {:.2f}%", rx_msghdr[i].msg_len, pool_occupancy * 100); - data_notifier.on_new_pdu(std::move(pdu), *(sockaddr_storage*)rx_msghdr[i].msg_hdr.msg_name); + logger.debug("Received {} bytes on UDP socket. Pool occupancy {:.2f}%", + rx_context.rx_msghdr[i].msg_len, + pool_occupancy * 100); + data_notifier.on_new_pdu(std::move(pdu), *(sockaddr_storage*)rx_context.rx_msghdr[i].msg_hdr.msg_name); } else { - logger.error("Could not allocate byte buffer. Received {} bytes on UDP socket", rx_msghdr[i].msg_len); + logger.error("Could not allocate byte buffer. Received {} bytes on UDP socket", rx_context.rx_msghdr[i].msg_len); } } } diff --git a/lib/gateways/udp_network_gateway_impl.h b/lib/gateways/udp_network_gateway_impl.h index 999b95f2f5..2951deba92 100644 --- a/lib/gateways/udp_network_gateway_impl.h +++ b/lib/gateways/udp_network_gateway_impl.h @@ -73,12 +73,6 @@ class udp_network_gateway_impl final : public udp_network_gateway int local_ai_socktype = 0; int local_ai_protocol = 0; - /// Temporary RX buffers for reception. - std::vector> rx_mem; - std::vector<::sockaddr_storage> rx_srcaddr; - std::vector<::mmsghdr> rx_msghdr; - std::vector<::iovec> rx_iovecs; - // Temporary Tx buffer for transmission. std::array tx_mem; diff --git a/lib/support/network/io_broker_epoll.cpp b/lib/support/network/io_broker_epoll.cpp index 4fe3f50e56..2df5028f18 100644 --- a/lib/support/network/io_broker_epoll.cpp +++ b/lib/support/network/io_broker_epoll.cpp @@ -72,6 +72,8 @@ io_broker_epoll::~io_broker_epoll() thread.join(); } + stop_impl(); + // Close epoll socket. if (not epoll_fd.close()) { logger.error("Failed to close io epoll broker file descriptor: {}", strerror(errno)); @@ -244,8 +246,8 @@ void io_broker_epoll::handle_enqueued_events() ev.completed->set_value(false); break; case control_event::event_type::close_io_broker: - // Close io broker. - stop_impl(); + // Set flag to stop thread loop. + running.store(false, std::memory_order_release); return; default: report_fatal_error("Unknown event type {}", (int)ev.type); @@ -354,7 +356,7 @@ io_broker::subscriber io_broker_epoll::register_fd(unique_fd fd, return subscriber{}; } - if (not running.load(std::memory_order_relaxed)) { + if (not running.load(std::memory_order_acquire)) { logger.warning("fd={}: Registration failed. Cause: io_broker is not running", fd.value()); return subscriber{}; } @@ -393,7 +395,7 @@ bool io_broker_epoll::unregister_fd(int fd, std::promise* complete_notifie } return false; } - if (not running.load(std::memory_order_relaxed)) { + if (not running.load(std::memory_order_acquire)) { logger.warning("fd={}: Deregistration failed. Cause: io_broker is not running", fd); if (complete_notifier) { complete_notifier->set_value(false); @@ -425,9 +427,6 @@ bool io_broker_epoll::unregister_fd(int fd, std::promise* complete_notifie void io_broker_epoll::stop_impl() { - // Set flag to stop thread loop. - running = false; - // Process any pending file descriptor removals. for (auto it = pending_fds_to_remove.begin(); it != pending_fds_to_remove.end();) { if (auto event_it = event_handler.find(it->first); event_it != event_handler.end()) { diff --git a/lib/support/network/sctp_socket.cpp b/lib/support/network/sctp_socket.cpp index 36be7d9ffb..d6d62d6019 100644 --- a/lib/support/network/sctp_socket.cpp +++ b/lib/support/network/sctp_socket.cpp @@ -193,11 +193,6 @@ sctp_socket& sctp_socket::operator=(sctp_socket&& other) noexcept return *this; } -sctp_socket::~sctp_socket() -{ - close(); -} - bool sctp_socket::close() { if (not sock_fd.is_open()) { diff --git a/tests/unittests/gateways/sctp_network_client_test.cpp b/tests/unittests/gateways/sctp_network_client_test.cpp index 2eced5054a..b699831ea1 100644 --- a/tests/unittests/gateways/sctp_network_client_test.cpp +++ b/tests/unittests/gateways/sctp_network_client_test.cpp @@ -150,13 +150,14 @@ TEST_F(sctp_network_client_test, when_bind_address_not_provided_then_client_is_c ASSERT_NE(client, nullptr); } -TEST_F(sctp_network_client_test, when_bind_interface_is_invalid_then_server_is_not_created) +TEST_F(sctp_network_client_test, when_bind_interface_is_invalid_then_client_connection_fails) { client_cfg.sctp.bind_interface = "invalid"; client_cfg.sctp.bind_address = "127.0.0.1"; client_cfg.sctp.bind_port = server.bind_port; client = create_sctp_network_client(client_cfg); - ASSERT_EQ(client, nullptr); + ASSERT_NE(client, nullptr); + ASSERT_FALSE(connect_to_server(client_cfg.sctp.bind_address, client_cfg.sctp.bind_port)); } TEST_F(sctp_network_client_test, when_server_does_not_exist_then_connection_fails) From 3f58d6ebb8f40b4ff9b5e9a39130ab2a290fb26a Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Tue, 17 Dec 2024 10:32:33 +0100 Subject: [PATCH 219/227] app_unit: added group option to group the OFH base cell parameters and force to re parse the cell option if it was previously parsed --- .../split_7_2/helpers/ru_ofh_config_cli11_schema.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp b/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp index b3958d6661..63c24fa6e9 100644 --- a/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_cli11_schema.cpp @@ -215,7 +215,16 @@ static void configure_cli11_ru_ofh_args(CLI::App& app, ru_ofh_unit_parsed_config add_option(app, "--gps_beta", ofh_cfg.gps_Beta, "GPS Beta")->capture_default_str()->check(CLI::Range(-32768, 32767)); // Common cell parameters. - configure_cli11_ru_ofh_base_cell_args(app, config.base_cell_cfg); + auto base_cell_group = app.add_option_group("base_cell"); + configure_cli11_ru_ofh_base_cell_args(*base_cell_group, config.base_cell_cfg); + base_cell_group->parse_complete_callback([&config, &app]() { + for (auto& cell : config.config.cells) { + cell.cell = config.base_cell_cfg; + }; + if (app.get_option("--cells")->get_callback_run()) { + app.get_option("--cells")->run_callback(); + } + }); // Cell parameters. add_option_cell( From 9f7d9c3db0830fe2f11798180f038187c51e13f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20S=C3=A1ez?= Date: Tue, 17 Dec 2024 17:55:56 +0100 Subject: [PATCH 220/227] ci: update retina --- .gitlab/ci/e2e/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index a5d83e4afe..d08a36cb8f 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.58.8 +RETINA_VERSION=0.59.0 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From fd2ab097653910f7e70cdf7e88f81c1043c9a66d Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 16 Dec 2024 14:35:55 +0000 Subject: [PATCH 221/227] ngu: added support to set DSCP value --- apps/services/network/udp_cli11_schema.cpp | 3 ++ apps/services/network/udp_cli11_schema.h | 3 ++ apps/units/o_cu_up/o_cu_up_builder.cpp | 1 + configs/ngu_multiple_sockets.yml | 10 +++-- include/srsran/gateways/udp_network_gateway.h | 5 ++- lib/gateways/udp_network_gateway_impl.cpp | 45 ++++++++++++++++--- lib/gateways/udp_network_gateway_impl.h | 1 + 7 files changed, 57 insertions(+), 11 deletions(-) diff --git a/apps/services/network/udp_cli11_schema.cpp b/apps/services/network/udp_cli11_schema.cpp index 89da3551f4..116e3d2628 100644 --- a/apps/services/network/udp_cli11_schema.cpp +++ b/apps/services/network/udp_cli11_schema.cpp @@ -20,6 +20,9 @@ static void configure_cli11_udp_args(CLI::App& app, udp_appconfig& udp_params) add_option( app, "--pool_threshold", udp_params.pool_threshold, "Pool accupancy threshold after which packets are dropped") ->capture_default_str(); + add_option(app, "--dscp", udp_params.dscp, "Differentiated Services Code Point value.") + ->capture_default_str() + ->check(CLI::Range(0, 63)); } void srsran::configure_cli11_with_udp_config_schema(CLI::App& app, udp_appconfig& config) diff --git a/apps/services/network/udp_cli11_schema.h b/apps/services/network/udp_cli11_schema.h index e1e8111fc2..1afa8449a5 100644 --- a/apps/services/network/udp_cli11_schema.h +++ b/apps/services/network/udp_cli11_schema.h @@ -11,6 +11,7 @@ #pragma once #include "CLI/CLI11.hpp" +#include namespace srsran { @@ -20,6 +21,8 @@ struct udp_appconfig { unsigned rx_max_msgs = 256; /// Pool accupancy threshold after which packets are dropped. float pool_threshold = 0.9; + /// Differentiated Services Code Point value. + std::optional dscp; }; /// \brief Configures the given CLI11 application with the UDP application configuration schema. diff --git a/apps/units/o_cu_up/o_cu_up_builder.cpp b/apps/units/o_cu_up/o_cu_up_builder.cpp index 44c107045e..6f9be68025 100644 --- a/apps/units/o_cu_up/o_cu_up_builder.cpp +++ b/apps/units/o_cu_up/o_cu_up_builder.cpp @@ -74,6 +74,7 @@ o_cu_up_unit srsran::build_o_cu_up(const o_cu_up_unit_config& unit_cfg, const o_ n3_udp_cfg.rx_max_mmsg = sock_cfg.udp_config.rx_max_msgs; n3_udp_cfg.pool_occupancy_threshold = sock_cfg.udp_config.pool_threshold; n3_udp_cfg.reuse_addr = false; // TODO allow reuse_addr for multiple sockets + n3_udp_cfg.dscp = sock_cfg.udp_config.dscp; std::unique_ptr ngu_gw = create_udp_gtpu_gateway(n3_udp_cfg, diff --git a/configs/ngu_multiple_sockets.yml b/configs/ngu_multiple_sockets.yml index eafd03f7dc..58be0adcc9 100644 --- a/configs/ngu_multiple_sockets.yml +++ b/configs/ngu_multiple_sockets.yml @@ -3,13 +3,15 @@ cu_up: ngu: socket: - - bind_addr: 127.0.3.1 # address that the NG-U socket will bind to. + bind_addr: 127.0.3.1 # Address that the NG-U socket will bind to. udp: - max_rx_msgs: 256 # maximum packets read from the socket in a single syscall. + max_rx_msgs: 256 # Maximum packets read from the socket in a single syscall. pool_threshold: 0.9 # Pool occupancy threshold, after which packets are dropped. + #dscp: 3 # Differentiated Services Code Point. - - bind_addr: 127.0.3.2 + bind_addr: 127.0.3.2 # Address that the NG-U socket will bind to. udp: - max_rx_msgs: 256 # maximum packets read from the socket in a single syscall. + max_rx_msgs: 256 # maximum packets read from the socket in a single syscall. pool_threshold: 0.9 # Pool occupancy threshold, after which packets are dropped. + #dscp: 4 # Differentiated Services Code Point. diff --git a/include/srsran/gateways/udp_network_gateway.h b/include/srsran/gateways/udp_network_gateway.h index 7ba07b303b..928c967eda 100644 --- a/include/srsran/gateways/udp_network_gateway.h +++ b/include/srsran/gateways/udp_network_gateway.h @@ -20,8 +20,9 @@ struct sockaddr_storage; namespace srsran { struct udp_network_gateway_config : common_network_gateway_config { - unsigned rx_max_mmsg = 256; - float pool_occupancy_threshold = 0.9; + unsigned rx_max_mmsg = 256; + float pool_occupancy_threshold = 0.9; + std::optional dscp; }; /// Interface to inject PDUs into gateway entity. diff --git a/lib/gateways/udp_network_gateway_impl.cpp b/lib/gateways/udp_network_gateway_impl.cpp index a1f87a5724..d07913f08b 100644 --- a/lib/gateways/udp_network_gateway_impl.cpp +++ b/lib/gateways/udp_network_gateway_impl.cpp @@ -129,11 +129,6 @@ bool udp_network_gateway_impl::create_and_bind() continue; } - if (not set_sockopts()) { - close_socket(); - continue; - } - char ip_addr[NI_MAXHOST]; char port_nr[NI_MAXSERV]; getnameinfo( @@ -191,6 +186,13 @@ bool udp_network_gateway_impl::create_and_bind() return false; } + // Set socket options. This is done after binding, + // so that we can set IPv4/IPv6 options accordingly. + if (not set_sockopts()) { + close_socket(); + return false; + } + return true; } @@ -375,6 +377,13 @@ bool udp_network_gateway_impl::set_sockopts() } } + if (config.dscp.has_value()) { + if (not set_dscp()) { + logger.error("Couldn't set DSCP for socket"); + return false; + } + } + logger.debug("Successfully set socket options"); return true; } @@ -419,6 +428,32 @@ bool udp_network_gateway_impl::set_reuse_addr() return true; } +bool udp_network_gateway_impl::set_dscp() +{ + if (not config.dscp.has_value()) { + return true; // No DSCP code to set. + } + uint8_t option = config.dscp.value() << 2; // DSCP is the only the 6 most significant bits. + if (local_addr.ss_family == AF_INET) { + if (::setsockopt(sock_fd.value(), IPPROTO_IP, IP_TOS, &option, sizeof(option))) { + logger.error("Couldn't set DSCP for socket: {}", strerror(errno)); + return false; + } + logger.debug("Set DSCP for socket. dscp={}", config.dscp.value()); + return true; + } + if (local_addr.ss_family == AF_INET6) { + if (setsockopt(sock_fd.value(), IPPROTO_IPV6, IPV6_TCLASS, &option, sizeof(option))) { + logger.error("Couldn't set DSCP for socket: {}", strerror(errno)); + return false; + } + logger.debug("Set DSCP for socket. dscp={}", config.dscp.value()); + return true; + } + logger.error("Unknown socket familly when setting DSCP"); + return false; +} + bool udp_network_gateway_impl::close_socket() { if (not sock_fd.close()) { diff --git a/lib/gateways/udp_network_gateway_impl.h b/lib/gateways/udp_network_gateway_impl.h index 2951deba92..ef18fab546 100644 --- a/lib/gateways/udp_network_gateway_impl.h +++ b/lib/gateways/udp_network_gateway_impl.h @@ -56,6 +56,7 @@ class udp_network_gateway_impl final : public udp_network_gateway bool set_non_blocking(); bool set_receive_timeout(unsigned rx_timeout_sec); bool set_reuse_addr(); + bool set_dscp(); bool close_socket(); udp_network_gateway_config config; // configuration From 7150dac83a5dc04559133c82f92504be40f1428a Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Tue, 17 Dec 2024 11:37:47 +0100 Subject: [PATCH 222/227] du_app_unit: removed multi-DU approach for multicell. Renamed multicell files to avoid using the word multicell. Removed passing the sector to the O-DU high and O-DU low. Sector is now derived from the number of cells. --- apps/du/du.cpp | 2 +- apps/du/du_appconfig.h | 2 - apps/du/du_appconfig_cli11_schema.cpp | 3 - apps/du/du_appconfig_translators.cpp | 9 +- apps/gnb/gnb.cpp | 2 +- apps/gnb/gnb_appconfig.h | 2 - apps/gnb/gnb_appconfig_cli11_schema.cpp | 7 -- apps/gnb/gnb_appconfig_translators.cpp | 9 +- .../worker_manager/worker_manager.cpp | 62 +++------- .../worker_manager/worker_manager_config.h | 2 - .../flexible_o_du_application_unit.h | 3 +- .../flexible_o_du/flexible_o_du_commands.h | 1 + .../o_du_high/o_du_high_unit_factory.cpp | 40 +++---- .../o_du_high/o_du_high_unit_factory.h | 8 +- .../o_du_low/du_low_config_translator.cpp | 10 +- .../o_du_low/du_low_config_translator.h | 3 +- .../o_du_low/o_du_low_unit_factory.cpp | 17 ++- .../o_du_low/o_du_low_unit_factory.h | 2 - .../split6_o_du_application_unit_impl.cpp | 3 +- .../split6_o_du_application_unit_impl.h | 2 +- .../split_6/split6_o_du_factory.cpp | 52 ++++---- .../split_6/split6_o_du_impl.cpp | 24 ++-- .../flexible_o_du/split_6/split6_o_du_impl.h | 4 +- .../split_7_2_o_du_application_unit_impl.cpp | 6 +- .../split_7_2_o_du_application_unit_impl.h | 2 +- .../split_7_2/split_7_2_o_du_factory.cpp | 7 -- .../split_7_2/split_7_2_o_du_factory.h | 17 --- .../split_8_o_du_application_unit_impl.cpp | 6 +- .../split_8_o_du_application_unit_impl.h | 2 +- .../split_8/split_8_o_du_factory.cpp | 7 -- .../split_8/split_8_o_du_factory.h | 17 --- .../split_dynamic/CMakeLists.txt | 3 +- .../dynamic_o_du_application_unit_impl.cpp | 8 +- .../dynamic_o_du_application_unit_impl.h | 2 +- .../split_dynamic/dynamic_o_du_factory.cpp | 1 - .../split_dynamic/dynamic_o_du_factory.h | 2 +- .../multicell_dynamic_o_du_factory.cpp | 49 -------- .../multicell_dynamic_o_du_factory.h | 34 ------ .../split_helpers/CMakeLists.txt | 5 +- .../split_helpers/flexible_o_du_factory.cpp | 105 +++++++--------- .../split_helpers/flexible_o_du_factory.h | 1 - .../split_helpers/flexible_o_du_impl.cpp | 34 +++--- .../split_helpers/flexible_o_du_impl.h | 23 ++-- .../multicell_flexible_o_du_factory.cpp | 112 ------------------ .../multicell_flexible_o_du_factory.h | 37 ------ .../multicell_flexible_o_du_impl.cpp | 61 ---------- .../multicell_flexible_o_du_impl.h | 63 ---------- .../split_helpers/o_du_high_factory.cpp | 99 ---------------- .../split_helpers/o_du_high_factory.h | 38 ------ 49 files changed, 182 insertions(+), 828 deletions(-) delete mode 100644 apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.cpp delete mode 100644 apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.h delete mode 100644 apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.cpp delete mode 100644 apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h delete mode 100644 apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.cpp delete mode 100644 apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.h delete mode 100644 apps/units/flexible_o_du/split_helpers/o_du_high_factory.cpp delete mode 100644 apps/units/flexible_o_du/split_helpers/o_du_high_factory.h diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 80689d1e6a..0af849c710 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -300,7 +300,7 @@ int main(int argc, char** argv) du_dependencies.json_sink = &json_sink; du_dependencies.metrics_notifier = &metrics_notifier_forwarder; - auto du_inst_and_cmds = o_du_app_unit->create_flexible_o_du_unit(du_dependencies, du_cfg.du_multicell_enabled); + auto du_inst_and_cmds = o_du_app_unit->create_flexible_o_du_unit(du_dependencies); // Only DU has metrics now. app_services::metrics_manager metrics_mngr( diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index e8f740a6f7..b597ee0a8b 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -46,8 +46,6 @@ struct metrics_appconfig { struct du_appconfig { /// Default constructor to update the log filename. du_appconfig() { log_cfg.filename = "/tmp/du.log"; } - /// DU multicell flag. This flag set to false is a deprecated feature. - bool du_multicell_enabled = true; /// Loggers configuration. logger_appconfig log_cfg; /// Metrics configuration. diff --git a/apps/du/du_appconfig_cli11_schema.cpp b/apps/du/du_appconfig_cli11_schema.cpp index 2b67decf8e..6bd3ea75c9 100644 --- a/apps/du/du_appconfig_cli11_schema.cpp +++ b/apps/du/du_appconfig_cli11_schema.cpp @@ -51,9 +51,6 @@ static void configure_cli11_f1u_args(CLI::App& app, srs_du::nru_appconfig& f1u_p 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") - ->capture_default_str(); - // Loggers section. configure_cli11_with_logger_appconfig_schema(app, du_cfg.log_cfg); diff --git a/apps/du/du_appconfig_translators.cpp b/apps/du/du_appconfig_translators.cpp index eaa36a9700..ed1e95ab19 100644 --- a/apps/du/du_appconfig_translators.cpp +++ b/apps/du/du_appconfig_translators.cpp @@ -19,9 +19,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.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_task_queue_size = unit_cfg.expert_execution_cfg.threads.non_rt_threads.non_rt_task_queue_size; - 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.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; + config.low_prio_task_queue_size = unit_cfg.expert_execution_cfg.threads.non_rt_threads.non_rt_task_queue_size; + config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; } diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 39a60baa21..88312027f9 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -421,7 +421,7 @@ int main(int argc, char** argv) odu_dependencies.json_sink = &json_sink; odu_dependencies.metrics_notifier = &metrics_notifier_forwarder; - auto du_inst_and_cmds = o_du_app_unit->create_flexible_o_du_unit(odu_dependencies, gnb_cfg.du_multicell_enabled); + auto du_inst_and_cmds = o_du_app_unit->create_flexible_o_du_unit(odu_dependencies); srs_du::du& du_inst = *du_inst_and_cmds.unit; diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 15a03f426d..96367e31b4 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -35,8 +35,6 @@ struct metrics_appconfig { struct gnb_appconfig { /// Default constructor to update the log filename. gnb_appconfig() { log_cfg.filename = "/tmp/gnb.log"; } - /// DU multicell flag. This flag set to false is a deprecated feature. - bool du_multicell_enabled = true; /// Loggers configuration. logger_appconfig log_cfg; /// Metrics configuration. diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index e43d9bfd5c..73daef7428 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -43,13 +43,6 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon ->check(CLI::Range(22, 32)); add_option(app, "--ran_node_name", gnb_cfg.ran_node_name, "RAN node name")->capture_default_str(); - add_option(app, - "--du_multicell_enabled", - gnb_parsed_cfg.du_multicell_enabled, - "DU multicell enabled flag. The support for the value 'false' is deprecated and will be removed in future " - "releases") - ->capture_default_str(); - // Loggers section. configure_cli11_with_logger_appconfig_schema(app, gnb_cfg.log_cfg); diff --git a/apps/gnb/gnb_appconfig_translators.cpp b/apps/gnb/gnb_appconfig_translators.cpp index d13531921d..b8beea9014 100644 --- a/apps/gnb/gnb_appconfig_translators.cpp +++ b/apps/gnb/gnb_appconfig_translators.cpp @@ -20,9 +20,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.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_task_queue_size = unit_cfg.expert_execution_cfg.threads.non_rt_threads.non_rt_task_queue_size; - 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.nof_low_prio_threads = unit_cfg.expert_execution_cfg.threads.non_rt_threads.nof_non_rt_threads; + config.low_prio_task_queue_size = unit_cfg.expert_execution_cfg.threads.non_rt_threads.non_rt_task_queue_size; + config.low_prio_sched_config = unit_cfg.expert_execution_cfg.affinities.low_priority_cpu_cfg; } diff --git a/apps/services/worker_manager/worker_manager.cpp b/apps/services/worker_manager/worker_manager.cpp index 0b977296fc..319436599c 100644 --- a/apps/services/worker_manager/worker_manager.cpp +++ b/apps/services/worker_manager/worker_manager.cpp @@ -244,50 +244,26 @@ void worker_manager::create_du_executors(const worker_manager_config::du_high_co // Instantiate DU-high executor mapper. 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; - 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); - } 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); - } + // Create one executor mapper as one DU supports multiple cells. + 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; + 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) { create_du_low_executors(du_low.value().is_blocking_mode_active, diff --git a/apps/services/worker_manager/worker_manager_config.h b/apps/services/worker_manager/worker_manager_config.h index 2aa33c0b48..8795043fe8 100644 --- a/apps/services/worker_manager/worker_manager_config.h +++ b/apps/services/worker_manager/worker_manager_config.h @@ -71,8 +71,6 @@ 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/apps/units/flexible_o_du/flexible_o_du_application_unit.h b/apps/units/flexible_o_du/flexible_o_du_application_unit.h index 7af29af73b..0001d628d6 100644 --- a/apps/units/flexible_o_du/flexible_o_du_application_unit.h +++ b/apps/units/flexible_o_du/flexible_o_du_application_unit.h @@ -25,8 +25,7 @@ class flexible_o_du_application_unit : public application_unit virtual ~flexible_o_du_application_unit() = default; /// Creates a flexible O-RAN DU using the given dependencies. - virtual o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, - bool use_multicell = false) = 0; + virtual o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) = 0; /// Returns the O-RAN DU high unit configuration of this flexible DU. virtual o_du_high_unit_config& get_o_du_high_unit_config() = 0; diff --git a/apps/units/flexible_o_du/flexible_o_du_commands.h b/apps/units/flexible_o_du/flexible_o_du_commands.h index e09a6f51b3..ff4a871091 100644 --- a/apps/units/flexible_o_du/flexible_o_du_commands.h +++ b/apps/units/flexible_o_du/flexible_o_du_commands.h @@ -15,6 +15,7 @@ #include "srsran/adt/expected.h" #include "srsran/adt/to_array.h" #include "srsran/ru/ru_controller.h" +#include "srsran/srslog/srslog.h" namespace srsran { diff --git a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp index a714656858..5c44e6e364 100644 --- a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp +++ b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp @@ -188,26 +188,23 @@ static rlc_metrics_notifier* build_rlc_du_metrics(std::vector((static_cast(du_high_unit_cfg.gnb_du_id) + o_du_high_unit_cfg.du_index)); + du_hi_cfg.ran.gnb_du_id = du_high_unit_cfg.gnb_du_id; du_hi_cfg.ran.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.ran.gnb_du_id); du_hi_cfg.ran.cells = generate_du_cell_config(du_high_unit_cfg); // Validates the derived parameters. validates_derived_du_params(du_hi_cfg.ran.cells); - du_hi_cfg.ran.srbs = generate_du_srb_config(du_high_unit_cfg); - du_hi_cfg.ran.qos = generate_du_qos_config(du_high_unit_cfg); - du_hi_cfg.ran.mac_cfg = generate_mac_expert_config(du_high_unit_cfg); - // Assign different initial C-RNTIs to different DUs. - du_hi_cfg.ran.mac_cfg.initial_crnti = to_rnti(0x4601 + (0x1000 * o_du_high_unit_cfg.du_index)); + du_hi_cfg.ran.srbs = generate_du_srb_config(du_high_unit_cfg); + du_hi_cfg.ran.qos = generate_du_qos_config(du_high_unit_cfg); + du_hi_cfg.ran.mac_cfg = generate_mac_expert_config(du_high_unit_cfg); + du_hi_cfg.ran.mac_cfg.initial_crnti = to_rnti(0x4601); du_hi_cfg.ran.sched_cfg = generate_scheduler_expert_config(du_high_unit_cfg); srs_du::du_high_dependencies& du_hi_deps = dependencies.o_du_hi_dependencies.du_hi; @@ -219,15 +216,15 @@ o_du_high_unit srsran::make_o_du_high_unit(const o_du_high_unit_params& o_du_hi du_hi_deps.mac_p = &dependencies.mac_p; du_hi_deps.rlc_p = &dependencies.rlc_p; - if (odu_unit_cfg.e2_cfg.base_cfg.enable_unit_e2) { + if (o_du_high_unit_cfg.e2_cfg.base_cfg.enable_unit_e2) { // Connect E2 agent to RLC metric source. dependencies.o_du_hi_dependencies.e2_client = &dependencies.e2_client_handler; - o_du_high_cfg.e2ap_config = generate_e2_config(odu_unit_cfg.e2_cfg, + o_du_high_cfg.e2ap_config = generate_e2_config(o_du_high_unit_cfg.e2_cfg, du_high_unit_cfg.gnb_id, du_high_unit_cfg.cells_cfg.front().cell.plmn, du_hi_cfg.ran.gnb_du_id); dependencies.o_du_hi_dependencies.e2_du_metric_iface = - &(dependencies.e2_metric_connectors.get_e2_metrics_interface(o_du_high_unit_cfg.du_index)); + &(dependencies.e2_metric_connectors.get_e2_metrics_interface(0)); } // DU high metrics. @@ -237,16 +234,15 @@ o_du_high_unit srsran::make_o_du_high_unit(const o_du_high_unit_params& o_du_hi build_scheduler_du_metrics(odu_unit.metrics, odu_unit.commands, dependencies.metrics_notifier, - odu_unit_cfg, + o_du_high_unit_cfg, dependencies.json_sink, - dependencies.e2_metric_connectors.get_e2_metric_notifier(o_du_high_unit_cfg.du_index)); + dependencies.e2_metric_connectors.get_e2_metric_notifier(0)); - du_hi_deps.rlc_metrics_notif = - build_rlc_du_metrics(odu_unit.metrics, - dependencies.metrics_notifier, - odu_unit_cfg, - dependencies.json_sink, - dependencies.e2_metric_connectors.get_e2_metric_notifier(o_du_high_unit_cfg.du_index)); + du_hi_deps.rlc_metrics_notif = build_rlc_du_metrics(odu_unit.metrics, + dependencies.metrics_notifier, + o_du_high_unit_cfg, + dependencies.json_sink, + dependencies.e2_metric_connectors.get_e2_metric_notifier(0)); // Configure test mode if (du_high_unit_cfg.test_mode_cfg.test_ue.rnti != rnti_t::INVALID_RNTI) { @@ -265,7 +261,7 @@ o_du_high_unit srsran::make_o_du_high_unit(const o_du_high_unit_params& o_du_hi } // FAPI configuration. - const fapi_unit_config& fapi_cfg = o_du_high_unit_cfg.o_du_hi_cfg.fapi_cfg; + const fapi_unit_config& fapi_cfg = o_du_high_unit_cfg.fapi_cfg; o_du_high_cfg.fapi.log_level = fapi_cfg.fapi_level; o_du_high_cfg.fapi.l2_nof_slots_ahead = fapi_cfg.l2_nof_slots_ahead; diff --git a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h index ee6f5b206c..073fe71832 100644 --- a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h +++ b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h @@ -56,12 +56,6 @@ struct o_du_high_unit { std::vector metrics; }; -/// O-RAN DU high unit parameters. -struct o_du_high_unit_params { - const o_du_high_unit_config& o_du_hi_cfg; - unsigned du_index; -}; - /// O-RAN DU high unit dependencies. struct o_du_high_unit_dependencies { srs_du::du_high_executor_mapper& execution_mapper; @@ -78,7 +72,7 @@ struct o_du_high_unit_dependencies { }; /// Creates the O-RAN DU high unit with the given configuration. -o_du_high_unit make_o_du_high_unit(const o_du_high_unit_params& o_du_high_unit_cfg, +o_du_high_unit make_o_du_high_unit(const o_du_high_unit_config& o_du_high_unit_cfg, o_du_high_unit_dependencies&& dependencies); } // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp b/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp index f4b247a6fc..5e1bb9052a 100644 --- a/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp +++ b/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp @@ -21,8 +21,7 @@ using namespace srsran; static void generate_du_low_config(srs_du::du_low_config& out_config, const du_low_unit_config& du_low, span du_cells, - span max_puschs_per_slot, - unsigned du_id) + span max_puschs_per_slot) { out_config.cells.reserve(du_cells.size()); @@ -117,7 +116,7 @@ static void generate_du_low_config(srs_du::du_low_config& out_config upper_phy_cell.rx_symbol_printer_port = du_low.loggers.phy_rx_symbols_port; upper_phy_cell.rx_symbol_printer_prach = du_low.loggers.phy_rx_symbols_prach; upper_phy_cell.logger_max_hex_size = du_low.loggers.hex_max_size; - upper_phy_cell.sector_id = du_id + i; + upper_phy_cell.sector_id = i; upper_phy_cell.nof_tx_ports = cell.dl_carrier.nof_ant; upper_phy_cell.nof_rx_ports = cell.ul_carrier.nof_ant; upper_phy_cell.ldpc_decoder_iterations = du_low.expert_phy_cfg.pusch_decoder_max_iterations; @@ -160,10 +159,9 @@ static void generate_du_low_config(srs_du::du_low_config& out_config void srsran::generate_o_du_low_config(srs_du::o_du_low_config& out_config, const du_low_unit_config& du_low_unit_cfg, span du_cells, - span max_puschs_per_slot, - unsigned du_id) + span max_puschs_per_slot) { - generate_du_low_config(out_config.du_low_cfg, du_low_unit_cfg, du_cells, max_puschs_per_slot, du_id); + generate_du_low_config(out_config.du_low_cfg, du_low_unit_cfg, du_cells, max_puschs_per_slot); } void srsran::fill_du_low_worker_manager_config(worker_manager_config& config, diff --git a/apps/units/flexible_o_du/o_du_low/du_low_config_translator.h b/apps/units/flexible_o_du/o_du_low/du_low_config_translator.h index f1c3f44eeb..43190acd12 100644 --- a/apps/units/flexible_o_du/o_du_low/du_low_config_translator.h +++ b/apps/units/flexible_o_du/o_du_low/du_low_config_translator.h @@ -26,8 +26,7 @@ struct worker_manager_config; void generate_o_du_low_config(srs_du::o_du_low_config& out_config, const du_low_unit_config& du_low_unit_cfg, span du_cells, - span max_puschs_per_slot, - unsigned du_id); + span max_puschs_per_slot); /// Fills the DU low worker manager parameters of the given worker manager configuration. void fill_du_low_worker_manager_config(worker_manager_config& config, diff --git a/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.cpp b/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.cpp index 9e0efce133..8738b89425 100644 --- a/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.cpp +++ b/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.cpp @@ -71,8 +71,7 @@ o_du_low_unit o_du_low_unit_factory::create(const o_du_low_unit_config& pa srs_du::o_du_low_config o_du_low_cfg; o_du_low_cfg.du_low_cfg.logger = &srslog::fetch_basic_logger("DU"); - generate_o_du_low_config( - o_du_low_cfg, params.du_low_unit_cfg, params.du_cells, params.max_puschs_per_slot, params.du_id); + generate_o_du_low_config(o_du_low_cfg, params.du_low_unit_cfg, params.du_cells, params.max_puschs_per_slot); // Fill the PRACH ports. o_du_low_cfg.prach_ports = params.prach_ports; @@ -83,21 +82,21 @@ o_du_low_unit o_du_low_unit_factory::create(const o_du_low_unit_config& pa generate_dl_processor_config(cell.dl_proc_cfg, params.du_low_unit_cfg, - *dependencies.workers.upper_pdsch_exec[i + params.du_id], + *dependencies.workers.upper_pdsch_exec[i], hal_dependencies.hw_encoder_factory); upper_phy_config& upper = cell.upper_phy_cfg; upper.rg_gateway = &dependencies.rg_gateway; upper.rx_symbol_request_notifier = &dependencies.rx_symbol_request_notifier; - upper.pucch_executor = dependencies.workers.upper_pucch_exec[i + params.du_id]; - upper.pusch_executor = dependencies.workers.upper_pusch_exec[i + params.du_id]; - upper.pusch_decoder_executor = dependencies.workers.upper_pusch_decoder_exec[i + params.du_id]; - upper.prach_executor = dependencies.workers.upper_prach_exec[i + params.du_id]; - upper.srs_executor = dependencies.workers.upper_srs_exec[i + params.du_id]; + upper.pucch_executor = dependencies.workers.upper_pucch_exec[i]; + upper.pusch_executor = dependencies.workers.upper_pusch_exec[i]; + upper.pusch_decoder_executor = dependencies.workers.upper_pusch_decoder_exec[i]; + upper.prach_executor = dependencies.workers.upper_prach_exec[i]; + upper.srs_executor = dependencies.workers.upper_srs_exec[i]; if (hal_dependencies.hw_decoder_factory) { upper.hw_decoder_factory = hal_dependencies.hw_decoder_factory; } - dependencies.workers.get_du_low_dl_executors(upper.dl_executors, i + params.du_id); + dependencies.workers.get_du_low_dl_executors(upper.dl_executors, i); } o_du_low_unit unit; diff --git a/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.h b/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.h index 619324b086..4f42593c25 100644 --- a/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.h +++ b/apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.h @@ -35,8 +35,6 @@ struct o_du_low_unit_config { std::vector prach_ports; span du_cells; span max_puschs_per_slot; - unsigned du_id; - unsigned nof_cells; }; /// O-RAN DU low unit dependencies. diff --git a/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.cpp b/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.cpp index ce12b6090b..4a337b41d7 100644 --- a/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.cpp +++ b/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.cpp @@ -55,8 +55,7 @@ void split6_o_du_application_unit_impl::on_parsing_configuration_registration(CL plugin->on_parsing_configuration_registration(app); } -o_du_unit split6_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, - bool use_multicell) +o_du_unit split6_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) { auto fapi_ctrl = plugin->create_fapi_adaptor(dependencies); report_error_if_not(!fapi_ctrl.empty(), "Could not create FAPI adaptor"); diff --git a/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.h b/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.h index 07b86963f9..9fc483a2ff 100644 --- a/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.h +++ b/apps/units/flexible_o_du/split_6/split6_o_du_application_unit_impl.h @@ -35,7 +35,7 @@ class split6_o_du_application_unit_impl : public flexible_o_du_application_unit void on_loggers_registration() override; // See interface for documentation. - o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, bool use_multicell = false) override; + o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) override; // See interface for documentation. o_du_high_unit_config& get_o_du_high_unit_config() override { return unit_cfg.odu_high_cfg; } diff --git a/apps/units/flexible_o_du/split_6/split6_o_du_factory.cpp b/apps/units/flexible_o_du/split_6/split6_o_du_factory.cpp index 7d2377ca25..785f190abe 100644 --- a/apps/units/flexible_o_du/split_6/split6_o_du_factory.cpp +++ b/apps/units/flexible_o_du/split_6/split6_o_du_factory.cpp @@ -15,7 +15,6 @@ #include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.h" #include "apps/units/flexible_o_du/o_du_high/o_du_high_unit_config.h" #include "apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h" -#include "apps/units/flexible_o_du/split_helpers/o_du_high_factory.h" #include "split6_o_du_impl.h" #include "split6_o_du_unit_config.h" #include "srsran/e2/e2_du_metrics_connector.h" @@ -31,44 +30,37 @@ o_du_unit srsran::create_o_du_split6(const split6_o_du_unit_config& e2_metric_connector_manager>( du_unit_cfg.odu_high_cfg.du_high_cfg.config.cells_cfg.size()); - std::vector du_high_insts; - - // Create O-DU high. - o_du_high_unit_factory_dependencies odu_hi_unit_dependencies = {*du_dependencies.workers, - *du_dependencies.f1c_client_handler, - *du_dependencies.f1u_gw, - *du_dependencies.timer_mng, - *du_dependencies.mac_p, - *du_dependencies.rlc_p, - *du_dependencies.e2_client_handler, - *(odu_unit.e2_metric_connectors), - *du_dependencies.json_sink, - *du_dependencies.metrics_notifier, - {}}; + o_du_high_unit_dependencies odu_hi_unit_dependencies = {du_dependencies.workers->get_du_high_executor_mapper(0), + *du_dependencies.f1c_client_handler, + *du_dependencies.f1u_gw, + *du_dependencies.timer_mng, + *du_dependencies.mac_p, + *du_dependencies.rlc_p, + *du_dependencies.e2_client_handler, + *(odu_unit.e2_metric_connectors), + *du_dependencies.json_sink, + *du_dependencies.metrics_notifier, + {}}; + // Adjust the dependencies. const auto& du_hi_unit_cfg = du_unit_cfg.odu_high_cfg.du_high_cfg.config; for (unsigned i = 0, e = du_hi_unit_cfg.cells_cfg.size(); i != e; ++i) { - auto& sector_deps = odu_hi_unit_dependencies.o_du_hi_dependencies.sectors.emplace_back(); - sector_deps.gateway = &fapi_adaptors[i]->get_message_interface_collection().get_slot_message_gateway(); - sector_deps.last_msg_notifier = + auto& sector_dependencies = odu_hi_unit_dependencies.o_du_hi_dependencies.sectors.emplace_back(); + sector_dependencies.gateway = &fapi_adaptors[i]->get_message_interface_collection().get_slot_message_gateway(); + sector_dependencies.last_msg_notifier = &fapi_adaptors[i]->get_message_interface_collection().get_slot_last_message_notifier(); - sector_deps.fapi_executor = du_unit_cfg.odu_high_cfg.fapi_cfg.l2_nof_slots_ahead != 0 - ? std::optional(du_dependencies.workers->fapi_exec[i]) - : std::make_optional(); + sector_dependencies.fapi_executor = du_unit_cfg.odu_high_cfg.fapi_cfg.l2_nof_slots_ahead != 0 + ? std::optional(du_dependencies.workers->fapi_exec[i]) + : std::make_optional(); } - du_high_insts = make_multicell_with_multi_du(du_unit_cfg.odu_high_cfg, std::move(odu_hi_unit_dependencies)); - - odu_unit.commands = std::move(du_high_insts.front().commands); - odu_unit.metrics = std::move(du_high_insts.front().metrics); + o_du_high_unit odu_hi_unit = make_o_du_high_unit(du_unit_cfg.odu_high_cfg, std::move(odu_hi_unit_dependencies)); - std::vector> odu_high_insts; - for (auto& sector : du_high_insts) { - odu_high_insts.push_back(std::move(sector.o_du_hi)); - } + odu_unit.commands = std::move(odu_hi_unit.commands); + odu_unit.metrics = std::move(odu_hi_unit.metrics); // Create the DU. - odu_unit.unit = std::make_unique(std::move(fapi_adaptors), std::move(odu_high_insts)); + odu_unit.unit = std::make_unique(std::move(fapi_adaptors), std::move(odu_hi_unit.o_du_hi)); report_error_if_not(odu_unit.unit, "Invalid Distributed Unit"); announce_du_high_cells(du_hi_unit_cfg); diff --git a/apps/units/flexible_o_du/split_6/split6_o_du_impl.cpp b/apps/units/flexible_o_du/split_6/split6_o_du_impl.cpp index ceb1530f1a..497f98bf12 100644 --- a/apps/units/flexible_o_du/split_6/split6_o_du_impl.cpp +++ b/apps/units/flexible_o_du/split_6/split6_o_du_impl.cpp @@ -14,29 +14,27 @@ using namespace srsran; split6_o_du_impl::split6_o_du_impl(std::vector> adaptors_, - std::vector> du_list_) : - du_list(std::move(du_list_)), adaptors(std::move(adaptors_)) + std::unique_ptr odu_hi_) : + odu_hi(std::move(odu_hi_)), adaptors(std::move(adaptors_)) { - srsran_assert(!du_list.empty(), "Invalid DU high wrapper"); - srsran_assert(adaptors.size() == du_list.size(), "Number of FAPI adaptors does not match number of DUs"); + srsran_assert(odu_hi, "Invalid O-DU high"); + srsran_assert(adaptors.size(), "Invalid FAPI adaptor"); // Hardcoded 0 is because at this moment there is one DU instance with one cell per cell, so we can always access the // cell id 0 of the DU. - for (unsigned i = 0, e = du_list.size(); i != e; ++i) { + for (unsigned i = 0, e = adaptors.size(); i != e; ++i) { adaptors[i]->get_message_interface_collection().set_slot_data_message_notifier( - du_list[i]->get_slot_data_message_notifier(0)); + odu_hi->get_slot_data_message_notifier(i)); adaptors[i]->get_message_interface_collection().set_slot_error_message_notifier( - du_list[i]->get_slot_error_message_notifier(0)); + odu_hi->get_slot_error_message_notifier(i)); adaptors[i]->get_message_interface_collection().set_slot_time_message_notifier( - du_list[i]->get_slot_time_message_notifier(0)); + odu_hi->get_slot_time_message_notifier(i)); } } void split6_o_du_impl::start() { - for (auto& du_obj : du_list) { - du_obj->get_power_controller().start(); - } + odu_hi->get_power_controller().start(); for (auto& adaptor : adaptors) { adaptor->get_power_operation_controller().start(); @@ -45,9 +43,7 @@ void split6_o_du_impl::start() void split6_o_du_impl::stop() { - for (auto& du_obj : du_list) { - du_obj->get_power_controller().stop(); - } + odu_hi->get_power_controller().stop(); for (auto& adaptor : adaptors) { adaptor->get_power_operation_controller().stop(); diff --git a/apps/units/flexible_o_du/split_6/split6_o_du_impl.h b/apps/units/flexible_o_du/split_6/split6_o_du_impl.h index 2b6e0e7ba5..0c74169e42 100644 --- a/apps/units/flexible_o_du/split_6/split6_o_du_impl.h +++ b/apps/units/flexible_o_du/split_6/split6_o_du_impl.h @@ -26,7 +26,7 @@ class split6_o_du_impl : public srs_du::du, public du_power_controller { public: explicit split6_o_du_impl(std::vector> adaptors_, - std::vector> du_list_); + std::unique_ptr odu_hi_); // See interface for documentation. du_power_controller& get_power_controller() override { return *this; } @@ -38,7 +38,7 @@ class split6_o_du_impl : public srs_du::du, public du_power_controller void stop() override; private: - std::vector> du_list; + std::unique_ptr odu_hi; std::vector> adaptors; }; diff --git a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.cpp b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.cpp index f9b4a65149..6f4225d132 100644 --- a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.cpp +++ b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.cpp @@ -50,11 +50,9 @@ void split_7_2_o_du_application_unit_impl::on_parsing_configuration_registration configure_cli11_with_split_7_2_o_du_unit_config_schema(app, unit_cfg); } -o_du_unit split_7_2_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, - bool use_multicell) +o_du_unit split_7_2_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) { - return use_multicell ? multicell_split_7_2_du_factory(unit_cfg).create_flexible_o_du(dependencies) - : split_7_2_o_du_factory(unit_cfg).create_flexible_o_du(dependencies); + return split_7_2_o_du_factory(unit_cfg).create_flexible_o_du(dependencies); } std::unique_ptr srsran::create_flexible_o_du_application_unit(std::string_view app_name) diff --git a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.h b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.h index 697bd61ca5..8594eb5741 100644 --- a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.h +++ b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_application_unit_impl.h @@ -34,7 +34,7 @@ class split_7_2_o_du_application_unit_impl : public flexible_o_du_application_un void on_loggers_registration() override; // See interface for documentation. - o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, bool use_multicell = false) override; + o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) override; // See interface for documentation. o_du_high_unit_config& get_o_du_high_unit_config() override { return unit_cfg.odu_high_cfg; } diff --git a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.cpp b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.cpp index 130211ff93..eeb04eb33f 100644 --- a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.cpp +++ b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.cpp @@ -19,10 +19,3 @@ split_7_2_o_du_factory::create_radio_unit(const flexible_o_du_ru_config& r { return create_ofh_radio_unit(unit_config.ru_cfg.config, ru_config, ru_dependencies); } - -std::unique_ptr -multicell_split_7_2_du_factory::create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) -{ - return create_ofh_radio_unit(unit_config.ru_cfg.config, ru_config, ru_dependencies); -} diff --git a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.h b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.h index e7050015f8..878cad6c30 100644 --- a/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.h +++ b/apps/units/flexible_o_du/split_7_2/split_7_2_o_du_factory.h @@ -11,7 +11,6 @@ #pragma once #include "apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h" -#include "apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h" #include "split_7_2_o_du_unit_config.h" namespace srsran { @@ -32,20 +31,4 @@ class split_7_2_o_du_factory : public flexible_o_du_factory const flexible_o_du_ru_dependencies& ru_dependencies) override; }; -/// Multicell split 7.2 O-RAN DU factory. -class multicell_split_7_2_du_factory : public multicell_flexible_o_du_factory -{ - const split_7_2_o_du_unit_config& unit_config; - -public: - explicit multicell_split_7_2_du_factory(const split_7_2_o_du_unit_config& config_) : - multicell_flexible_o_du_factory({config_.odu_high_cfg, config_.du_low_cfg}), unit_config(config_) - { - } - -private: - std::unique_ptr create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) override; -}; - } // namespace srsran diff --git a/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.cpp b/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.cpp index 9c006e8b6c..e602165835 100644 --- a/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.cpp +++ b/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.cpp @@ -50,11 +50,9 @@ void split_8_o_du_application_unit_impl::on_parsing_configuration_registration(C configure_cli11_with_split_8_o_du_unit_config_schema(app, unit_cfg); } -o_du_unit split_8_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, - bool use_multicell) +o_du_unit split_8_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) { - return use_multicell ? multicell_split8_du_factory(unit_cfg).create_flexible_o_du(dependencies) - : split8_du_factory(unit_cfg).create_flexible_o_du(dependencies); + return split8_du_factory(unit_cfg).create_flexible_o_du(dependencies); } std::unique_ptr srsran::create_flexible_o_du_application_unit(std::string_view app_name) diff --git a/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.h b/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.h index 153d4a3cd2..bda128864d 100644 --- a/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.h +++ b/apps/units/flexible_o_du/split_8/split_8_o_du_application_unit_impl.h @@ -34,7 +34,7 @@ class split_8_o_du_application_unit_impl : public flexible_o_du_application_unit void on_loggers_registration() override; // See interface for documentation. - o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, bool use_multicell = false) override; + o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) override; // See interface for documentation. o_du_high_unit_config& get_o_du_high_unit_config() override { return unit_cfg.odu_high_cfg; } diff --git a/apps/units/flexible_o_du/split_8/split_8_o_du_factory.cpp b/apps/units/flexible_o_du/split_8/split_8_o_du_factory.cpp index e17756ca19..bd59542d2f 100644 --- a/apps/units/flexible_o_du/split_8/split_8_o_du_factory.cpp +++ b/apps/units/flexible_o_du/split_8/split_8_o_du_factory.cpp @@ -18,10 +18,3 @@ std::unique_ptr split8_du_factory::create_radio_unit(const flexible_ { return create_sdr_radio_unit(unit_config.ru_cfg, ru_config, ru_dependencies); } - -std::unique_ptr -multicell_split8_du_factory::create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) -{ - return create_sdr_radio_unit(unit_config.ru_cfg, ru_config, ru_dependencies); -} diff --git a/apps/units/flexible_o_du/split_8/split_8_o_du_factory.h b/apps/units/flexible_o_du/split_8/split_8_o_du_factory.h index d10bd54ca0..6773d777e3 100644 --- a/apps/units/flexible_o_du/split_8/split_8_o_du_factory.h +++ b/apps/units/flexible_o_du/split_8/split_8_o_du_factory.h @@ -11,7 +11,6 @@ #pragma once #include "apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h" -#include "apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h" #include "split_8_o_du_unit_config.h" namespace srsran { @@ -32,20 +31,4 @@ class split8_du_factory : public flexible_o_du_factory const flexible_o_du_ru_dependencies& ru_dependencies) override; }; -/// Multicell split 8 O-RAN DU factory. -class multicell_split8_du_factory : public multicell_flexible_o_du_factory -{ - const split_8_o_du_unit_config& unit_config; - -public: - explicit multicell_split8_du_factory(const split_8_o_du_unit_config& config_) : - multicell_flexible_o_du_factory({config_.odu_high_cfg, config_.du_low_cfg}), unit_config(config_) - { - } - -private: - std::unique_ptr create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) override; -}; - } // namespace srsran diff --git a/apps/units/flexible_o_du/split_dynamic/CMakeLists.txt b/apps/units/flexible_o_du/split_dynamic/CMakeLists.txt index 3bf8dc0b50..28a7a3d96e 100644 --- a/apps/units/flexible_o_du/split_dynamic/CMakeLists.txt +++ b/apps/units/flexible_o_du/split_dynamic/CMakeLists.txt @@ -12,8 +12,7 @@ set(SOURCES dynamic_o_du_translators.cpp dynamic_o_du_unit_cli11_schema.cpp dynamic_o_du_unit_config_validator.cpp - dynamic_o_du_unit_config_yaml_writer.cpp - multicell_dynamic_o_du_factory.cpp) + dynamic_o_du_unit_config_yaml_writer.cpp) add_library(srsran_flexible_o_du_split_dynamic STATIC ${SOURCES}) target_include_directories(srsran_flexible_o_du_split_dynamic PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.cpp b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.cpp index b848c8fb4a..3f75ea93e7 100644 --- a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.cpp +++ b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.cpp @@ -9,14 +9,12 @@ */ #include "dynamic_o_du_application_unit_impl.h" -#include "apps/services/e2/e2_metric_connector_manager.h" #include "dynamic_o_du_factory.h" #include "dynamic_o_du_translators.h" #include "dynamic_o_du_unit_cli11_schema.h" #include "dynamic_o_du_unit_config_validator.h" #include "dynamic_o_du_unit_config_yaml_writer.h" #include "dynamic_o_du_unit_logger_registrator.h" -#include "multicell_dynamic_o_du_factory.h" using namespace srsran; @@ -50,11 +48,9 @@ void dynamic_o_du_application_unit_impl::on_parsing_configuration_registration(C configure_cli11_with_dynamic_o_du_unit_config_schema(app, unit_cfg); } -o_du_unit dynamic_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, - bool use_multicell) +o_du_unit dynamic_o_du_application_unit_impl::create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) { - return use_multicell ? multicell_dynamic_o_du_factory(unit_cfg).create_flexible_o_du(dependencies) - : dynamic_o_du_factory(unit_cfg).create_flexible_o_du(dependencies); + return dynamic_o_du_factory(unit_cfg).create_flexible_o_du(dependencies); } std::unique_ptr srsran::create_flexible_o_du_application_unit(std::string_view app_name) diff --git a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.h b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.h index 3e99352a08..6c146b4956 100644 --- a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.h +++ b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_application_unit_impl.h @@ -36,7 +36,7 @@ class dynamic_o_du_application_unit_impl : public flexible_o_du_application_unit void on_loggers_registration() override; // See interface for documentation. - o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies, bool use_multicell = false) override; + o_du_unit create_flexible_o_du_unit(const o_du_unit_dependencies& dependencies) override; // See interface for documentation. o_du_high_unit_config& get_o_du_high_unit_config() override { return unit_cfg.odu_high_cfg; } diff --git a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.cpp b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.cpp index ec48b8f163..e9dfdeb188 100644 --- a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.cpp +++ b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.cpp @@ -13,7 +13,6 @@ #include "apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_factories.h" #include "apps/units/flexible_o_du/split_8/helpers/ru_sdr_factories.h" #include "dynamic_o_du_translators.h" -#include "dynamic_o_du_unit_config.h" #include "srsran/ru/ru_dummy_factory.h" using namespace srsran; diff --git a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.h b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.h index ba2968dddd..8150b031bd 100644 --- a/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.h +++ b/apps/units/flexible_o_du/split_dynamic/dynamic_o_du_factory.h @@ -10,8 +10,8 @@ #pragma once +#include "apps/units/flexible_o_du/split_dynamic/dynamic_o_du_unit_config.h" #include "apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h" -#include "dynamic_o_du_unit_config.h" namespace srsran { diff --git a/apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.cpp b/apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.cpp deleted file mode 100644 index fe55e6ed8a..0000000000 --- a/apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.cpp +++ /dev/null @@ -1,49 +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 "multicell_dynamic_o_du_factory.h" -#include "apps/services/worker_manager/worker_manager.h" -#include "apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_factories.h" -#include "apps/units/flexible_o_du/split_8/helpers/ru_sdr_factories.h" -#include "dynamic_o_du_translators.h" -#include "srsran/ru/ru_dummy_factory.h" - -using namespace srsran; - -static std::unique_ptr create_dummy_radio_unit(const ru_dummy_unit_config& ru_cfg, - const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) -{ - ru_dummy_dependencies dependencies; - dependencies.logger = &srslog::fetch_basic_logger("RU"); - dependencies.executor = ru_dependencies.workers.radio_exec; - dependencies.timing_notifier = &ru_dependencies.timing_notifier; - dependencies.symbol_notifier = &ru_dependencies.symbol_notifier; - - return create_dummy_ru( - generate_ru_dummy_config(ru_cfg, ru_config.du_cells, ru_config.max_processing_delay, ru_config.prach_nof_ports), - dependencies); -} - -std::unique_ptr -multicell_dynamic_o_du_factory::create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) -{ - const auto& ru_cfg = unit_config.ru_cfg; - if (const auto* cfg = std::get_if(&ru_cfg)) { - return create_ofh_radio_unit(cfg->config, ru_config, ru_dependencies); - } - - if (const auto* cfg = std::get_if(&ru_cfg)) { - return create_sdr_radio_unit(*cfg, ru_config, ru_dependencies); - } - - return create_dummy_radio_unit(std::get(ru_cfg), ru_config, ru_dependencies); -} diff --git a/apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.h b/apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.h deleted file mode 100644 index 2de4b7af85..0000000000 --- a/apps/units/flexible_o_du/split_dynamic/multicell_dynamic_o_du_factory.h +++ /dev/null @@ -1,34 +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 "apps/units/flexible_o_du/split_dynamic/dynamic_o_du_unit_config.h" -#include "apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h" - -namespace srsran { - -/// Multicell dynamic O-RAN DU factory. -class multicell_dynamic_o_du_factory : public multicell_flexible_o_du_factory -{ - const dynamic_o_du_unit_config& unit_config; - -public: - explicit multicell_dynamic_o_du_factory(const dynamic_o_du_unit_config& config_) : - multicell_flexible_o_du_factory({config_.odu_high_cfg, config_.du_low_cfg}), unit_config(config_) - { - } - -private: - std::unique_ptr create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) override; -}; - -} // namespace srsran diff --git a/apps/units/flexible_o_du/split_helpers/CMakeLists.txt b/apps/units/flexible_o_du/split_helpers/CMakeLists.txt index 4f0dc4fb9c..24ce05304d 100644 --- a/apps/units/flexible_o_du/split_helpers/CMakeLists.txt +++ b/apps/units/flexible_o_du/split_helpers/CMakeLists.txt @@ -8,10 +8,7 @@ set(SOURCES flexible_o_du_factory.cpp - flexible_o_du_impl.cpp - multicell_flexible_o_du_factory.cpp - multicell_flexible_o_du_impl.cpp - o_du_high_factory.cpp) + flexible_o_du_impl.cpp) add_library(srsran_flexible_du_helpers STATIC ${SOURCES}) target_include_directories(srsran_flexible_du_helpers PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp b/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp index f1b3b2ba4a..4a5a7586d8 100644 --- a/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp +++ b/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp @@ -15,9 +15,7 @@ #include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.h" #include "apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h" #include "apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.h" -#include "apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.h" -#include "o_du_high_factory.h" -#include "srsran/du/o_du.h" +#include "flexible_o_du_impl.h" #include "srsran/du/o_du_factory.h" #include "srsran/e2/e2_du_metrics_connector.h" @@ -25,9 +23,9 @@ using namespace srsran; o_du_unit flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependencies& dependencies) { - o_du_unit odu_unit; - const unsigned nof_cells = config.odu_high_cfg.du_high_cfg.config.cells_cfg.size(); - odu_unit.e2_metric_connectors = std::make_unique< + o_du_unit o_du; + const unsigned nof_cells = config.odu_high_cfg.du_high_cfg.config.cells_cfg.size(); + o_du.e2_metric_connectors = std::make_unique< e2_metric_connector_manager>(nof_cells); const du_high_unit_config& du_hi = config.odu_high_cfg.du_high_cfg.config; @@ -35,8 +33,7 @@ o_du_unit flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependenci auto du_cells = generate_du_cell_config(du_hi); - std::vector> du_insts; - auto du_impl = std::make_unique(nof_cells); + auto du_impl = std::make_unique(nof_cells); std::vector prach_ports; std::vector max_pusch_per_slot; @@ -45,56 +42,41 @@ o_du_unit flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependenci max_pusch_per_slot.push_back(high.cell.pusch_cfg.max_puschs_per_slot); } - // O-DU low factory is common for all the cells. + o_du_low_unit_config odu_low_cfg = {du_lo, prach_ports, du_cells, max_pusch_per_slot}; + o_du_low_unit_dependencies odu_low_dependencies = { + du_impl->get_upper_ru_dl_rg_adapter(), du_impl->get_upper_ru_ul_request_adapter(), *dependencies.workers}; o_du_low_unit_factory odu_low_factory(du_lo.hal_config, nof_cells); - - // Create O-DU low. - std::vector du_low_units; + auto odu_lo_unit = odu_low_factory.create(odu_low_cfg, odu_low_dependencies); + + o_du_high_unit_dependencies odu_hi_unit_dependencies = {dependencies.workers->get_du_high_executor_mapper(0), + *dependencies.f1c_client_handler, + *dependencies.f1u_gw, + *dependencies.timer_mng, + *dependencies.mac_p, + *dependencies.rlc_p, + *dependencies.e2_client_handler, + *(o_du.e2_metric_connectors), + *dependencies.json_sink, + *dependencies.metrics_notifier, + {}}; + + // Adjust the dependencies. for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { - o_du_low_unit_config odu_low_cfg = {du_lo, - {prach_ports[i]}, - span(&du_cells[i], 1), - span(&max_pusch_per_slot[i], 1), - i, - nof_cells}; - - o_du_low_unit_dependencies odu_low_dependencies = { - du_impl->get_upper_ru_dl_rg_adapter(), du_impl->get_upper_ru_ul_request_adapter(), *dependencies.workers}; - du_low_units.push_back(odu_low_factory.create(odu_low_cfg, odu_low_dependencies)); + auto& sector_dependencies = odu_hi_unit_dependencies.o_du_hi_dependencies.sectors.emplace_back(); + sector_dependencies.gateway = &odu_lo_unit.o_du_lo->get_slot_message_gateway(i); + sector_dependencies.last_msg_notifier = &odu_lo_unit.o_du_lo->get_slot_last_message_notifier(i); + sector_dependencies.fapi_executor = config.odu_high_cfg.fapi_cfg.l2_nof_slots_ahead != 0 + ? std::optional(dependencies.workers->fapi_exec[i]) + : std::make_optional(); } - // Create O-DU high. - o_du_high_unit_factory_dependencies odu_hi_unit_dependencies = {*dependencies.workers, - *dependencies.f1c_client_handler, - *dependencies.f1u_gw, - *dependencies.timer_mng, - *dependencies.mac_p, - *dependencies.rlc_p, - *dependencies.e2_client_handler, - *(odu_unit.e2_metric_connectors), - *dependencies.json_sink, - *dependencies.metrics_notifier, - {}}; + o_du_high_unit odu_hi_unit = make_o_du_high_unit(config.odu_high_cfg, std::move(odu_hi_unit_dependencies)); - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { - auto& sector_deps = odu_hi_unit_dependencies.o_du_hi_dependencies.sectors.emplace_back(); - sector_deps.gateway = &du_low_units[i].o_du_lo->get_slot_message_gateway(0); - sector_deps.last_msg_notifier = &du_low_units[i].o_du_lo->get_slot_last_message_notifier(0); - sector_deps.fapi_executor = config.odu_high_cfg.fapi_cfg.l2_nof_slots_ahead != 0 - ? std::optional(dependencies.workers->fapi_exec[i]) - : std::make_optional(); - } - std::vector du_high_units = - make_multicell_with_multi_du(config.odu_high_cfg, std::move(odu_hi_unit_dependencies)); + o_du.metrics = std::move(odu_hi_unit.metrics); + o_du.commands = std::move(odu_hi_unit.commands); - // Create the O-DU. - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { - du_insts.push_back(srs_du::make_o_du(std::move(du_high_units[i].o_du_hi), std::move(du_low_units[i].o_du_lo))); - } - - // Move commands and metrics. - odu_unit.metrics = std::move(du_high_units.front().metrics); - odu_unit.commands = std::move(du_high_units.front().commands); + auto odu_instance = make_o_du(std::move(odu_hi_unit.o_du_hi), std::move(odu_lo_unit.o_du_lo)); + report_error_if_not(odu_instance, "Invalid Distributed Unit"); flexible_o_du_ru_config ru_config{{du_cells}, du_lo.expert_phy_cfg.max_processing_delay_slots, @@ -105,17 +87,22 @@ o_du_unit flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependenci du_impl->get_upper_ru_error_adapter()}; std::unique_ptr ru = create_radio_unit(ru_config, ru_dependencies); + srsran_assert(ru, "Invalid Radio Unit"); // Add RU commands. - odu_unit.commands.push_back(std::make_unique()); - odu_unit.commands.push_back(std::make_unique(ru->get_controller())); - odu_unit.commands.push_back(std::make_unique(ru->get_controller())); - odu_unit.commands.push_back(std::make_unique(ru->get_controller())); + o_du.commands.push_back(std::make_unique()); + o_du.commands.push_back(std::make_unique(ru->get_controller())); + o_du.commands.push_back(std::make_unique(ru->get_controller())); + o_du.commands.push_back(std::make_unique(ru->get_controller())); + // Configure the RU and DU in the dynamic DU. du_impl->add_ru(std::move(ru)); - du_impl->add_o_dus(std::move(du_insts)); - odu_unit.unit = std::move(du_impl); + du_impl->add_du(std::move(odu_instance)); + + o_du.unit = std::move(du_impl); + + announce_du_high_cells(du_hi); - return odu_unit; + return o_du; } diff --git a/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h b/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h index bb36421b67..dc46207e58 100644 --- a/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h +++ b/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.h @@ -23,7 +23,6 @@ class flexible_o_du_factory public: explicit flexible_o_du_factory(const flexible_o_du_unit_config& config_) : config(config_) {} - virtual ~flexible_o_du_factory() = default; /// Creates a flexible O-RAN DU using the given dependencies and configuration. diff --git a/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.cpp b/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.cpp index 49ebda093d..434c927b31 100644 --- a/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.cpp +++ b/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.cpp @@ -25,20 +25,14 @@ flexible_o_du_impl::flexible_o_du_impl(unsigned nof_cells) : void flexible_o_du_impl::start() { - for (auto& du_obj : du_list) { - du_obj->get_power_controller().start(); - } - + du->get_power_controller().start(); ru->get_controller().start(); } void flexible_o_du_impl::stop() { ru->get_controller().stop(); - - for (auto& du_obj : du_list) { - du_obj->get_power_controller().stop(); - } + du->get_power_controller().stop(); } void flexible_o_du_impl::add_ru(std::unique_ptr active_ru) @@ -46,22 +40,22 @@ void flexible_o_du_impl::add_ru(std::unique_ptr active_ru) ru = std::move(active_ru); srsran_assert(ru, "Invalid Radio Unit"); + // Connect the RU adaptor to the RU. ru_dl_rg_adapt.connect(ru->get_downlink_plane_handler()); ru_ul_request_adapt.connect(ru->get_uplink_plane_handler()); } -void flexible_o_du_impl::add_o_dus(std::vector> active_o_du) +void flexible_o_du_impl::add_du(std::unique_ptr active_du) { - du_list = std::move(active_o_du); - srsran_assert(!du_list.empty(), "Cannot set an empty DU list"); - - for (auto& du_obj : du_list) { - span upper_ptrs = du_obj->get_o_du_low().get_du_low().get_all_upper_phys(); - for (auto* upper : upper_ptrs) { - // Make connections between DU and RU. - ru_ul_adapt.map_handler(upper->get_sector_id(), upper->get_rx_symbol_handler()); - ru_timing_adapt.map_handler(upper->get_sector_id(), upper->get_timing_handler()); - ru_error_adapt.map_handler(upper->get_sector_id(), upper->get_error_handler()); - } + du = std::move(active_du); + srsran_assert(du, "Cannot set an invalid DU"); + + // Connect all the sectors of the DU low to the RU adaptors. + span upper_ptrs = du->get_o_du_low().get_du_low().get_all_upper_phys(); + for (auto* upper : upper_ptrs) { + // Make connections between DU and RU. + ru_ul_adapt.map_handler(upper->get_sector_id(), upper->get_rx_symbol_handler()); + ru_timing_adapt.map_handler(upper->get_sector_id(), upper->get_timing_handler()); + ru_error_adapt.map_handler(upper->get_sector_id(), upper->get_error_handler()); } } diff --git a/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.h b/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.h index 1edef2c9ce..7564e92d3e 100644 --- a/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.h +++ b/apps/units/flexible_o_du/split_helpers/flexible_o_du_impl.h @@ -15,7 +15,6 @@ #include "srsran/du/o_du.h" #include "srsran/ru/ru_adapters.h" #include -#include namespace srsran { @@ -23,7 +22,7 @@ class radio_unit; /// \brief Flexible O-RAN DU implementation. /// -/// The O-RAN DU manages only one cell. To achieve multicell, one O-RAN DU is created per cell. +/// One O-RAN DU can handle more than one cell. class flexible_o_du_impl : public srs_du::du, public du_power_controller { public: @@ -38,11 +37,11 @@ class flexible_o_du_impl : public srs_du::du, public du_power_controller // See interface for documentation. void stop() override; - /// Adds the given RU to this dynamic DU. + /// Adds the given RU to this flexible O-RAN DU. void add_ru(std::unique_ptr active_ru); - /// Adds the given DUs to this dynamic DU. - void add_o_dus(std::vector> active_o_du); + /// Adds the given DU to this flexible O-RAN DU. + void add_du(std::unique_ptr active_du); /// Getters to the adaptors. upper_phy_ru_ul_adapter& get_upper_ru_ul_adapter() { return ru_ul_adapt; } @@ -52,13 +51,13 @@ class flexible_o_du_impl : public srs_du::du, public du_power_controller upper_phy_ru_ul_request_adapter& get_upper_ru_ul_request_adapter() { return ru_ul_request_adapt; } private: - upper_phy_ru_ul_adapter ru_ul_adapt; - upper_phy_ru_timing_adapter ru_timing_adapt; - upper_phy_ru_error_adapter ru_error_adapt; - std::vector> du_list; - std::unique_ptr ru; - upper_phy_ru_dl_rg_adapter ru_dl_rg_adapt; - upper_phy_ru_ul_request_adapter ru_ul_request_adapt; + upper_phy_ru_ul_adapter ru_ul_adapt; + upper_phy_ru_timing_adapter ru_timing_adapt; + upper_phy_ru_error_adapter ru_error_adapt; + std::unique_ptr du; + std::unique_ptr ru; + upper_phy_ru_dl_rg_adapter ru_dl_rg_adapt; + upper_phy_ru_ul_request_adapter ru_ul_request_adapt; }; } // namespace srsran diff --git a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.cpp b/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.cpp deleted file mode 100644 index f9b74ae42d..0000000000 --- a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.cpp +++ /dev/null @@ -1,112 +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 "multicell_flexible_o_du_factory.h" -#include "apps/services/e2/e2_metric_connector_manager.h" -#include "apps/services/worker_manager/worker_manager.h" -#include "apps/units/flexible_o_du/flexible_o_du_commands.h" -#include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.h" -#include "apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h" -#include "apps/units/flexible_o_du/o_du_low/o_du_low_unit_factory.h" -#include "multicell_flexible_o_du_impl.h" -#include "srsran/du/o_du_factory.h" -#include "srsran/e2/e2_du_metrics_connector.h" - -using namespace srsran; - -o_du_unit multicell_flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependencies& dependencies) -{ - o_du_unit o_du; - const unsigned nof_cells = config.odu_high_cfg.du_high_cfg.config.cells_cfg.size(); - o_du.e2_metric_connectors = std::make_unique< - e2_metric_connector_manager>(nof_cells); - - const du_high_unit_config& du_hi = config.odu_high_cfg.du_high_cfg.config; - const du_low_unit_config& du_lo = config.du_low_cfg; - - auto du_cells = generate_du_cell_config(du_hi); - - auto du_impl = std::make_unique(nof_cells); - - std::vector prach_ports; - std::vector max_pusch_per_slot; - for (const auto& high : du_hi.cells_cfg) { - prach_ports.push_back(high.cell.prach_cfg.ports); - max_pusch_per_slot.push_back(high.cell.pusch_cfg.max_puschs_per_slot); - } - - static constexpr unsigned du_id = 0U; - o_du_low_unit_config odu_low_cfg = { - du_lo, prach_ports, du_cells, max_pusch_per_slot, du_id, static_cast(du_cells.size())}; - o_du_low_unit_dependencies odu_low_dependencies = { - du_impl->get_upper_ru_dl_rg_adapter(), du_impl->get_upper_ru_ul_request_adapter(), *dependencies.workers}; - o_du_low_unit_factory odu_low_factory(du_lo.hal_config, nof_cells); - auto odu_lo_unit = odu_low_factory.create(odu_low_cfg, odu_low_dependencies); - - o_du_high_unit_params odu_hi_unit_params = {config.odu_high_cfg, du_id}; - - o_du_high_unit_dependencies odu_hi_unit_dependencies = {dependencies.workers->get_du_high_executor_mapper(du_id), - *dependencies.f1c_client_handler, - *dependencies.f1u_gw, - *dependencies.timer_mng, - *dependencies.mac_p, - *dependencies.rlc_p, - *dependencies.e2_client_handler, - *(o_du.e2_metric_connectors), - *dependencies.json_sink, - *dependencies.metrics_notifier, - {}}; - - // Adjust the dependencies. - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { - auto& sector_dependencies = odu_hi_unit_dependencies.o_du_hi_dependencies.sectors.emplace_back(); - sector_dependencies.gateway = &odu_lo_unit.o_du_lo->get_slot_message_gateway(i); - sector_dependencies.last_msg_notifier = &odu_lo_unit.o_du_lo->get_slot_last_message_notifier(i); - sector_dependencies.fapi_executor = config.odu_high_cfg.fapi_cfg.l2_nof_slots_ahead != 0 - ? std::optional(dependencies.workers->fapi_exec[i]) - : std::make_optional(); - } - - o_du_high_unit odu_hi_unit = make_o_du_high_unit(odu_hi_unit_params, std::move(odu_hi_unit_dependencies)); - - o_du.metrics = std::move(odu_hi_unit.metrics); - o_du.commands = std::move(odu_hi_unit.commands); - - auto odu_instance = make_o_du(std::move(odu_hi_unit.o_du_hi), std::move(odu_lo_unit.o_du_lo)); - report_error_if_not(odu_instance, "Invalid Distributed Unit"); - - flexible_o_du_ru_config ru_config{{du_cells}, - du_lo.expert_phy_cfg.max_processing_delay_slots, - static_cast(du_hi.cells_cfg.front().cell.prach_cfg.ports.size())}; - flexible_o_du_ru_dependencies ru_dependencies{*dependencies.workers, - du_impl->get_upper_ru_ul_adapter(), - du_impl->get_upper_ru_timing_adapter(), - du_impl->get_upper_ru_error_adapter()}; - - std::unique_ptr ru = create_radio_unit(ru_config, ru_dependencies); - - srsran_assert(ru, "Invalid Radio Unit"); - - // Add RU commands. - o_du.commands.push_back(std::make_unique()); - o_du.commands.push_back(std::make_unique(ru->get_controller())); - o_du.commands.push_back(std::make_unique(ru->get_controller())); - o_du.commands.push_back(std::make_unique(ru->get_controller())); - - // Configure the RU and DU in the dynamic DU. - du_impl->add_ru(std::move(ru)); - du_impl->add_du(std::move(odu_instance)); - - o_du.unit = std::move(du_impl); - - announce_du_high_cells(du_hi); - - return o_du; -} diff --git a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h b/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h deleted file mode 100644 index dd53737400..0000000000 --- a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_factory.h +++ /dev/null @@ -1,37 +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 "apps/units/flexible_o_du/o_du_unit.h" -#include "apps/units/flexible_o_du/split_helpers/flexible_o_du_configs.h" -#include "srsran/ru/ru.h" - -namespace srsran { - -/// Multicell flexible O-RAN DU factory interface. -class multicell_flexible_o_du_factory -{ - const flexible_o_du_unit_config config; - -public: - explicit multicell_flexible_o_du_factory(const flexible_o_du_unit_config& config_) : config(config_) {} - virtual ~multicell_flexible_o_du_factory() = default; - - /// Creates a multicell flexible O-RAN DU using the given dependencies and configuration. - o_du_unit create_flexible_o_du(const o_du_unit_dependencies& dependencies); - -private: - /// Creates a Radio Unit using the given config and dependencies. - virtual std::unique_ptr create_radio_unit(const flexible_o_du_ru_config& ru_config, - const flexible_o_du_ru_dependencies& ru_dependencies) = 0; -}; - -} // namespace srsran diff --git a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.cpp b/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.cpp deleted file mode 100644 index 06aa66ea5a..0000000000 --- a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.cpp +++ /dev/null @@ -1,61 +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 "multicell_flexible_o_du_impl.h" -#include "srsran/du/du_low/du_low.h" -#include "srsran/du/du_low/o_du_low.h" -#include "srsran/du/o_du.h" -#include "srsran/phy/upper/upper_phy.h" -#include "srsran/ru/ru.h" -#include "srsran/ru/ru_controller.h" - -using namespace srsran; - -multicell_flexible_o_du_impl::multicell_flexible_o_du_impl(unsigned nof_cells) : - ru_ul_adapt(nof_cells), ru_timing_adapt(nof_cells), ru_error_adapt(nof_cells) -{ -} - -void multicell_flexible_o_du_impl::start() -{ - du->get_power_controller().start(); - ru->get_controller().start(); -} - -void multicell_flexible_o_du_impl::stop() -{ - ru->get_controller().stop(); - du->get_power_controller().stop(); -} - -void multicell_flexible_o_du_impl::add_ru(std::unique_ptr active_ru) -{ - ru = std::move(active_ru); - srsran_assert(ru, "Invalid Radio Unit"); - - // Connect the RU adaptor to the RU. - ru_dl_rg_adapt.connect(ru->get_downlink_plane_handler()); - ru_ul_request_adapt.connect(ru->get_uplink_plane_handler()); -} - -void multicell_flexible_o_du_impl::add_du(std::unique_ptr active_du) -{ - du = std::move(active_du); - srsran_assert(du, "Cannot set an invalid DU"); - - // Connect all the sectors of the DU low to the RU adaptors. - span upper_ptrs = du->get_o_du_low().get_du_low().get_all_upper_phys(); - for (auto* upper : upper_ptrs) { - // Make connections between DU and RU. - ru_ul_adapt.map_handler(upper->get_sector_id(), upper->get_rx_symbol_handler()); - ru_timing_adapt.map_handler(upper->get_sector_id(), upper->get_timing_handler()); - ru_error_adapt.map_handler(upper->get_sector_id(), upper->get_error_handler()); - } -} diff --git a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.h b/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.h deleted file mode 100644 index 4233b58ea6..0000000000 --- a/apps/units/flexible_o_du/split_helpers/multicell_flexible_o_du_impl.h +++ /dev/null @@ -1,63 +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/du/du.h" -#include "srsran/du/du_power_controller.h" -#include "srsran/du/o_du.h" -#include "srsran/ru/ru_adapters.h" -#include - -namespace srsran { - -class radio_unit; - -/// \brief Multicell flexible O-RAN DU implementation. -/// -/// One O-RAN DU can handle more than one cell. -class multicell_flexible_o_du_impl : public srs_du::du, public du_power_controller -{ -public: - explicit multicell_flexible_o_du_impl(unsigned nof_cells); - - // See interface for documentation. - du_power_controller& get_power_controller() override { return *this; } - - // See interface for documentation. - void start() override; - - // See interface for documentation. - void stop() override; - - /// Adds the given RU to this flexible O-RAN DU. - void add_ru(std::unique_ptr active_ru); - - /// Adds the given DU to this flexible O-RAN DU. - void add_du(std::unique_ptr active_du); - - /// Getters to the adaptors. - upper_phy_ru_ul_adapter& get_upper_ru_ul_adapter() { return ru_ul_adapt; } - upper_phy_ru_timing_adapter& get_upper_ru_timing_adapter() { return ru_timing_adapt; } - upper_phy_ru_error_adapter& get_upper_ru_error_adapter() { return ru_error_adapt; } - upper_phy_ru_dl_rg_adapter& get_upper_ru_dl_rg_adapter() { return ru_dl_rg_adapt; } - upper_phy_ru_ul_request_adapter& get_upper_ru_ul_request_adapter() { return ru_ul_request_adapt; } - -private: - upper_phy_ru_ul_adapter ru_ul_adapt; - upper_phy_ru_timing_adapter ru_timing_adapt; - upper_phy_ru_error_adapter ru_error_adapt; - std::unique_ptr du; - std::unique_ptr ru; - upper_phy_ru_dl_rg_adapter ru_dl_rg_adapt; - upper_phy_ru_ul_request_adapter ru_ul_request_adapt; -}; - -} // namespace srsran diff --git a/apps/units/flexible_o_du/split_helpers/o_du_high_factory.cpp b/apps/units/flexible_o_du/split_helpers/o_du_high_factory.cpp deleted file mode 100644 index 14be23e3e5..0000000000 --- a/apps/units/flexible_o_du/split_helpers/o_du_high_factory.cpp +++ /dev/null @@ -1,99 +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 "o_du_high_factory.h" -#include "apps/services/worker_manager/worker_manager.h" -#include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.h" -#include "apps/units/flexible_o_du/o_du_high/o_du_high_unit_config.h" - -using namespace srsran; - -/// \brief Update the Flexible DU metrics configuration with the given local DU configuration and E2 configuration. -/// -/// This function manages the multi cell workaround for the DU high metrics. To have multi cell, now one DU is -/// instantiated per cell, so this would create multiple consumers that does not make sense, for example stdout. -/// With this we avoid having 2 different objects that write in the stdout. -static void update_du_metrics(std::vector& flexible_du_cfg, - std::vector local_du_cfg, - bool is_e2_enabled) -{ - // First call, copy everything. - if (flexible_du_cfg.empty()) { - flexible_du_cfg = std::move(local_du_cfg); - return; - } - - // Safe check that all the DUs provides the same amount of metrics. - srsran_assert(flexible_du_cfg.size() == local_du_cfg.size(), - "Flexible DU metrics size '{}' does not match DU metrics size '{}'", - flexible_du_cfg.size(), - local_du_cfg.size()); - - // Iterate the metrics configs of each DU. Each DU should ha - for (unsigned i = 0, e = local_du_cfg.size(); i != e; ++i) { - // Store the metrics producers for each DU. - flexible_du_cfg[i].producers.push_back(std::move(local_du_cfg[i].producers.back())); - - // Move E2 consumers for each DU to the common output config. E2 Consumers occupy the last position. - if (is_e2_enabled) { - flexible_du_cfg[i].consumers.push_back(std::move(local_du_cfg[i].consumers.back())); - } - } -} - -std::vector srsran::make_multicell_with_multi_du(const o_du_high_unit_config& o_du_high_unit_cfg, - o_du_high_unit_factory_dependencies&& dependencies) -{ - const du_high_unit_config& du_hi = o_du_high_unit_cfg.du_high_cfg.config; - - auto du_cells = generate_du_cell_config(du_hi); - - std::vector du_insts; - - for (unsigned i = 0, e = du_cells.size(); i != e; ++i) { - // Create one DU per cell. - o_du_high_unit_config tmp_cfg; - tmp_cfg.du_high_cfg.config = du_hi; - tmp_cfg.du_high_cfg.config.cells_cfg.resize(1); - tmp_cfg.du_high_cfg.config.cells_cfg[0] = du_hi.cells_cfg[i]; - tmp_cfg.fapi_cfg = o_du_high_unit_cfg.fapi_cfg; - tmp_cfg.e2_cfg = o_du_high_unit_cfg.e2_cfg; - srs_du::o_du_high_dependencies sector_deps; - sector_deps.sectors.push_back(dependencies.o_du_hi_dependencies.sectors[i]); - - o_du_high_unit_params odu_hi_unit_params = {tmp_cfg, i}; - o_du_high_unit_dependencies odu_hi_unit_dependencies = {dependencies.workers.get_du_high_executor_mapper(i), - dependencies.f1c_client_handler, - dependencies.f1u_gw, - dependencies.timer_mng, - dependencies.mac_p, - dependencies.rlc_p, - dependencies.e2_client_handler, - dependencies.e2_metric_connectors, - dependencies.json_sink, - dependencies.metrics_notifier, - sector_deps}; - - du_insts.push_back(make_o_du_high_unit(odu_hi_unit_params, std::move(odu_hi_unit_dependencies))); - - if (i != 0) { - update_du_metrics( - du_insts.front().metrics, std::move(du_insts.back().metrics), tmp_cfg.e2_cfg.base_cfg.enable_unit_e2); - - // Use commands of the first cell only. - du_insts.back().commands.clear(); - } - } - - // Configure the application unit metrics for the DU high. - announce_du_high_cells(du_hi); - - return du_insts; -} diff --git a/apps/units/flexible_o_du/split_helpers/o_du_high_factory.h b/apps/units/flexible_o_du/split_helpers/o_du_high_factory.h deleted file mode 100644 index bd52ee7760..0000000000 --- a/apps/units/flexible_o_du/split_helpers/o_du_high_factory.h +++ /dev/null @@ -1,38 +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 "apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h" - -namespace srsran { - -struct worker_manager; - -/// O-RAN DU high unit factory dependencies. -struct o_du_high_unit_factory_dependencies { - worker_manager& workers; - srs_du::f1c_connection_client& f1c_client_handler; - srs_du::f1u_du_gateway& f1u_gw; - timer_manager& timer_mng; - mac_pcap& mac_p; - rlc_pcap& rlc_p; - e2_connection_client& e2_client_handler; - e2_du_metrics_connector_manager& e2_metric_connectors; - srslog::sink& json_sink; - app_services::metrics_notifier& metrics_notifier; - srs_du::o_du_high_dependencies o_du_hi_dependencies; -}; - -/// Creates one O-RAN DU high per cell. -std::vector make_multicell_with_multi_du(const o_du_high_unit_config& o_du_high_unit_cfg, - o_du_high_unit_factory_dependencies&& dependencies); - -} // namespace srsran From 0aa50575d289260e8561a6029b25b86b838e1262 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Wed, 18 Dec 2024 10:45:23 +0100 Subject: [PATCH 223/227] configs: set pusch mcs table to qam64 in the config for srsUE --- configs/gnb_rf_b210_fdd_srsUE.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/gnb_rf_b210_fdd_srsUE.yml b/configs/gnb_rf_b210_fdd_srsUE.yml index d90752e382..2f62626095 100644 --- a/configs/gnb_rf_b210_fdd_srsUE.yml +++ b/configs/gnb_rf_b210_fdd_srsUE.yml @@ -43,6 +43,8 @@ cell_cfg: prach_config_index: 1 pdsch: mcs_table: qam64 + pusch: + mcs_table: qam64 log: filename: /tmp/gnb.log From 79cd0b6a4adf3c21179c96f23c1d778c1cc26e67 Mon Sep 17 00:00:00 2001 From: faluco Date: Fri, 29 Nov 2024 16:31:33 +0100 Subject: [PATCH 224/227] Update FMT library to v11 and adapt all codebase to new API changes --- COPYRIGHT | 14 +- apps/cu/cu.cpp | 2 +- apps/du/du.cpp | 2 +- apps/examples/ofh/ru_emulator.cpp | 9 +- apps/examples/phy/radio_ssb.cpp | 14 +- apps/gnb/gnb.cpp | 2 +- .../cli11_cpu_affinities_parser_helper.cpp | 7 +- .../du_high/du_high_config_cli11_schema.cpp | 6 +- .../du_high/du_high_config_translators.cpp | 3 +- .../du_high/du_high_config_validator.cpp | 15 +- .../metrics/du_high_rlc_metrics_consumers.cpp | 16 +- ..._high_scheduler_cell_metrics_consumers.cpp | 104 +- .../o_du_high/o_du_high_unit_factory.cpp | 4 +- .../helpers/ru_sdr_config_translator.cpp | 6 +- .../fmt/include/fmt/{LICENSE.rst => LICENSE} | 2 +- external/fmt/include/fmt/args.h | 228 + external/fmt/include/fmt/base.h | 3077 ++++++++ external/fmt/include/fmt/chrono.h | 2105 +++++- external/fmt/include/fmt/color.h | 382 +- external/fmt/include/fmt/compile.h | 792 +- external/fmt/include/fmt/core.h | 1890 +---- external/fmt/include/fmt/format-inl.h | 2951 ++++---- external/fmt/include/fmt/format.h | 6464 +++++++++-------- external/fmt/include/fmt/locale.h | 78 - external/fmt/include/fmt/os.h | 467 +- external/fmt/include/fmt/ostream.h | 260 +- external/fmt/include/fmt/posix.h | 2 - external/fmt/include/fmt/printf.h | 729 +- external/fmt/include/fmt/ranges.h | 970 ++- external/fmt/include/fmt/std.h | 699 ++ external/fmt/include/fmt/xchar.h | 322 + external/fmt/src/format.cc | 64 +- external/fmt/src/os.cc | 358 +- include/srsran/adt/bit_buffer.h | 2 +- include/srsran/adt/bounded_bitset.h | 3 +- include/srsran/adt/bounded_integer.h | 3 +- include/srsran/adt/byte_buffer.h | 4 +- include/srsran/adt/byte_buffer_chain.h | 2 +- include/srsran/adt/byte_buffer_view.h | 2 +- include/srsran/adt/complex.h | 4 +- include/srsran/adt/interval.h | 3 +- include/srsran/adt/span.h | 19 +- include/srsran/adt/static_vector.h | 1 + .../srsran/cu_cp/cell_meas_manager_config.h | 2 +- include/srsran/cu_cp/cu_cp_types.h | 8 +- include/srsran/cu_up/cu_up_config.h | 2 +- include/srsran/cu_up/cu_up_types.h | 12 +- .../du/du_high/du_high_executor_mapper.h | 2 + .../f1ap/du/f1ap_du_ue_context_update.h | 1 + include/srsran/f1u/cu_up/f1u_bearer_logger.h | 4 +- include/srsran/f1u/cu_up/f1u_config.h | 2 +- include/srsran/f1u/du/f1u_bearer_logger.h | 10 +- include/srsran/f1u/du/f1u_config.h | 2 +- .../f1u/local_connector/f1u_local_connector.h | 2 +- include/srsran/fapi/message_builders.h | 4 +- include/srsran/gtpu/gtpu_config.h | 20 +- include/srsran/gtpu/gtpu_teid.h | 2 +- include/srsran/gtpu/gtpu_teid_pool_factory.h | 1 + ...t_harq_buffer_context_repository_factory.h | 1 + include/srsran/nru/nru_packing.h | 2 +- .../ofh/compression/compression_params.h | 1 + .../dpdk/dpdk_ethernet_port_context.h | 1 + include/srsran/pcap/rlc_pcap.h | 3 +- include/srsran/pdcp/pdcp_config.h | 117 +- include/srsran/pdcp/pdcp_rx_metrics.h | 2 +- include/srsran/pdcp/pdcp_sn_size.h | 2 +- include/srsran/pdcp/pdcp_tx_metrics.h | 2 +- include/srsran/phy/lower/sampling_rate.h | 2 +- include/srsran/phy/support/mask_types.h | 4 +- .../srsran/phy/support/precoding_formatters.h | 3 +- .../phy/support/re_pattern_formatters.h | 2 +- .../srsran/phy/support/support_formatters.h | 3 +- .../channel_processor_formatters.h | 12 +- .../channel_processors/pdsch/formatters.h | 6 +- .../channel_processors/pucch/formatters.h | 14 +- .../channel_processors/pusch/formatters.h | 21 +- .../channel_state_information_formatters.h | 3 +- .../srsran/phy/upper/log_likelihood_ratio.h | 2 +- include/srsran/phy/upper/rb_allocation.h | 3 +- .../signal_processor_formatters.h | 5 +- .../upper/signal_processors/srs/formatters.h | 6 +- .../srsran/phy/upper/trx_buffer_identifier.h | 5 +- include/srsran/ran/cause/e1ap_cause.h | 10 +- include/srsran/ran/cause/f1ap_cause.h | 10 +- include/srsran/ran/cause/ngap_cause.h | 13 +- .../srsran/ran/csi_report/csi_report_data.h | 1 - .../ran/csi_report/csi_report_formatters.h | 11 +- include/srsran/ran/csi_rs/csi_meas_config.h | 30 +- include/srsran/ran/cu_types.h | 11 +- include/srsran/ran/cyclic_prefix.h | 2 +- include/srsran/ran/du_types.h | 9 +- include/srsran/ran/frequency_range.h | 14 +- include/srsran/ran/gnb_du_id.h | 8 +- .../srsran/ran/logical_channel/lcid_dl_sch.h | 2 +- include/srsran/ran/nr_cell_identity.h | 5 +- include/srsran/ran/pdcch/dci_packing.h | 1 - .../srsran/ran/pdcch/dci_packing_formatters.h | 10 +- .../ran/pdcch/pdcch_context_formatter.h | 4 +- include/srsran/ran/pdcch/search_space.h | 3 +- .../ran/pdsch/pdsch_context_formatter.h | 4 +- include/srsran/ran/plmn_identity.h | 8 +- .../precoding_weight_matrix_formatters.h | 3 +- .../ran/pucch/pucch_context_formatter.h | 2 +- .../ran/pusch/pusch_context_formatter.h | 4 +- include/srsran/ran/qos/five_qi.h | 12 +- include/srsran/ran/qos/qos_flow_id.h | 2 +- include/srsran/ran/qos/qos_prio_level.h | 3 +- include/srsran/ran/rb_id.h | 6 +- .../resource_allocation/ofdm_symbol_range.h | 2 +- include/srsran/ran/resource_block.h | 2 + include/srsran/ran/rnti.h | 2 +- include/srsran/ran/sch/modulation_scheme.h | 2 +- include/srsran/ran/serv_cell_index.h | 4 +- include/srsran/ran/slot_point.h | 2 +- .../ran/srs/srs_channel_matrix_formatters.h | 3 +- .../srsran/ran/srs/srs_resource_formatter.h | 11 +- include/srsran/ran/subcarrier_spacing.h | 21 +- .../ran/tdd/tdd_ul_dl_config_formatters.h | 11 +- include/srsran/ran/uci/uci_formatters.h | 6 +- include/srsran/ran/uci/uci_mapping.h | 4 +- include/srsran/ran/up_transport_layer_info.h | 2 +- include/srsran/rlc/rlc_config.h | 32 +- include/srsran/rlc/rlc_mode.h | 2 +- include/srsran/rlc/rlc_rx_metrics.h | 8 +- include/srsran/rlc/rlc_tx_metrics.h | 14 +- include/srsran/rrc/meas_types.h | 5 +- .../config/scheduler_expert_config.h | 1 + .../scheduler/config/serving_cell_config.h | 1 + include/srsran/scheduler/harq_id.h | 2 +- include/srsran/scheduler/result/vrb_alloc.h | 2 +- include/srsran/sdap/sdap_config.h | 6 +- include/srsran/security/security.h | 188 +- include/srsran/security/security_engine.h | 2 +- .../srsran/srslog/detail/log_entry_metadata.h | 2 +- include/srsran/srslog/formatter.h | 7 +- include/srsran/srslog/logger.h | 1 + .../srsran/support/async/async_procedure.h | 1 + include/srsran/support/bit_encoding.h | 4 +- include/srsran/support/cpu_features.h | 13 +- include/srsran/support/error_handling.h | 12 +- .../support/executors/priority_task_worker.h | 2 +- .../support/format/custom_formattable.h | 16 +- .../support/format/delimited_formatter.h | 23 +- include/srsran/support/format/fmt_optional.h | 37 - .../srsran/support/format/prefixed_logger.h | 2 +- include/srsran/support/io/sctp_socket.h | 4 +- include/srsran/support/io/sockets.h | 2 +- .../support/io/transport_layer_address.h | 3 +- include/srsran/support/math/math_utils.h | 1 + include/srsran/support/srsran_assert.h | 49 +- include/srsran/support/srsran_test.h | 8 +- include/srsran/support/test_utils.h | 3 +- .../srsran/support/tracing/resource_usage.h | 4 +- include/srsran/support/units.h | 4 +- lib/asn1/asn1_utils.cpp | 22 +- .../cell_meas_manager_impl.cpp | 5 +- .../du_processor/du_configuration_manager.cpp | 11 +- lib/cu_cp/log_format.h | 2 +- lib/cu_cp/ngap_repository.cpp | 2 +- lib/cu_cp/ue_manager/ue_manager_impl.cpp | 12 +- .../ue_security_manager_impl.cpp | 5 +- .../up_resource_manager_helpers.cpp | 3 +- lib/cu_up/adapters/e1ap_adapters.h | 8 +- lib/cu_up/cu_up_manager_impl.cpp | 3 +- lib/cu_up/cu_up_ue_logger.h | 7 +- lib/cu_up/ue_context.h | 3 +- lib/cu_up/ue_manager.cpp | 11 +- lib/du/du_cell_config_validation.cpp | 82 +- lib/du/du_high/du_high_executor_mapper.cpp | 2 +- .../asn1_csi_meas_config_helpers.cpp | 29 +- .../converters/asn1_rrc_config_helpers.cpp | 105 +- .../converters/f1ap_configuration_helpers.cpp | 2 +- lib/du/du_high/du_manager/du_cell_manager.cpp | 6 +- lib/du/du_high/du_manager/du_cell_manager.h | 2 +- lib/du/du_high/du_manager/du_manager_impl.cpp | 2 +- lib/du/du_high/du_manager/du_ue/du_bearer.cpp | 9 +- .../du_ue/du_ue_controller_impl.cpp | 29 +- .../du_manager/du_ue/du_ue_manager.cpp | 32 +- .../procedures/initial_du_setup_procedure.cpp | 4 +- .../du_manager/procedures/procedure_logger.h | 16 +- .../procedures/ue_configuration_procedure.cpp | 4 +- .../du_ran_resource_manager_impl.cpp | 5 +- .../ue_capability_manager.cpp | 2 +- lib/e1ap/common/e1ap_asn1_converters.h | 18 +- lib/e1ap/common/log_helpers.cpp | 3 +- lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp | 4 +- .../ue_context/e1ap_cu_cp_ue_context.cpp | 9 +- .../cu_cp/ue_context/e1ap_cu_cp_ue_context.h | 17 +- lib/e1ap/cu_cp/ue_context/e1ap_ue_ids.h | 8 +- lib/e1ap/cu_cp/ue_context/e1ap_ue_logger.h | 18 +- lib/e1ap/cu_up/e1ap_cu_up_impl.cpp | 3 +- .../bearer_context_release_procedure.cpp | 2 +- .../cu_up/ue_context/e1ap_cu_up_ue_context.h | 34 +- lib/e1ap/cu_up/ue_context/e1ap_ue_logger.h | 20 +- .../e2sm_kpm_du_meas_provider_impl.cpp | 2 +- lib/e2/e2sm/e2sm_kpm/e2sm_kpm_impl.cpp | 11 +- lib/f1ap/asn1_helpers.cpp | 2 +- lib/f1ap/cu_cp/f1ap_cu_impl.cpp | 17 +- .../cu_cp/ue_context/f1ap_cu_ue_context.h | 34 +- lib/f1ap/cu_cp/ue_context/f1ap_ue_logger.h | 2 +- lib/f1ap/du/f1ap_du_impl.cpp | 24 +- lib/f1ap/du/procedures/proc_logger.h | 4 +- lib/f1ap/du/ue_context/f1ap_du_ue_manager.h | 2 +- lib/f1ap/du/ue_context/f1ap_ue_context.h | 14 +- lib/f1ap/du/ue_context/f1c_du_bearer_impl.cpp | 6 +- lib/f1ap/log_helpers.cpp | 7 +- lib/f1ap/proc_logger.h | 6 +- .../local_connector/f1u_local_connector.cpp | 1 - lib/fapi/loggers/message_loggers.cpp | 157 +- .../message_bufferer_slot_gateway_impl.cpp | 5 +- ...ge_bufferer_slot_time_notifier_decorator.h | 2 + lib/fapi/validators/message_validators.cpp | 20 +- lib/fapi_adaptor/mac/messages/pucch.cpp | 2 +- lib/fapi_adaptor/phy/messages/pucch.cpp | 2 +- .../phy_to_fapi_results_event_translator.cpp | 2 +- lib/gtpu/gtpu_demux_impl.h | 2 +- lib/gtpu/gtpu_pdu.cpp | 4 +- lib/gtpu/gtpu_pdu.h | 16 +- lib/gtpu/gtpu_tunnel_logger.h | 7 +- lib/gtpu/gtpu_tunnel_ngu_rx_impl.h | 2 +- lib/mac/mac_ctrl/mac_controller.cpp | 9 +- lib/mac/mac_ctrl/proc_logger.h | 4 +- lib/mac/mac_dl/cell_dl_harq_buffer_pool.cpp | 4 +- lib/mac/mac_dl/cell_dl_harq_buffer_pool.h | 2 +- lib/mac/mac_dl/dl_sch_pdu_assembler.cpp | 64 +- lib/mac/mac_dl/mac_cell_processor.cpp | 26 +- lib/mac/mac_sched/rlf_detector.h | 13 +- .../mac_sched/srsran_scheduler_adapter.cpp | 14 +- lib/mac/mac_sched/uci_cell_decoder.cpp | 8 +- lib/mac/mac_ul/lcid_ul_sch.h | 2 +- lib/mac/mac_ul/mac_ul_processor.cpp | 21 +- lib/mac/mac_ul/mac_ul_sch_pdu.h | 10 +- lib/mac/mac_ul/mac_ul_ue_manager.cpp | 14 +- lib/mac/mac_ul/pdu_rx_handler.cpp | 25 +- lib/mac/rnti_value_table.h | 3 +- lib/ngap/log_helpers.cpp | 3 +- lib/ngap/ngap_asn1_converters.h | 2 +- lib/ngap/ngap_impl.cpp | 82 +- lib/ngap/ue_context/ngap_ue_context.h | 30 +- lib/ngap/ue_context/ngap_ue_logger.h | 9 +- .../ofh_uplane_message_decoder_impl.cpp | 2 +- lib/pdcp/pdcp_bearer_logger.h | 4 +- lib/pdcp/pdcp_entity_rx.cpp | 1 - lib/pdcp/pdcp_entity_rx.h | 2 +- lib/pdcp/pdcp_entity_tx.h | 3 +- lib/pdcp/pdcp_pdu.h | 10 +- .../polar/polar_decoder_impl.cpp | 2 +- .../modulation_mapper_lut_impl.cpp | 4 +- .../prach_detector_phy_validator_impl.cpp | 1 + .../pusch/logging_pusch_processor_decorator.h | 4 +- .../pusch/pusch_decoder_impl.cpp | 4 +- lib/phy/upper/processor_pool_helpers.h | 2 + lib/phy/upper/uplink_processor_impl.cpp | 2 +- lib/psup/psup_packing.cpp | 5 +- lib/radio/uhd/radio_uhd_exception_handler.h | 3 +- lib/ran/band_helper.cpp | 11 +- lib/ran/pdcch/dci_packing.cpp | 22 +- lib/ran/pdcch/search_space.cpp | 2 +- lib/ran/sch/tbs_calculator.cpp | 2 +- lib/ran/srs/srs_information.cpp | 2 +- lib/ran/ssb_gscn.cpp | 14 +- lib/rlc/rlc_am_pdu.h | 14 +- lib/rlc/rlc_bearer_logger.h | 4 +- lib/rlc/rlc_retx_queue.h | 2 +- lib/rlc/rlc_rx_am_entity.cpp | 1 - lib/rlc/rlc_rx_am_entity.h | 4 +- lib/rlc/rlc_rx_um_entity.h | 4 +- lib/rlc/rlc_sdu_queue_lockfree.h | 4 +- lib/rlc/rlc_tx_am_entity.cpp | 4 +- lib/rlc/rlc_tx_am_entity.h | 2 +- lib/rlc/rlc_tx_um_entity.cpp | 4 +- lib/rlc/rlc_tx_um_entity.h | 2 +- lib/rlc/rlc_um_pdu.h | 2 +- lib/rrc/rrc_du_impl.cpp | 1 - .../rrc_ue_capability_transfer_procedure.cpp | 2 +- lib/rrc/ue/rrc_ue_logger.h | 5 +- .../ru_uplink_request_handler_generic_impl.h | 1 + .../ofh/ru_ofh_downlink_plane_handler_proxy.h | 2 + lib/ru/ofh/ru_ofh_factory.cpp | 4 +- .../ofh/ru_ofh_uplink_plane_handler_proxy.h | 2 + lib/scheduler/cell/cell_harq_manager.cpp | 25 +- lib/scheduler/cell/resource_grid.cpp | 4 +- lib/scheduler/cell/resource_grid.h | 4 +- lib/scheduler/cell_scheduler.cpp | 2 +- .../common_scheduling/ra_scheduler.cpp | 18 +- lib/scheduler/config/csi_helper.cpp | 2 +- lib/scheduler/config/sched_config_manager.cpp | 34 +- lib/scheduler/config/sched_config_manager.h | 2 +- .../scheduler_cell_config_validator.cpp | 6 +- .../config/serving_cell_config_validator.cpp | 37 +- lib/scheduler/config/ue_configuration.cpp | 5 +- lib/scheduler/config/ue_configuration.h | 11 +- .../logging/scheduler_event_logger.cpp | 112 +- .../logging/scheduler_metric_handler.cpp | 2 +- .../logging/scheduler_result_logger.cpp | 135 +- lib/scheduler/policy/scheduler_time_pf.cpp | 8 +- lib/scheduler/policy/scheduler_time_rr.cpp | 16 +- .../pucch_scheduling/pucch_allocator_impl.cpp | 40 +- lib/scheduler/scheduler_impl.cpp | 30 +- lib/scheduler/slicing/slice_scheduler.cpp | 6 +- lib/scheduler/slicing/slice_ue_repository.cpp | 11 +- lib/scheduler/srs/srs_scheduler_impl.cpp | 34 +- .../support/pdcch/search_space_helper.h | 4 +- .../pdcch_aggregation_level_calculator.cpp | 4 +- .../support/pusch/pusch_td_resource_indices.h | 1 + .../uci_scheduling/uci_scheduler_impl.cpp | 10 +- lib/scheduler/ue_context/ue.h | 8 +- lib/scheduler/ue_context/ue_cell.cpp | 7 +- .../ue_scheduling/ue_cell_grid_allocator.cpp | 93 +- .../ue_scheduling/ue_event_manager.cpp | 45 +- .../ue_scheduling/ue_fallback_scheduler.cpp | 40 +- lib/scheduler/ue_scheduling/ue_repository.cpp | 8 +- .../ue_scheduling/ue_scheduler_impl.cpp | 2 +- lib/sdap/sdap_session_logger.h | 11 +- lib/srslog/formatters/json_formatter.cpp | 52 +- lib/srslog/formatters/json_formatter.h | 1 + lib/srslog/formatters/text_formatter.cpp | 62 +- lib/srslog/sinks/file_utils.h | 2 +- lib/support/cpu_architecture_info.cpp | 15 +- lib/support/executors/unique_thread.cpp | 7 +- lib/support/sysinfo.cpp | 6 +- lib/support/timers.cpp | 6 +- lib/support/tracing/event_tracing.cpp | 8 +- .../benchmarks/du_high/du_high_benchmark.cpp | 14 +- .../ofh/ofh_compression_benchmark.cpp | 4 +- tests/benchmarks/pdcp/pdcp_rx_benchmark.cpp | 10 +- tests/benchmarks/pdcp/pdcp_tx_benchmark.cpp | 10 +- .../ldpc/ldpc_decoder_benchmark.cpp | 6 +- .../ldpc/ldpc_encoder_benchmark.cpp | 6 +- .../pdsch_encoder_hwacc_benchmark.cpp | 4 +- .../pdsch_processor_benchmark.cpp | 4 +- .../prach_detector_benchmark.cpp | 2 +- .../pucch/pucch_processor_benchmark.cpp | 19 +- .../pusch/pusch_decoder_hwacc_benchmark.cpp | 4 +- .../pusch/pusch_processor_benchmark.cpp | 4 +- .../srs_estimator_benchmark.cpp | 2 +- tests/benchmarks/rlc/rlc_am_rx_benchmark.cpp | 4 +- tests/benchmarks/rlc/rlc_am_tx_benchmark.cpp | 2 +- .../rlc/rlc_handle_status_report.cpp | 2 +- tests/integrationtests/ofh/helpers.h | 4 +- .../ofh/ofh_integration_test.cpp | 5 +- .../channel_processors/pxsch_bler_test.cpp | 8 +- tests/unittests/adt/interval_test.cpp | 8 +- tests/unittests/adt/span_formatter_test.cpp | 10 +- .../cu_cp/cu_cp_reestablishment_test.cpp | 2 +- .../cu_cp/cu_cp_test_environment.cpp | 2 +- .../cu_cp/cu_cp_ue_context_release_test.cpp | 2 +- .../du_srs_resource_manager_test.cpp | 4 + .../du_manager/du_ue/ue_manager_test.cpp | 2 +- .../pucch_resource_generator_test.cpp | 2 +- tests/unittests/e2/e2sm_kpm_test.cpp | 16 +- .../f1ap/du/f1ap_du_test_helpers.cpp | 4 +- tests/unittests/ngap/ngap_paging_test.cpp | 1 - tests/unittests/pdcp/pdcp_rx_metrics_test.cpp | 2 +- .../pdcp/pdcp_rx_reestablish_test.cpp | 2 +- .../pdcp/pdcp_rx_status_report_test.cpp | 2 +- tests/unittests/pdcp/pdcp_rx_test.cpp | 2 +- .../pdcp/pdcp_tx_empty_pool_test.cpp | 2 +- tests/unittests/pdcp/pdcp_tx_metrics_test.cpp | 2 +- .../pdcp/pdcp_tx_reestablish_test.cpp | 2 +- .../pdcp/pdcp_tx_status_report_test.cpp | 2 +- tests/unittests/pdcp/pdcp_tx_test.cpp | 2 +- tests/unittests/phy/lower/lower_phy_test.cpp | 6 +- .../ofdm_prach_demodulator_test.cpp | 4 + .../phy/support/resource_grid_test_doubles.h | 3 +- .../channel_coding/ldpc/ldpc_rm_test.cpp | 2 +- .../short/short_block_detector_test.cpp | 2 +- .../short/short_block_encoder_test.cpp | 4 +- .../pdsch/pdsch_encoder_test.cpp | 2 +- .../pucch/pucch_demodulator_format3_test.cpp | 1 - .../pucch/pucch_demodulator_format4_test.cpp | 1 - ...pucch_processor_validator_format4_test.cpp | 3 +- .../pusch/pusch_decoder_vectortest.cpp | 2 +- .../pusch/pusch_processor_validator_test.cpp | 1 - .../pusch/ulsch_demultiplex_test.cpp | 4 + .../uci/uci_decoder_test.cpp | 4 +- .../upper/channel_state_information_test.cpp | 4 +- .../phy/upper/log_likelihood_ratio_test.cpp | 2 +- .../dmrs_pucch_estimator_test.cpp | 18 +- .../dmrs_pusch_estimator_test.cpp | 7 + .../radio/zmq/radio_zmq_loopback_test.cpp | 2 +- .../radio/zmq/radio_zmq_validator_test.cpp | 6 +- .../ran/pdcch/dci_packing_validator_test.cpp | 19 +- tests/unittests/ran/pucch/pucch_info_test.cpp | 4 + .../ran/pusch/pusch_tpmi_select_test.cpp | 5 +- tests/unittests/ran/pusch/ulsch_info_test.cpp | 2 +- tests/unittests/rlc/rlc_tx_am_test.cpp | 2 +- tests/unittests/rlc/rlc_um_test.cpp | 2 +- .../cell/cell_resource_grid_test.cpp | 4 +- .../common_scheduling/sib1_scheduler_test.cpp | 7 +- .../common_scheduling/ssb_scheduler_test.cpp | 14 +- .../scheduler/multiple_ue_sched_test.cpp | 38 +- .../pdcch/pdcch_resource_allocator_test.cpp | 22 +- .../scheduler_ue_fallback_mode_test.cpp | 7 +- .../scheduler/support/dmrs_helpers_test.cpp | 2 +- ...dcch_aggregation_level_calculator_test.cpp | 2 +- .../pusch/pusch_td_resource_indices_test.cpp | 1 + .../test_utils/dummy_test_components.h | 3 +- .../test_utils/result_test_helpers.h | 2 +- .../test_utils/scheduler_test_simulator.cpp | 2 +- .../test_utils/scheduler_test_suite.cpp | 2 +- .../ue_scheduling/fallback_scheduler_test.cpp | 15 +- .../ue_scheduling/ue_configuration_test.cpp | 8 +- .../security/ciphering_engine_test.cpp | 2 +- .../security/integrity_engine_test.cpp | 2 +- .../srslog/benchmarks/frontend_latency.cpp | 1 + tests/unittests/support/timer_test.cpp | 1 + .../unittests/support/unique_thread_test.cpp | 2 +- utils/trx_srsran/trx_srsran.cpp | 14 +- 409 files changed, 15746 insertions(+), 10167 deletions(-) rename external/fmt/include/fmt/{LICENSE.rst => LICENSE} (95%) create mode 100644 external/fmt/include/fmt/args.h create mode 100644 external/fmt/include/fmt/base.h delete mode 100644 external/fmt/include/fmt/locale.h delete mode 100644 external/fmt/include/fmt/posix.h create mode 100644 external/fmt/include/fmt/std.h create mode 100644 external/fmt/include/fmt/xchar.h delete mode 100644 include/srsran/support/format/fmt_optional.h diff --git a/COPYRIGHT b/COPYRIGHT index 3cc7d7e778..3698d7c838 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -16,22 +16,24 @@ Copyright: 2013-2017 Google Inc. License: MIT -Files: external/fmt/chrono.h +Files: external/fmt/args.h + external/fmt/base.h + external/fmt/chrono.h external/fmt/color.h external/fmt/compile.h external/fmt/core.h external/fmt/format.h external/fmt/format-inl.h external/fmt/LICENSE.rst - external/fmt/locale.h external/fmt/os.h external/fmt/ostream.h - external/fmt/posix.h external/fmt/printf.h external/fmt/ranges.h + external/fmt/std.h + external/fmt/xchar.h external/fmt/format.cc external/fmt/os.cc -Copyright: 2012-2020 Victor Zverovich +Copyright: 2012-2024 Victor Zverovich License: MIT @@ -91,13 +93,13 @@ License: BSD-2-clause (Simplified BSD) modification, are permitted provided that the following conditions are met: . - 1. Redistributions of source code must retain the above copyright notice, + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. . 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 520d25ceb9..b55a2f84fc 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -71,7 +71,7 @@ static constexpr unsigned MAX_CONFIG_FILES = 10; static void populate_cli11_generic_args(CLI::App& app) { fmt::memory_buffer buffer; - format_to(buffer, "srsRAN 5G CU version {} ({})", get_version(), get_build_hash()); + format_to(std::back_inserter(buffer), "srsRAN 5G CU version {} ({})", get_version(), get_build_hash()); app.set_version_flag("-v,--version", srsran::to_c_str(buffer)); app.set_config("-c,", config_file, "Read config from file", false)->expected(1, MAX_CONFIG_FILES); } diff --git a/apps/du/du.cpp b/apps/du/du.cpp index 0af849c710..5453c7b68f 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -63,7 +63,7 @@ static constexpr unsigned MAX_CONFIG_FILES = 10; static void populate_cli11_generic_args(CLI::App& app) { fmt::memory_buffer buffer; - format_to(buffer, "srsRAN 5G DU version {} ({})", get_version(), get_build_hash()); + format_to(std::back_inserter(buffer), "srsRAN 5G DU version {} ({})", get_version(), get_build_hash()); app.set_version_flag("-v,--version", srsran::to_c_str(buffer)); app.set_config("-c,", config_file, "Read config from file", false)->expected(1, MAX_CONFIG_FILES); } diff --git a/apps/examples/ofh/ru_emulator.cpp b/apps/examples/ofh/ru_emulator.cpp index 959dc5553e..41dba2fcb5 100644 --- a/apps/examples/ofh/ru_emulator.cpp +++ b/apps/examples/ofh/ru_emulator.cpp @@ -339,7 +339,7 @@ static bool decode_rx_message(rx_message_info& message_info, span // Decode and check the filter index in the byte 26, bits 0-3. auto filter_index = static_cast(packet[22] & 0x0f); if (filter_index != filter_index_type::standard_channel_filter && !is_a_prach_message(filter_index)) { - logger.warning("Packet is corrupt: unknown filter index = {} decoded", filter_index); + logger.warning("Packet is corrupt: unknown filter index = {} decoded", fmt::underlying(filter_index)); return false; } message_info.filter_index = filter_index; @@ -489,7 +489,7 @@ class ru_emulator : public frame_notifier uint64_t malformed = corrupt_counter.calculate_acc_value(); uint64_t dropped = dropped_counter.calculate_acc_value(); - fmt::format_to(buffer, + fmt::format_to(std::back_inserter(buffer), "| {:%H:%M:%S} | {:^3} | {:^11} | {:^11} | {:^11} | {:^11} | {:^15} | {:^13} | {:^13} | {:^13} | " "{:^15} | {:^14} | {:^14} | {:^14} | {:^15} | {:^15} | {:^11} | {:^11} | {:^11} |\n", current_time, @@ -585,7 +585,10 @@ class ru_emulator : public frame_notifier { fmt::memory_buffer stats_format_buf; for (unsigned i = 0, e = eaxc.size(); i != e; ++i) { - fmt::format_to(stats_format_buf, "{}{}", seq_id_checker.calculate_statistics(eaxc[i]), (i == e - 1) ? "" : "/"); + fmt::format_to(std::back_inserter(stats_format_buf), + "{}{}", + seq_id_checker.calculate_statistics(eaxc[i]), + (i == e - 1) ? "" : "/"); } return to_string(stats_format_buf); } diff --git a/apps/examples/phy/radio_ssb.cpp b/apps/examples/phy/radio_ssb.cpp index 0591e278ec..499c93e05f 100644 --- a/apps/examples/phy/radio_ssb.cpp +++ b/apps/examples/phy/radio_ssb.cpp @@ -64,7 +64,7 @@ static srslog::basic_levels log_level = srslog::basic_levels::warning; /// Program parameters. static subcarrier_spacing scs = subcarrier_spacing::kHz15; static unsigned max_processing_delay_slots = 4; -static cyclic_prefix cp = cyclic_prefix::NORMAL; +static cyclic_prefix cy_prefix = cyclic_prefix::NORMAL; static double dl_center_freq = 3489.42e6; static double ssb_center_freq = 3488.16e6; static double tx_gain = 60.0; @@ -205,7 +205,7 @@ static const auto profiles = to_array({ // parallel execution. for (unsigned channel_id = 0; channel_id != nof_ports * nof_sectors; ++channel_id) { fmt::memory_buffer buffer; - fmt::format_to(buffer, "inproc://{}#{}", getpid(), channel_id); + fmt::format_to(std::back_inserter(buffer), "inproc://{}#{}", getpid(), channel_id); tx_channel_args.emplace_back(to_string(buffer)); rx_channel_args.emplace_back(to_string(buffer)); } @@ -238,7 +238,7 @@ static const auto profiles = to_array({ // parallel execution. for (unsigned channel_id = 0; channel_id != nof_ports * nof_sectors; ++channel_id) { fmt::memory_buffer buffer; - fmt::format_to(buffer, "inproc://{}#{}", getpid(), channel_id); + fmt::format_to(std::back_inserter(buffer), "inproc://{}#{}", getpid(), channel_id); tx_channel_args.emplace_back(to_string(buffer)); rx_channel_args.emplace_back(to_string(buffer)); } @@ -297,7 +297,7 @@ static void usage(std::string_view prog) fmt::print("\t-T Set thread profile (single, dual, quad). [Default {}]\n", thread_profile_name); fmt::print("\t-C Set clock source (internal, external, gpsdo). [Default {}]\n", clock_source); fmt::print("\t-S Set sync source (internal, external, gpsdo). [Default {}]\n", sync_source); - fmt::print("\t-v Logging level. [Default {}]\n", log_level); + fmt::print("\t-v Logging level. [Default {}]\n", fmt::underlying(log_level)); fmt::print("\t-c Enable amplitude clipping. [Default {}]\n", enable_clipping); fmt::print("\t-b Baseband gain back-off prior to clipping (in dB). [Default {}]\n", baseband_backoff_dB); fmt::print("\t-d Fill the resource grid with random data [Default {}]\n", enable_random_data); @@ -463,7 +463,7 @@ lower_phy_configuration create_lower_phy_configuration(task_executor* phy_config.time_alignment_calibration = 0; phy_config.system_time_throttling = 0.0F; phy_config.ta_offset = n_ta_offset::n0; - phy_config.cp = cp; + phy_config.cp = cy_prefix; phy_config.dft_window_offset = 0.5F; phy_config.bb_gateway = &bb_gateway; phy_config.rx_symbol_notifier = rx_symbol_notifier; @@ -518,9 +518,9 @@ int main(int argc, char** argv) // Make sure parameters are valid. report_fatal_error_if_not( srate.is_valid(scs), "Sampling rate ({}) must be multiple of {}kHz.", srate, scs_to_khz(scs)); - report_fatal_error_if_not(cp.is_valid(scs, srate.get_dft_size(scs)), + report_fatal_error_if_not(cy_prefix.is_valid(scs, srate.get_dft_size(scs)), "The cyclic prefix ({}) numerology ({}) and sampling rate ({}) combination is invalid .", - cp.to_string(), + cy_prefix.to_string(), to_numerology_value(scs), srate); diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index 88312027f9..8799271013 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -75,7 +75,7 @@ static constexpr unsigned MAX_CONFIG_FILES = 10; static void populate_cli11_generic_args(CLI::App& app) { fmt::memory_buffer buffer; - format_to(buffer, "srsRAN 5G gNB version {} ({})", get_version(), get_build_hash()); + format_to(std::back_inserter(buffer), "srsRAN 5G gNB version {} ({})", get_version(), get_build_hash()); app.set_version_flag("-v,--version", srsran::to_c_str(buffer)); app.set_config("-c,", config_file, "Read config from file", false)->expected(1, MAX_CONFIG_FILES); } diff --git a/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp b/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp index cecf4cfadf..3de145ca4b 100644 --- a/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp +++ b/apps/services/worker_manager/cli11_cpu_affinities_parser_helper.cpp @@ -29,9 +29,10 @@ static expected parse_int(const std::string& value) 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()); + std::string error_message = + fmt::format("Invalid CPU core selected '{}'. Valid CPU ids: {}", + cpu_idx, + span(os_sched_affinity_bitmask::available_cpus().get_cpu_ids())); os_sched_affinity_bitmask one_cpu_mask; if (cpu_idx >= one_cpu_mask.size()) { diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index 82655af1f6..5f871fb14b 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -47,11 +47,11 @@ static std::function get_vector_default_function(spancsi_report_cfg_list[0].cqi_table = cqi_table_t::table3; break; default: - report_error("Invalid MCS table={} for cell with pci={}\n", cell_cfg.pdsch_cfg.mcs_table, cell_cfg.pci); + report_error( + "Invalid MCS table={} for cell with pci={}\n", fmt::underlying(cell_cfg.pdsch_cfg.mcs_table), cell_cfg.pci); } // Generate zp-CSI-RS resources. diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp index 8839fc67ca..c235bc3cf5 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_validator.cpp @@ -17,7 +17,6 @@ #include "srsran/ran/pucch/pucch_info.h" #include "srsran/ran/transform_precoding/transform_precoding_helpers.h" #include "srsran/rlc/rlc_config.h" -#include "srsran/support/format/fmt_optional.h" #include using namespace srsran; @@ -211,7 +210,7 @@ static bool validate_pdcch_unit_config(const du_high_unit_base_cell_config& base "cell bandwidth={}Mhz\n", cs0_idx, ss0_idx, - base_cell.channel_bw_mhz); + fmt::underlying(base_cell.channel_bw_mhz)); return false; } // NOTE: The CORESET duration of 3 symbols is only permitted if the dmrs-typeA-Position information element has @@ -834,14 +833,16 @@ static bool validate_dl_ul_arfcn_and_band(const du_high_unit_base_cell_config& c // Obtain the minimum bandwidth for the subcarrier and band combination. min_channel_bandwidth min_chan_bw = band_helper::get_min_channel_bw(band, config.common_scs); if (min_chan_bw == min_channel_bandwidth::invalid) { - fmt::print("Invalid combination for band n{} and subcarrier spacing {}.\n", band, to_string(config.common_scs)); + fmt::print("Invalid combination for band n{} and subcarrier spacing {}.\n", + fmt::underlying(band), + to_string(config.common_scs)); return false; } // Check that the configured bandwidth is greater than or equal to the minimum bandwidth if (bs_channel_bandwidth_to_MHz(config.channel_bw_mhz) < min_channel_bandwidth_to_MHz(min_chan_bw)) { fmt::print("Minimum supported bandwidth for n{} with SCS {} is {}MHz.\n", - band, + fmt::underlying(band), to_string(config.common_scs), min_channel_bandwidth_to_MHz(min_chan_bw)); return false; @@ -852,7 +853,8 @@ static bool validate_dl_ul_arfcn_and_band(const du_high_unit_base_cell_config& c error_type ret = band_helper::is_dl_arfcn_valid_given_band( *config.band, config.dl_f_ref_arfcn, config.common_scs, config.channel_bw_mhz); if (not ret.has_value()) { - fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); + fmt::print( + "Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, fmt::underlying(band), ret.error()); return false; } // Check if also the corresponding UL ARFCN is valid. @@ -860,7 +862,8 @@ static bool validate_dl_ul_arfcn_and_band(const du_high_unit_base_cell_config& c ret = band_helper::is_ul_arfcn_valid_given_band(*config.band, ul_arfcn, config.channel_bw_mhz); if (not ret.has_value()) { // NOTE: The message must say that it's the DL ARFCN that is invalid, as that is the parameters set by the user. - fmt::print("Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, band, ret.error()); + fmt::print( + "Invalid DL ARFCN={} for band {}. Cause: {}.\n", config.dl_f_ref_arfcn, fmt::underlying(band), ret.error()); return false; } } else { diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_consumers.cpp index d432be6e11..1b5575cfa6 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_consumers.cpp @@ -103,7 +103,7 @@ void rlc_metrics_consumer_json::handle_metric(const app_services::metrics_set& m auto& output = ctx.get().back(); output.write(static_cast(drb.du_index)); - output.write(drb.ue_index); + output.write(static_cast(drb.ue_index)); output.write(static_cast(drb.rb_id.get_drb_id())); // TX metrics @@ -144,13 +144,13 @@ void rlc_metrics_consumer_log::handle_metric(const app_services::metrics_set& me const rlc_metrics& drb = static_cast(metric).get_metrics(); fmt::memory_buffer buffer; - fmt::format_to(buffer, "RLC Metrics:"); - fmt::format_to(buffer, " du={}", static_cast(drb.du_index)); - fmt::format_to(buffer, " ue={}", drb.ue_index); - fmt::format_to(buffer, " rb={}", drb.rb_id); - fmt::format_to(buffer, " mode={}", drb.rx.mode); - fmt::format_to(buffer, " TX=[{}]", format_rlc_tx_metrics(drb.metrics_period, drb.tx)); - fmt::format_to(buffer, " RX=[{}] ", format_rlc_rx_metrics(drb.metrics_period, drb.rx)); + fmt::format_to(std::back_inserter(buffer), "RLC Metrics:"); + fmt::format_to(std::back_inserter(buffer), " du={}", static_cast(drb.du_index)); + fmt::format_to(std::back_inserter(buffer), " ue={}", static_cast(drb.ue_index)); + fmt::format_to(std::back_inserter(buffer), " rb={}", drb.rb_id); + fmt::format_to(std::back_inserter(buffer), " mode={}", drb.rx.mode); + fmt::format_to(std::back_inserter(buffer), " TX=[{}]", format_rlc_tx_metrics(drb.metrics_period, drb.tx)); + fmt::format_to(std::back_inserter(buffer), " RX=[{}] ", format_rlc_rx_metrics(drb.metrics_period, drb.rx)); logger.info("{}", to_c_str(buffer)); } diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp index 38655a05fd..a24419d828 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.cpp @@ -12,8 +12,8 @@ #include "du_high_rlc_metrics.h" #include "srsran/scheduler/scheduler_metrics.h" #include "srsran/support/engineering_notation.h" -#include "srsran/support/math/math_utils.h" -#include +#include "fmt/ranges.h" +#include "fmt/std.h" #include using namespace srsran; @@ -307,9 +307,9 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr } // log cell-wide metrics - fmt::format_to(buffer, "Cell Scheduler Metrics:"); + fmt::format_to(std::back_inserter(buffer), "Cell Scheduler Metrics:"); fmt::format_to( - buffer, + std::back_inserter(buffer), " total_dl_brate={}bps total_ul_brate={}bps nof_prbs={} nof_dl_slots={} nof_ul_slots={} error_indications={} " "mean_latency={}usec latency_hist=[{}]", float_to_eng_string(sum_dl_bitrate_kbps * 1e3, 1, false), @@ -321,10 +321,10 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr metrics.average_decision_latency.count(), fmt::join(metrics.latency_histogram.begin(), metrics.latency_histogram.end(), ", ")); if (not metrics.events.empty()) { - fmt::format_to(buffer, " events=["); + fmt::format_to(std::back_inserter(buffer), " events=["); bool first = true; for (const auto& event : metrics.events) { - fmt::format_to(buffer, + fmt::format_to(std::back_inserter(buffer), "{}{{rnti={} slot={} type={}}}", first ? "" : ", ", event.rnti, @@ -332,101 +332,109 @@ void scheduler_cell_metrics_consumer_log::handle_metric(const app_services::metr event_to_string(event.type)); first = false; } - fmt::format_to(buffer, "]"); + fmt::format_to(std::back_inserter(buffer), "]"); } logger.info("{}", to_c_str(buffer)); buffer.clear(); // log ue-specific metrics for (const auto& ue : metrics.ue_metrics) { - fmt::format_to(buffer, "Scheduler UE Metrics:"); - fmt::format_to(buffer, " pci={}", ue.pci); - fmt::format_to(buffer, " rnti={:x}", to_value(ue.rnti)); + fmt::format_to(std::back_inserter(buffer), "Scheduler UE Metrics:"); + fmt::format_to(std::back_inserter(buffer), " pci={}", ue.pci); + fmt::format_to(std::back_inserter(buffer), " rnti={:x}", to_value(ue.rnti)); if (ue.cqi_stats.get_nof_observations() > 0) { - fmt::format_to(buffer, " cqi={}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); + fmt::format_to( + std::back_inserter(buffer), " cqi={}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); } else { - fmt::format_to(buffer, " cqi=n/a"); + fmt::format_to(std::back_inserter(buffer), " cqi=n/a"); } if (ue.ri_stats.get_nof_observations() > 0) { - fmt::format_to(buffer, " ri={:.1f}", ue.ri_stats.get_mean()); + fmt::format_to(std::back_inserter(buffer), " ri={:.1f}", ue.ri_stats.get_mean()); } else { - fmt::format_to(buffer, " ri=n/a"); + fmt::format_to(std::back_inserter(buffer), " ri=n/a"); } - fmt::format_to(buffer, " dl_mcs={}", int(ue.dl_mcs.to_uint())); + fmt::format_to(std::back_inserter(buffer), " dl_mcs={}", int(ue.dl_mcs.to_uint())); if (ue.dl_brate_kbps > 0) { - fmt::format_to(buffer, " dl_brate={}bps", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, false)); + fmt::format_to( + std::back_inserter(buffer), " dl_brate={}bps", float_to_eng_string(ue.dl_brate_kbps * 1e3, 1, false)); } else { - fmt::format_to(buffer, " dl_brate={}bps", 0); + fmt::format_to(std::back_inserter(buffer), " dl_brate={}bps", 0); } - fmt::format_to(buffer, " dl_nof_ok={}", ue.dl_nof_ok); - fmt::format_to(buffer, " dl_nof_nok={}", ue.dl_nof_nok); + fmt::format_to(std::back_inserter(buffer), " dl_nof_ok={}", ue.dl_nof_ok); + fmt::format_to(std::back_inserter(buffer), " dl_nof_nok={}", ue.dl_nof_nok); unsigned dl_total = ue.dl_nof_ok + ue.dl_nof_nok; - fmt::format_to(buffer, " dl_error_rate={}%", dl_total > 0 ? to_percentage(ue.dl_nof_nok, dl_total) : 0); - fmt::format_to(buffer, " dl_bs={}", scaled_fmt_integer(ue.dl_bs, false)); - fmt::format_to(buffer, " dl_nof_prbs={}", ue.tot_dl_prbs_used); + fmt::format_to(std::back_inserter(buffer), + " dl_error_rate={}%", + dl_total > 0 ? to_percentage(ue.dl_nof_nok, dl_total) : 0); + fmt::format_to(std::back_inserter(buffer), " dl_bs={}", scaled_fmt_integer(ue.dl_bs, false)); + fmt::format_to(std::back_inserter(buffer), " dl_nof_prbs={}", ue.tot_dl_prbs_used); if (ue.last_dl_olla.has_value()) { - fmt::format_to(buffer, " dl_olla={}", ue.last_dl_olla); + fmt::format_to(std::back_inserter(buffer), " dl_olla={}", ue.last_dl_olla); } if (!std::isnan(ue.pusch_snr_db) && !iszero(ue.pusch_snr_db)) { - fmt::format_to(buffer, " pusch_snr_db={:.1f}", std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); + fmt::format_to(std::back_inserter(buffer), " pusch_snr_db={:.1f}", std::clamp(ue.pusch_snr_db, -99.9f, 99.9f)); } else { - fmt::format_to(buffer, " pusch_snr_db=n/a"); + fmt::format_to(std::back_inserter(buffer), " pusch_snr_db=n/a"); } if (!std::isinf(ue.pusch_rsrp_db) && !std::isnan(ue.pusch_rsrp_db)) { if (ue.pusch_rsrp_db >= 0.0F) { - fmt::format_to(buffer, " pusch_rsrp_db=ovl"); + fmt::format_to(std::back_inserter(buffer), " pusch_rsrp_db=ovl"); } else { - fmt::format_to(buffer, " pusch_rsrp_db={:.1f}", std::clamp(ue.pusch_rsrp_db, -99.9F, 0.0F)); + fmt::format_to(std::back_inserter(buffer), " pusch_rsrp_db={:.1f}", std::clamp(ue.pusch_rsrp_db, -99.9F, 0.0F)); } } else { - fmt::format_to(buffer, " pusch_rsrp_db=n/a"); + fmt::format_to(std::back_inserter(buffer), " pusch_rsrp_db=n/a"); } - fmt::format_to(buffer, " ul_mcs={}", ue.ul_mcs.to_uint()); + fmt::format_to(std::back_inserter(buffer), " ul_mcs={}", ue.ul_mcs.to_uint()); if (ue.ul_brate_kbps > 0) { - fmt::format_to(buffer, " ul_brate={}bps", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, false)); + fmt::format_to( + std::back_inserter(buffer), " ul_brate={}bps", float_to_eng_string(ue.ul_brate_kbps * 1e3, 1, false)); } else { - fmt::format_to(buffer, " ul_brate={}bps", 0); + fmt::format_to(std::back_inserter(buffer), " ul_brate={}bps", 0); } - fmt::format_to(buffer, " ul_nof_ok={}", ue.ul_nof_ok); - fmt::format_to(buffer, " ul_nof_nok={}", ue.ul_nof_nok); + fmt::format_to(std::back_inserter(buffer), " ul_nof_ok={}", ue.ul_nof_ok); + fmt::format_to(std::back_inserter(buffer), " ul_nof_nok={}", ue.ul_nof_nok); unsigned ul_total = ue.ul_nof_ok + ue.ul_nof_nok; - fmt::format_to(buffer, " ul_error_rate={}%", ul_total > 0 ? to_percentage(ue.ul_nof_nok, ul_total) : 0); + fmt::format_to(std::back_inserter(buffer), + " ul_error_rate={}%", + ul_total > 0 ? to_percentage(ue.ul_nof_nok, ul_total) : 0); if (ul_total > 0) { - fmt::format_to(buffer, " crc_delay_ms={:.3}", ue.ul_delay_ms); + fmt::format_to(std::back_inserter(buffer), " crc_delay_ms={:.3}", ue.ul_delay_ms); } else { - fmt::format_to(buffer, " crc_delay_ms=n/a"); + fmt::format_to(std::back_inserter(buffer), " crc_delay_ms=n/a"); } - fmt::format_to(buffer, " ul_nof_prbs={}", ue.tot_ul_prbs_used); - fmt::format_to(buffer, " bsr={}", scaled_fmt_integer(ue.bsr, false)); - fmt::format_to(buffer, " sr_count={}", ue.sr_count); + fmt::format_to(std::back_inserter(buffer), " ul_nof_prbs={}", ue.tot_ul_prbs_used); + fmt::format_to(std::back_inserter(buffer), " bsr={}", scaled_fmt_integer(ue.bsr, false)); + fmt::format_to(std::back_inserter(buffer), " sr_count={}", ue.sr_count); if (ue.last_ul_olla.has_value()) { - fmt::format_to(buffer, " ul_olla={}", ue.last_ul_olla); + fmt::format_to(std::back_inserter(buffer), " ul_olla={}", ue.last_ul_olla); } if (ue.ta_stats.get_nof_observations() > 0) { - fmt::format_to(buffer, " ta={}s", float_to_eng_string(ue.ta_stats.get_mean(), 0, false)); + fmt::format_to(std::back_inserter(buffer), " ta={}s", float_to_eng_string(ue.ta_stats.get_mean(), 0, false)); } else { - fmt::format_to(buffer, " ta=n/a"); + fmt::format_to(std::back_inserter(buffer), " ta=n/a"); } if (ue.srs_ta_stats.get_nof_observations() > 0) { - fmt::format_to(buffer, " srs_ta={}s", float_to_eng_string(ue.srs_ta_stats.get_mean(), 0, false)); + fmt::format_to( + std::back_inserter(buffer), " srs_ta={}s", float_to_eng_string(ue.srs_ta_stats.get_mean(), 0, false)); } else { - fmt::format_to(buffer, " srs_ta=n/a"); + fmt::format_to(std::back_inserter(buffer), " srs_ta=n/a"); } if (ue.last_phr.has_value()) { - fmt::format_to(buffer, " last_phr={}", ue.last_phr.value()); + fmt::format_to(std::back_inserter(buffer), " last_phr={}", ue.last_phr.value()); } else { - fmt::format_to(buffer, " last_phr=n/a"); + fmt::format_to(std::back_inserter(buffer), " last_phr=n/a"); } if (ue.mean_ce_delay_msec.has_value()) { - fmt::format_to(buffer, " ul_ce_delay={:.2}ms", ue.mean_ce_delay_msec.value()); + fmt::format_to(std::back_inserter(buffer), " ul_ce_delay={:.2}ms", ue.mean_ce_delay_msec.value()); } else { - fmt::format_to(buffer, " ul_ce_delay=n/a"); + fmt::format_to(std::back_inserter(buffer), " ul_ce_delay=n/a"); } logger.info("{}", to_c_str(buffer)); diff --git a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp index 5c44e6e364..7b9fbbc105 100644 --- a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp +++ b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp @@ -53,7 +53,7 @@ void srsran::announce_du_high_cells(const du_high_unit_config& du_high_unit_cfg) "SSB derived parameters for cell: {}, band: {}, dl_arfcn:{}, nof_crbs: {} scs:{}, ssb_scs:{}:\n\t - SSB offset " "pointA:{} \n\t - k_SSB:{} \n\t - SSB arfcn:{} \n\t - Coreset index:{} \n\t - Searchspace index:{}", cell.pci, - cell.dl_carrier.band, + fmt::underlying(cell.dl_carrier.band), cell.dl_carrier.arfcn_f_ref, cell.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(), to_string(cell.dl_cfg_common.init_dl_bwp.generic_params.scs), @@ -197,7 +197,7 @@ o_du_high_unit srsran::make_o_du_high_unit(const o_du_high_unit_config& o_du_hi // DU-high configuration. du_hi_cfg.ran.gnb_du_id = du_high_unit_cfg.gnb_du_id; - du_hi_cfg.ran.gnb_du_name = fmt::format("srsdu{}", du_hi_cfg.ran.gnb_du_id); + du_hi_cfg.ran.gnb_du_name = fmt::format("srsdu{}", fmt::underlying(du_hi_cfg.ran.gnb_du_id)); du_hi_cfg.ran.cells = generate_du_cell_config(du_high_unit_cfg); // Validates the derived parameters. validates_derived_du_params(du_hi_cfg.ran.cells); diff --git a/apps/units/flexible_o_du/split_8/helpers/ru_sdr_config_translator.cpp b/apps/units/flexible_o_du/split_8/helpers/ru_sdr_config_translator.cpp index 9db6e2d989..1ef940fbb4 100644 --- a/apps/units/flexible_o_du/split_8/helpers/ru_sdr_config_translator.cpp +++ b/apps/units/flexible_o_du/split_8/helpers/ru_sdr_config_translator.cpp @@ -15,14 +15,14 @@ using namespace srsran; -/// Static configuration that the gnb supports. -static constexpr cyclic_prefix cp = cyclic_prefix::NORMAL; - /// Fills the given low PHY configuration from the given gnb configuration. static lower_phy_configuration generate_low_phy_config(const srs_du::du_cell_config& config, const ru_sdr_unit_config& ru_cfg, unsigned max_processing_delay_slot) { + /// Static configuration that the gnb supports. + static constexpr cyclic_prefix cp = cyclic_prefix::NORMAL; + lower_phy_configuration out_cfg; out_cfg.scs = config.scs_common; diff --git a/external/fmt/include/fmt/LICENSE.rst b/external/fmt/include/fmt/LICENSE similarity index 95% rename from external/fmt/include/fmt/LICENSE.rst rename to external/fmt/include/fmt/LICENSE index f0ec3db4d2..1cd1ef9269 100644 --- a/external/fmt/include/fmt/LICENSE.rst +++ b/external/fmt/include/fmt/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012 - present, Victor Zverovich +Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/external/fmt/include/fmt/args.h b/external/fmt/include/fmt/args.h new file mode 100644 index 0000000000..31a60e8faf --- /dev/null +++ b/external/fmt/include/fmt/args.h @@ -0,0 +1,228 @@ +// Formatting library for C++ - dynamic argument lists +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_ARGS_H_ +#define FMT_ARGS_H_ + +#ifndef FMT_MODULE +# include // std::reference_wrapper +# include // std::unique_ptr +# include +#endif + +#include "format.h" // std_string_view + +FMT_BEGIN_NAMESPACE + +namespace detail { + +template struct is_reference_wrapper : std::false_type {}; +template +struct is_reference_wrapper> : std::true_type {}; + +template auto unwrap(const T& v) -> const T& { return v; } +template +auto unwrap(const std::reference_wrapper& v) -> const T& { + return static_cast(v); +} + +// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC +// 2022 (v17.10.0). +// +// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for +// templates it doesn't complain about inability to deduce single translation +// unit for placing vtable. So node is made a fake template. +template struct node { + virtual ~node() = default; + std::unique_ptr> next; +}; + +class dynamic_arg_list { + template struct typed_node : node<> { + T value; + + template + FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} + + template + FMT_CONSTEXPR typed_node(const basic_string_view& arg) + : value(arg.data(), arg.size()) {} + }; + + std::unique_ptr> head_; + + public: + template auto push(const Arg& arg) -> const T& { + auto new_node = std::unique_ptr>(new typed_node(arg)); + auto& value = new_node->value; + new_node->next = std::move(head_); + head_ = std::move(new_node); + return value; + } +}; +} // namespace detail + +/** + * A dynamic list of formatting arguments with storage. + * + * It can be implicitly converted into `fmt::basic_format_args` for passing + * into type-erased formatting functions such as `fmt::vformat`. + */ +template +class dynamic_format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + using char_type = typename Context::char_type; + + template struct need_copy { + static constexpr detail::type mapped_type = + detail::mapped_type_constant::value; + + enum { + value = !(detail::is_reference_wrapper::value || + std::is_same>::value || + std::is_same>::value || + (mapped_type != detail::type::cstring_type && + mapped_type != detail::type::string_type && + mapped_type != detail::type::custom_type)) + }; + }; + + template + using stored_type = conditional_t< + std::is_convertible>::value && + !detail::is_reference_wrapper::value, + std::basic_string, T>; + + // Storage of basic_format_arg must be contiguous. + std::vector> data_; + std::vector> named_info_; + + // Storage of arguments not fitting into basic_format_arg must grow + // without relocation because items in data_ refer to it. + detail::dynamic_arg_list dynamic_args_; + + friend class basic_format_args; + + auto get_types() const -> unsigned long long { + return detail::is_unpacked_bit | data_.size() | + (named_info_.empty() + ? 0ULL + : static_cast(detail::has_named_args_bit)); + } + + auto data() const -> const basic_format_arg* { + return named_info_.empty() ? data_.data() : data_.data() + 1; + } + + template void emplace_arg(const T& arg) { + data_.emplace_back(detail::make_arg(arg)); + } + + template + void emplace_arg(const detail::named_arg& arg) { + if (named_info_.empty()) { + constexpr const detail::named_arg_info* zero_ptr{nullptr}; + data_.insert(data_.begin(), {zero_ptr, 0}); + } + data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); + auto pop_one = [](std::vector>* data) { + data->pop_back(); + }; + std::unique_ptr>, decltype(pop_one)> + guard{&data_, pop_one}; + named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); + data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; + guard.release(); + } + + public: + constexpr dynamic_format_arg_store() = default; + + /** + * Adds an argument into the dynamic store for later passing to a formatting + * function. + * + * Note that custom types and string types (but not string views) are copied + * into the store dynamically allocating memory if necessary. + * + * **Example**: + * + * fmt::dynamic_format_arg_store store; + * store.push_back(42); + * store.push_back("abc"); + * store.push_back(1.5f); + * std::string result = fmt::vformat("{} and {} and {}", store); + */ + template void push_back(const T& arg) { + if (detail::const_check(need_copy::value)) + emplace_arg(dynamic_args_.push>(arg)); + else + emplace_arg(detail::unwrap(arg)); + } + + /** + * Adds a reference to the argument into the dynamic store for later passing + * to a formatting function. + * + * **Example**: + * + * fmt::dynamic_format_arg_store store; + * char band[] = "Rolling Stones"; + * store.push_back(std::cref(band)); + * band[9] = 'c'; // Changing str affects the output. + * std::string result = fmt::vformat("{}", store); + * // result == "Rolling Scones" + */ + template void push_back(std::reference_wrapper arg) { + static_assert( + need_copy::value, + "objects of built-in types and string views are always copied"); + emplace_arg(arg.get()); + } + + /** + * Adds named argument into the dynamic store for later passing to a + * formatting function. `std::reference_wrapper` is supported to avoid + * copying of the argument. The name is always copied into the store. + */ + template + void push_back(const detail::named_arg& arg) { + const char_type* arg_name = + dynamic_args_.push>(arg.name).c_str(); + if (detail::const_check(need_copy::value)) { + emplace_arg( + fmt::arg(arg_name, dynamic_args_.push>(arg.value))); + } else { + emplace_arg(fmt::arg(arg_name, arg.value)); + } + } + + /// Erase all elements from the store. + void clear() { + data_.clear(); + named_info_.clear(); + dynamic_args_ = detail::dynamic_arg_list(); + } + + /// Reserves space to store at least `new_cap` arguments including + /// `new_cap_named` named arguments. + void reserve(size_t new_cap, size_t new_cap_named) { + FMT_ASSERT(new_cap >= new_cap_named, + "Set of arguments includes set of named arguments"); + data_.reserve(new_cap); + named_info_.reserve(new_cap_named); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_ARGS_H_ diff --git a/external/fmt/include/fmt/base.h b/external/fmt/include/fmt/base.h new file mode 100644 index 0000000000..6276494253 --- /dev/null +++ b/external/fmt/include/fmt/base.h @@ -0,0 +1,3077 @@ +// Formatting library for C++ - the base API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_BASE_H_ +#define FMT_BASE_H_ + +#if defined(FMT_IMPORT_STD) && !defined(FMT_MODULE) +# define FMT_MODULE +#endif + +#ifndef FMT_MODULE +# include // CHAR_BIT +# include // FILE +# include // strlen + +// is also included transitively from . +# include // std::byte +# include // std::enable_if +#endif + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 110002 + +// Detect compiler versions. +#if defined(__clang__) && !defined(__ibmxl__) +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif +#if defined(__ICL) +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif +#if defined(_MSC_VER) +# define FMT_MSC_VERSION _MSC_VER +#else +# define FMT_MSC_VERSION 0 +#endif + +// Detect standard library versions. +#ifdef _GLIBCXX_RELEASE +# define FMT_GLIBCXX_RELEASE _GLIBCXX_RELEASE +#else +# define FMT_GLIBCXX_RELEASE 0 +#endif +#ifdef _LIBCPP_VERSION +# define FMT_LIBCPP_VERSION _LIBCPP_VERSION +#else +# define FMT_LIBCPP_VERSION 0 +#endif + +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + +// Detect __has_*. +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif +#ifdef __has_include +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +// Detect C++14 relaxed constexpr. +#ifdef FMT_USE_CONSTEXPR +// Use the provided definition. +#elif FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L +// GCC only allows throw in constexpr since version 6: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371. +# define FMT_USE_CONSTEXPR 1 +#elif FMT_ICC_VERSION +# define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628 +#elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 +# define FMT_USE_CONSTEXPR 1 +#else +# define FMT_USE_CONSTEXPR 0 +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +#else +# define FMT_CONSTEXPR +#endif + +// Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated. +#if !defined(__cpp_lib_is_constant_evaluated) +# define FMT_USE_CONSTEVAL 0 +#elif FMT_CPLUSPLUS < 201709L +# define FMT_USE_CONSTEVAL 0 +#elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10 +# define FMT_USE_CONSTEVAL 0 +#elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000 +# define FMT_USE_CONSTEVAL 0 +#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L +# define FMT_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14. +#elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929 +# define FMT_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10. +#elif defined(__cpp_consteval) +# define FMT_USE_CONSTEVAL 1 +#elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101 +# define FMT_USE_CONSTEVAL 1 +#else +# define FMT_USE_CONSTEVAL 0 +#endif +#if FMT_USE_CONSTEVAL +# define FMT_CONSTEVAL consteval +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEVAL +# define FMT_CONSTEXPR20 +#endif + +#if defined(FMT_USE_NONTYPE_TEMPLATE_ARGS) +// Use the provided definition. +#elif defined(__NVCOMPILER) +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +#elif FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#elif defined(__cpp_nontype_template_args) && \ + __cpp_nontype_template_args >= 201911L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#elif FMT_CLANG_VERSION >= 1200 && FMT_CPLUSPLUS >= 202002L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#else +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +#endif + +#ifdef FMT_USE_CONCEPTS +// Use the provided definition. +#elif defined(__cpp_concepts) +# define FMT_USE_CONCEPTS 1 +#else +# define FMT_USE_CONCEPTS 0 +#endif + +// Check if exceptions are disabled. +#ifdef FMT_EXCEPTIONS +// Use the provided definition. +#elif defined(__GNUC__) && !defined(__EXCEPTIONS) +# define FMT_EXCEPTIONS 0 +#elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#else +# define FMT_EXCEPTIONS 1 +#endif +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +# define FMT_FALLTHROUGH [[fallthrough]] +#elif defined(__clang__) +# define FMT_FALLTHROUGH [[clang::fallthrough]] +#elif FMT_GCC_VERSION >= 700 && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) +# define FMT_FALLTHROUGH [[gnu::fallthrough]] +#else +# define FMT_FALLTHROUGH +#endif + +// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings. +#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#ifndef FMT_NODISCARD +# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] +# else +# define FMT_NODISCARD +# endif +#endif + +#ifdef FMT_DEPRECATED +// Use the provided definition. +#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated) +# define FMT_DEPRECATED [[deprecated]] +#else +# define FMT_DEPRECATED /* deprecated */ +#endif + +#ifdef FMT_INLINE +// Use the provided definition. +#elif FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +# define FMT_ALWAYS_INLINE inline +#endif +// A version of FMT_INLINE to prevent code bloat in debug mode. +#ifdef NDEBUG +# define FMT_INLINE FMT_ALWAYS_INLINE +#else +# define FMT_INLINE inline +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_VISIBILITY(value) __attribute__((visibility(value))) +#else +# define FMT_VISIBILITY(value) +#endif + +#ifndef FMT_GCC_PRAGMA +// Workaround a _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884 +// and an nvhpc warning: https://github.com/fmtlib/fmt/pull/2582. +# if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER) +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +# else +# define FMT_GCC_PRAGMA(arg) +# endif +#endif + +// GCC < 5 requires this-> in decltype. +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +# define FMT_DECLTYPE_THIS this-> +#else +# define FMT_DECLTYPE_THIS +#endif + +#if FMT_MSC_VERSION +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +# define FMT_UNCHECKED_ITERATOR(It) \ + using _Unchecked_type = It // Mark iterator as checked. +#else +# define FMT_MSC_WARNING(...) +# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + inline namespace v11 { +# define FMT_END_NAMESPACE \ + } \ + } +#endif + +#ifndef FMT_EXPORT +# define FMT_EXPORT +# define FMT_BEGIN_EXPORT +# define FMT_END_EXPORT +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# if defined(FMT_LIB_EXPORT) +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_API FMT_VISIBILITY("default") +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifndef FMT_UNICODE +# define FMT_UNICODE 1 +#endif + +// Check if rtti is available. +#ifndef FMT_USE_RTTI +// __RTTI is for EDG compilers. _CPPRTTI is for MSVC. +# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \ + defined(__INTEL_RTTI__) || defined(__RTTI) +# define FMT_USE_RTTI 1 +# else +# define FMT_USE_RTTI 0 +# endif +#endif + +#define FMT_FWD(...) static_cast(__VA_ARGS__) + +// Enable minimal optimizations for more compact code in debug mode. +FMT_GCC_PRAGMA("GCC push_options") +#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) +FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +#endif + +FMT_BEGIN_NAMESPACE + +// Implementations of enable_if_t and other metafunctions for older systems. +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; +template using bool_constant = std::integral_constant; +template +using remove_reference_t = typename std::remove_reference::type; +template +using remove_const_t = typename std::remove_const::type; +template +using remove_cvref_t = typename std::remove_cv>::type; +template struct type_identity { + using type = T; +}; +template using type_identity_t = typename type_identity::type; +template +using make_unsigned_t = typename std::make_unsigned::type; +template +using underlying_t = typename std::underlying_type::type; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +// A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { + using type = void; +}; +template using void_t = typename void_t_impl::type; +#else +template using void_t = void; +#endif + +struct monostate { + constexpr monostate() {} +}; + +// An enable_if helper to be used in template parameters which results in much +// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +// to workaround a bug in MSVC 2019 (see #1140 and #1186). +#ifdef FMT_DOC +# define FMT_ENABLE_IF(...) +#else +# define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0 +#endif + +// This is defined in base.h instead of format.h to avoid injecting in std. +// It is a template to avoid undesirable implicit conversions to std::byte. +#ifdef __cpp_lib_byte +template ::value)> +inline auto format_as(T b) -> unsigned char { + return static_cast(b); +} +#endif + +namespace detail { +// Suppresses "unused variable" warnings with the method described in +// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +// (void)var does not work on many Intel compilers. +template FMT_CONSTEXPR void ignore_unused(const T&...) {} + +constexpr auto is_constant_evaluated(bool default_value = false) noexcept + -> bool { +// Workaround for incompatibility between libstdc++ consteval-based +// std::is_constant_evaluated() implementation and clang-14: +// https://github.com/fmtlib/fmt/issues/3247. +#if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \ + (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500) + ignore_unused(default_value); + return __builtin_is_constant_evaluated(); +#elif defined(__cpp_lib_is_constant_evaluated) + ignore_unused(default_value); + return std::is_constant_evaluated(); +#else + return default_value; +#endif +} + +// Suppresses "conditional expression is constant" warnings. +template constexpr auto const_check(T value) -> T { return value; } + +FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#if defined(FMT_ASSERT) +// Use the provided definition. +#elif defined(NDEBUG) +// FMT_ASSERT is not empty to avoid -Wempty-body. +# define FMT_ASSERT(condition, message) \ + fmt::detail::ignore_unused((condition), (message)) +#else +# define FMT_ASSERT(condition, message) \ + ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ + ? (void)0 \ + : fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +#endif + +#ifdef FMT_USE_INT128 +// Do nothing. +#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ + !(FMT_CLANG_VERSION && FMT_MSC_VERSION) +# define FMT_USE_INT128 1 +using int128_opt = __int128_t; // An optional native 128-bit integer. +using uint128_opt = __uint128_t; +template inline auto convert_for_visit(T value) -> T { + return value; +} +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 +enum class int128_opt {}; +enum class uint128_opt {}; +// Reduce template instantiations. +template auto convert_for_visit(T) -> monostate { return {}; } +#endif + +// Casts a nonnegative integer to unsigned. +template +FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t { + FMT_ASSERT(std::is_unsigned::value || value >= 0, "negative value"); + return static_cast>(value); +} + +// A heuristic to detect std::string and std::[experimental::]string_view. +// It is mainly used to avoid dependency on <[experimental/]string_view>. +template +struct is_std_string_like : std::false_type {}; +template +struct is_std_string_like().find_first_of( + typename T::value_type(), 0))>> + : std::is_convertible().data()), + const typename T::value_type*> {}; + +// Returns true iff the literal encoding is UTF-8. +constexpr auto is_utf8_enabled() -> bool { + // Avoid an MSVC sign extension bug: https://github.com/fmtlib/fmt/pull/2297. + using uchar = unsigned char; + return sizeof("\u00A7") == 3 && uchar("\u00A7"[0]) == 0xC2 && + uchar("\u00A7"[1]) == 0xA7; +} +constexpr auto use_utf8() -> bool { + return !FMT_MSC_VERSION || is_utf8_enabled(); +} + +static_assert(!FMT_UNICODE || use_utf8(), + "Unicode support requires compiling with /utf-8"); + +template FMT_CONSTEXPR auto length(const Char* s) -> size_t { + size_t len = 0; + while (*s++) ++len; + return len; +} + +template +FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n) + -> int { + if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n); + for (; n != 0; ++s1, ++s2, --n) { + if (*s1 < *s2) return -1; + if (*s1 > *s2) return 1; + } + return 0; +} + +namespace adl { +using namespace std; + +template +auto invoke_back_inserter() + -> decltype(back_inserter(std::declval())); +} // namespace adl + +template +struct is_back_insert_iterator : std::false_type {}; + +template +struct is_back_insert_iterator< + It, bool_constant()), + It>::value>> : std::true_type {}; + +// Extracts a reference to the container from *insert_iterator. +template +inline auto get_container(OutputIt it) -> typename OutputIt::container_type& { + struct accessor : OutputIt { + accessor(OutputIt base) : OutputIt(base) {} + using OutputIt::container; + }; + return *accessor(it).container; +} +} // namespace detail + +// Checks whether T is a container with contiguous storage. +template struct is_contiguous : std::false_type {}; + +/** + * An implementation of `std::basic_string_view` for pre-C++17. It provides a + * subset of the API. `fmt::basic_string_view` is used for format strings even + * if `std::basic_string_view` is available to prevent issues when a library is + * compiled with a different `-std` option than the client code (which is not + * recommended). + */ +FMT_EXPORT +template class basic_string_view { + private: + const Char* data_; + size_t size_; + + public: + using value_type = Char; + using iterator = const Char*; + + constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {} + + /// Constructs a string reference object from a C string and a size. + constexpr basic_string_view(const Char* s, size_t count) noexcept + : data_(s), size_(count) {} + + constexpr basic_string_view(std::nullptr_t) = delete; + + /// Constructs a string reference object from a C string. + FMT_CONSTEXPR20 + basic_string_view(const Char* s) + : data_(s), + size_(detail::const_check(std::is_same::value && + !detail::is_constant_evaluated(false)) + ? strlen(reinterpret_cast(s)) + : detail::length(s)) {} + + /// Constructs a string reference from a `std::basic_string` or a + /// `std::basic_string_view` object. + template ::value&& std::is_same< + typename S::value_type, Char>::value)> + FMT_CONSTEXPR basic_string_view(const S& s) noexcept + : data_(s.data()), size_(s.size()) {} + + /// Returns a pointer to the string data. + constexpr auto data() const noexcept -> const Char* { return data_; } + + /// Returns the string size. + constexpr auto size() const noexcept -> size_t { return size_; } + + constexpr auto begin() const noexcept -> iterator { return data_; } + constexpr auto end() const noexcept -> iterator { return data_ + size_; } + + constexpr auto operator[](size_t pos) const noexcept -> const Char& { + return data_[pos]; + } + + FMT_CONSTEXPR void remove_prefix(size_t n) noexcept { + data_ += n; + size_ -= n; + } + + FMT_CONSTEXPR auto starts_with(basic_string_view sv) const noexcept + -> bool { + return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0; + } + FMT_CONSTEXPR auto starts_with(Char c) const noexcept -> bool { + return size_ >= 1 && *data_ == c; + } + FMT_CONSTEXPR auto starts_with(const Char* s) const -> bool { + return starts_with(basic_string_view(s)); + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR auto compare(basic_string_view other) const -> int { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = detail::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + FMT_CONSTEXPR friend auto operator==(basic_string_view lhs, + basic_string_view rhs) -> bool { + return lhs.compare(rhs) == 0; + } + friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) != 0; + } + friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) < 0; + } + friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) <= 0; + } + friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) > 0; + } + friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) >= 0; + } +}; + +FMT_EXPORT +using string_view = basic_string_view; + +/// Specifies if `T` is a character type. Can be specialized by users. +FMT_EXPORT +template struct is_char : std::false_type {}; +template <> struct is_char : std::true_type {}; + +namespace detail { + +// Constructs fmt::basic_string_view from types implicitly convertible +// to it, deducing Char. Explicitly convertible types such as the ones returned +// from FMT_STRING are intentionally excluded. +template ::value)> +constexpr auto to_string_view(const Char* s) -> basic_string_view { + return s; +} +template ::value)> +constexpr auto to_string_view(const T& s) + -> basic_string_view { + return s; +} +template +constexpr auto to_string_view(basic_string_view s) + -> basic_string_view { + return s; +} + +template +struct has_to_string_view : std::false_type {}; +// detail:: is intentional since to_string_view is not an extension point. +template +struct has_to_string_view< + T, void_t()))>> + : std::true_type {}; + +template struct string_literal { + static constexpr Char value[sizeof...(C)] = {C...}; + constexpr operator basic_string_view() const { + return {value, sizeof...(C)}; + } +}; +#if FMT_CPLUSPLUS < 201703L +template +constexpr Char string_literal::value[sizeof...(C)]; +#endif + +enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type +}; + +// Maps core type T to the corresponding type enum constant. +template +struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + +FMT_TYPE_CONSTANT(int, int_type); +FMT_TYPE_CONSTANT(unsigned, uint_type); +FMT_TYPE_CONSTANT(long long, long_long_type); +FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +FMT_TYPE_CONSTANT(int128_opt, int128_type); +FMT_TYPE_CONSTANT(uint128_opt, uint128_type); +FMT_TYPE_CONSTANT(bool, bool_type); +FMT_TYPE_CONSTANT(Char, char_type); +FMT_TYPE_CONSTANT(float, float_type); +FMT_TYPE_CONSTANT(double, double_type); +FMT_TYPE_CONSTANT(long double, long_double_type); +FMT_TYPE_CONSTANT(const Char*, cstring_type); +FMT_TYPE_CONSTANT(basic_string_view, string_type); +FMT_TYPE_CONSTANT(const void*, pointer_type); + +constexpr auto is_integral_type(type t) -> bool { + return t > type::none_type && t <= type::last_integer_type; +} +constexpr auto is_arithmetic_type(type t) -> bool { + return t > type::none_type && t <= type::last_numeric_type; +} + +constexpr auto set(type rhs) -> int { return 1 << static_cast(rhs); } +constexpr auto in(type t, int set) -> bool { + return ((set >> static_cast(t)) & 1) != 0; +} + +// Bitsets of types. +enum { + sint_set = + set(type::int_type) | set(type::long_long_type) | set(type::int128_type), + uint_set = set(type::uint_type) | set(type::ulong_long_type) | + set(type::uint128_type), + bool_set = set(type::bool_type), + char_set = set(type::char_type), + float_set = set(type::float_type) | set(type::double_type) | + set(type::long_double_type), + string_set = set(type::string_type), + cstring_set = set(type::cstring_type), + pointer_set = set(type::pointer_type) +}; +} // namespace detail + +/// Reports a format error at compile time or, via a `format_error` exception, +/// at runtime. +// This function is intentionally not constexpr to give a compile-time error. +FMT_NORETURN FMT_API void report_error(const char* message); + +FMT_DEPRECATED FMT_NORETURN inline void throw_format_error( + const char* message) { + report_error(message); +} + +/// String's character (code unit) type. +template ()))> +using char_t = typename V::value_type; + +/** + * Parsing context consisting of a format string range being parsed and an + * argument counter for automatic indexing. + * You can use the `format_parse_context` type alias for `char` instead. + */ +FMT_EXPORT +template class basic_format_parse_context { + private: + basic_string_view format_str_; + int next_arg_id_; + + FMT_CONSTEXPR void do_check_arg_id(int id); + + public: + using char_type = Char; + using iterator = const Char*; + + explicit constexpr basic_format_parse_context( + basic_string_view format_str, int next_arg_id = 0) + : format_str_(format_str), next_arg_id_(next_arg_id) {} + + /// Returns an iterator to the beginning of the format string range being + /// parsed. + constexpr auto begin() const noexcept -> iterator { + return format_str_.begin(); + } + + /// Returns an iterator past the end of the format string range being parsed. + constexpr auto end() const noexcept -> iterator { return format_str_.end(); } + + /// Advances the begin iterator to `it`. + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(detail::to_unsigned(it - begin())); + } + + /// Reports an error if using the manual argument indexing; otherwise returns + /// the next argument index and switches to the automatic indexing. + FMT_CONSTEXPR auto next_arg_id() -> int { + if (next_arg_id_ < 0) { + report_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + int id = next_arg_id_++; + do_check_arg_id(id); + return id; + } + + /// Reports an error if using the automatic argument indexing; otherwise + /// switches to the manual indexing. + FMT_CONSTEXPR void check_arg_id(int id) { + if (next_arg_id_ > 0) { + report_error("cannot switch from automatic to manual argument indexing"); + return; + } + next_arg_id_ = -1; + do_check_arg_id(id); + } + FMT_CONSTEXPR void check_arg_id(basic_string_view) { + next_arg_id_ = -1; + } + FMT_CONSTEXPR void check_dynamic_spec(int arg_id); +}; + +FMT_EXPORT +using format_parse_context = basic_format_parse_context; + +namespace detail { +// A parse context with extra data used only in compile-time checks. +template +class compile_parse_context : public basic_format_parse_context { + private: + int num_args_; + const type* types_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, int num_args, const type* types, + int next_arg_id = 0) + : base(format_str, next_arg_id), num_args_(num_args), types_(types) {} + + constexpr auto num_args() const -> int { return num_args_; } + constexpr auto arg_type(int id) const -> type { return types_[id]; } + + FMT_CONSTEXPR auto next_arg_id() -> int { + int id = base::next_arg_id(); + if (id >= num_args_) report_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) report_error("argument not found"); + } + using base::check_arg_id; + + FMT_CONSTEXPR void check_dynamic_spec(int arg_id) { + detail::ignore_unused(arg_id); + if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) + report_error("width/precision is not integer"); + } +}; + +/// A contiguous memory buffer with an optional growing ability. It is an +/// internal class and shouldn't be used directly, only via `memory_buffer`. +template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + using grow_fun = void (*)(buffer& buf, size_t capacity); + grow_fun grow_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + FMT_CONSTEXPR20 buffer(grow_fun grow, size_t sz) noexcept + : size_(sz), capacity_(sz), grow_(grow) {} + + constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0, + size_t cap = 0) noexcept + : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {} + + FMT_CONSTEXPR20 ~buffer() = default; + buffer(buffer&&) = default; + + /// Sets the buffer data and capacity. + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + auto begin() noexcept -> T* { return ptr_; } + auto end() noexcept -> T* { return ptr_ + size_; } + + auto begin() const noexcept -> const T* { return ptr_; } + auto end() const noexcept -> const T* { return ptr_ + size_; } + + /// Returns the size of this buffer. + constexpr auto size() const noexcept -> size_t { return size_; } + + /// Returns the capacity of this buffer. + constexpr auto capacity() const noexcept -> size_t { return capacity_; } + + /// Returns a pointer to the buffer data (not null-terminated). + FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; } + FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } + + /// Clears this buffer. + void clear() { size_ = 0; } + + // Tries resizing the buffer to contain `count` elements. If T is a POD type + // the new elements may not be initialized. + FMT_CONSTEXPR void try_resize(size_t count) { + try_reserve(count); + size_ = count <= capacity_ ? count : capacity_; + } + + // Tries increasing the buffer capacity to `new_capacity`. It can increase the + // capacity by a smaller amount than requested but guarantees there is space + // for at least one additional element either by increasing the capacity or by + // flushing the buffer if it is full. + FMT_CONSTEXPR void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow_(*this, new_capacity); + } + + FMT_CONSTEXPR void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /// Appends data to the end of the buffer. + template void append(const U* begin, const U* end) { + while (begin != end) { + auto count = to_unsigned(end - begin); + try_reserve(size_ + count); + auto free_cap = capacity_ - size_; + if (free_cap < count) count = free_cap; + // A loop is faster than memcpy on small sizes. + T* out = ptr_ + size_; + for (size_t i = 0; i < count; ++i) out[i] = begin[i]; + size_ += count; + begin += count; + } + } + + template FMT_CONSTEXPR auto operator[](Idx index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](Idx index) const -> const T& { + return ptr_[index]; + } +}; + +struct buffer_traits { + explicit buffer_traits(size_t) {} + auto count() const -> size_t { return 0; } + auto limit(size_t size) -> size_t { return size; } +}; + +class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + auto count() const -> size_t { return count_; } + auto limit(size_t size) -> size_t { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return size < n ? size : n; + } +}; + +// A buffer that writes to an output iterator when flushed. +template +class iterator_buffer : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() == buffer_size) static_cast(buf).flush(); + } + + void flush() { + auto size = this->size(); + this->clear(); + const T* begin = data_; + const T* end = begin + this->limit(size); + while (begin != end) *out_++ = *begin++; + } + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(grow, data_, 0, buffer_size), out_(out) {} + iterator_buffer(iterator_buffer&& other) noexcept + : Traits(other), + buffer(grow, data_, 0, buffer_size), + out_(other.out_) {} + ~iterator_buffer() { + // Don't crash if flush fails during unwinding. + FMT_TRY { flush(); } + FMT_CATCH(...) {} + } + + auto out() -> OutputIt { + flush(); + return out_; + } + auto count() const -> size_t { return Traits::count() + this->size(); } +}; + +template +class iterator_buffer : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() == buf.capacity()) + static_cast(buf).flush(); + } + + void flush() { + size_t n = this->limit(this->size()); + if (this->data() == out_) { + out_ += n; + this->set(data_, buffer_size); + } + this->clear(); + } + + public: + explicit iterator_buffer(T* out, size_t n = buffer_size) + : fixed_buffer_traits(n), buffer(grow, out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) noexcept + : fixed_buffer_traits(other), + buffer(static_cast(other)), + out_(other.out_) { + if (this->data() != out_) { + this->set(data_, buffer_size); + this->clear(); + } + } + ~iterator_buffer() { flush(); } + + auto out() -> T* { + flush(); + return out_; + } + auto count() const -> size_t { + return fixed_buffer_traits::count() + this->size(); + } +}; + +template class iterator_buffer : public buffer { + public: + explicit iterator_buffer(T* out, size_t = 0) + : buffer([](buffer&, size_t) {}, out, 0, ~size_t()) {} + + auto out() -> T* { return &*this->end(); } +}; + +// A buffer that writes to a container with the contiguous storage. +template +class iterator_buffer< + OutputIt, + enable_if_t::value && + is_contiguous::value, + typename OutputIt::container_type::value_type>> + : public buffer { + private: + using container_type = typename OutputIt::container_type; + using value_type = typename container_type::value_type; + container_type& container_; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t capacity) { + auto& self = static_cast(buf); + self.container_.resize(capacity); + self.set(&self.container_[0], capacity); + } + + public: + explicit iterator_buffer(container_type& c) + : buffer(grow, c.size()), container_(c) {} + explicit iterator_buffer(OutputIt out, size_t = 0) + : iterator_buffer(get_container(out)) {} + + auto out() -> OutputIt { return back_inserter(container_); } +}; + +// A buffer that counts the number of code units written discarding the output. +template class counting_buffer : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() != buffer_size) return; + static_cast(buf).count_ += buf.size(); + buf.clear(); + } + + public: + counting_buffer() : buffer(grow, data_, 0, buffer_size) {} + + auto count() -> size_t { return count_ + this->size(); } +}; +} // namespace detail + +template +FMT_CONSTEXPR void basic_format_parse_context::do_check_arg_id(int id) { + // Argument id is only checked at compile-time during parsing because + // formatting has its own validation. + if (detail::is_constant_evaluated() && + (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { + using context = detail::compile_parse_context; + if (id >= static_cast(this)->num_args()) + report_error("argument not found"); + } +} + +template +FMT_CONSTEXPR void basic_format_parse_context::check_dynamic_spec( + int arg_id) { + if (detail::is_constant_evaluated() && + (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { + using context = detail::compile_parse_context; + static_cast(this)->check_dynamic_spec(arg_id); + } +} + +FMT_EXPORT template class basic_format_arg; +FMT_EXPORT template class basic_format_args; +FMT_EXPORT template class dynamic_format_arg_store; + +// A formatter for objects of type T. +FMT_EXPORT +template +struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; +}; + +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. +template +using has_formatter = + std::is_constructible>; + +// An output iterator that appends to a buffer. It is used instead of +// back_insert_iterator to reduce symbol sizes and avoid dependency. +template class basic_appender { + private: + detail::buffer* buffer_; + + friend auto get_container(basic_appender app) -> detail::buffer& { + return *app.buffer_; + } + + public: + using iterator_category = int; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; + using container_type = detail::buffer; + FMT_UNCHECKED_ITERATOR(basic_appender); + + FMT_CONSTEXPR basic_appender(detail::buffer& buf) : buffer_(&buf) {} + + auto operator=(T c) -> basic_appender& { + buffer_->push_back(c); + return *this; + } + auto operator*() -> basic_appender& { return *this; } + auto operator++() -> basic_appender& { return *this; } + auto operator++(int) -> basic_appender { return *this; } +}; + +using appender = basic_appender; + +namespace detail { +template +struct is_back_insert_iterator> : std::true_type {}; + +template +struct locking : std::true_type {}; +template +struct locking>::nonlocking>> + : std::false_type {}; + +template FMT_CONSTEXPR inline auto is_locking() -> bool { + return locking::value; +} +template +FMT_CONSTEXPR inline auto is_locking() -> bool { + return locking::value || is_locking(); +} + +// An optimized version of std::copy with the output value type (T). +template ::value)> +auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { + get_container(out).append(begin, end); + return out; +} + +template ::value)> +FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { + while (begin != end) *out++ = static_cast(*begin++); + return out; +} + +template +FMT_CONSTEXPR auto copy(basic_string_view s, OutputIt out) -> OutputIt { + return copy(s.begin(), s.end(), out); +} + +template +constexpr auto has_const_formatter_impl(T*) + -> decltype(typename Context::template formatter_type().format( + std::declval(), std::declval()), + true) { + return true; +} +template +constexpr auto has_const_formatter_impl(...) -> bool { + return false; +} +template +constexpr auto has_const_formatter() -> bool { + return has_const_formatter_impl(static_cast(nullptr)); +} + +template +struct is_buffer_appender : std::false_type {}; +template +struct is_buffer_appender< + It, bool_constant< + is_back_insert_iterator::value && + std::is_base_of, + typename It::container_type>::value>> + : std::true_type {}; + +// Maps an output iterator to a buffer. +template ::value)> +auto get_buffer(OutputIt out) -> iterator_buffer { + return iterator_buffer(out); +} +template ::value)> +auto get_buffer(OutputIt out) -> buffer& { + return get_container(out); +} + +template +auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) { + return buf.out(); +} +template +auto get_iterator(buffer&, OutputIt out) -> OutputIt { + return out; +} + +struct view {}; + +template struct named_arg : view { + const Char* name; + const T& value; + named_arg(const Char* n, const T& v) : name(n), value(v) {} +}; + +template struct named_arg_info { + const Char* name; + int id; +}; + +template struct is_named_arg : std::false_type {}; +template struct is_statically_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +template constexpr auto count() -> size_t { return B ? 1 : 0; } +template constexpr auto count() -> size_t { + return (B1 ? 1 : 0) + count(); +} + +template constexpr auto count_named_args() -> size_t { + return count::value...>(); +} + +template +constexpr auto count_statically_named_args() -> size_t { + return count::value...>(); +} + +struct unformattable {}; +struct unformattable_char : unformattable {}; +struct unformattable_pointer : unformattable {}; + +template struct string_value { + const Char* data; + size_t size; +}; + +template struct named_arg_value { + const named_arg_info* data; + size_t size; +}; + +template struct custom_value { + using parse_context = typename Context::parse_context_type; + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); +}; + +// A formatting argument value. +template class value { + public: + using char_type = typename Context::char_type; + + union { + monostate no_value; + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + int128_opt int128_value; + uint128_opt uint128_value; + bool bool_value; + char_type char_value; + float float_value; + double double_value; + long double long_double_value; + const void* pointer; + string_value string; + custom_value custom; + named_arg_value named_args; + }; + + constexpr FMT_ALWAYS_INLINE value() : no_value() {} + constexpr FMT_ALWAYS_INLINE value(int val) : int_value(val) {} + constexpr FMT_ALWAYS_INLINE value(unsigned val) : uint_value(val) {} + constexpr FMT_ALWAYS_INLINE value(long long val) : long_long_value(val) {} + constexpr FMT_ALWAYS_INLINE value(unsigned long long val) + : ulong_long_value(val) {} + FMT_ALWAYS_INLINE value(int128_opt val) : int128_value(val) {} + FMT_ALWAYS_INLINE value(uint128_opt val) : uint128_value(val) {} + constexpr FMT_ALWAYS_INLINE value(float val) : float_value(val) {} + constexpr FMT_ALWAYS_INLINE value(double val) : double_value(val) {} + FMT_ALWAYS_INLINE value(long double val) : long_double_value(val) {} + constexpr FMT_ALWAYS_INLINE value(bool val) : bool_value(val) {} + constexpr FMT_ALWAYS_INLINE value(char_type val) : char_value(val) {} + FMT_CONSTEXPR FMT_ALWAYS_INLINE value(const char_type* val) { + string.data = val; + if (is_constant_evaluated()) string.size = {}; + } + FMT_CONSTEXPR FMT_ALWAYS_INLINE value(basic_string_view val) { + string.data = val.data(); + string.size = val.size(); + } + FMT_ALWAYS_INLINE value(const void* val) : pointer(val) {} + FMT_ALWAYS_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + template FMT_CONSTEXPR20 FMT_ALWAYS_INLINE value(T& val) { + using value_type = remove_const_t; + // T may overload operator& e.g. std::vector::reference in libc++. +#if defined(__cpp_if_constexpr) + if constexpr (std::is_same::value) + custom.value = const_cast(&val); +#endif + if (!is_constant_evaluated()) + custom.value = const_cast(&reinterpret_cast(val)); + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + custom.format = format_custom_arg< + value_type, typename Context::template formatter_type>; + } + value(unformattable); + value(unformattable_char); + value(unformattable_pointer); + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { + auto f = Formatter(); + parse_ctx.advance_to(f.parse(parse_ctx)); + using qualified_type = + conditional_t(), const T, T>; + // format must be const for compatibility with std::format and compilation. + const auto& cf = f; + ctx.advance_to(cf.format(*static_cast(arg), ctx)); + } +}; + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. +enum { long_short = sizeof(long) == sizeof(int) }; +using long_type = conditional_t; +using ulong_type = conditional_t; + +template struct format_as_result { + template ::value || std::is_class::value)> + static auto map(U*) -> remove_cvref_t()))>; + static auto map(...) -> void; + + using type = decltype(map(static_cast(nullptr))); +}; +template using format_as_t = typename format_as_result::type; + +template +struct has_format_as + : bool_constant, void>::value> {}; + +#define FMT_MAP_API FMT_CONSTEXPR FMT_ALWAYS_INLINE + +// Maps formatting arguments to core types. +// arg_mapper reports errors by returning unformattable instead of using +// static_assert because it's used in the is_formattable trait. +template struct arg_mapper { + using char_type = typename Context::char_type; + + FMT_MAP_API auto map(signed char val) -> int { return val; } + FMT_MAP_API auto map(unsigned char val) -> unsigned { return val; } + FMT_MAP_API auto map(short val) -> int { return val; } + FMT_MAP_API auto map(unsigned short val) -> unsigned { return val; } + FMT_MAP_API auto map(int val) -> int { return val; } + FMT_MAP_API auto map(unsigned val) -> unsigned { return val; } + FMT_MAP_API auto map(long val) -> long_type { return val; } + FMT_MAP_API auto map(unsigned long val) -> ulong_type { return val; } + FMT_MAP_API auto map(long long val) -> long long { return val; } + FMT_MAP_API auto map(unsigned long long val) -> unsigned long long { + return val; + } + FMT_MAP_API auto map(int128_opt val) -> int128_opt { return val; } + FMT_MAP_API auto map(uint128_opt val) -> uint128_opt { return val; } + FMT_MAP_API auto map(bool val) -> bool { return val; } + + template ::value || + std::is_same::value)> + FMT_MAP_API auto map(T val) -> char_type { + return val; + } + template ::value || +#ifdef __cpp_char8_t + std::is_same::value || +#endif + std::is_same::value || + std::is_same::value) && + !std::is_same::value, + int> = 0> + FMT_MAP_API auto map(T) -> unformattable_char { + return {}; + } + + FMT_MAP_API auto map(float val) -> float { return val; } + FMT_MAP_API auto map(double val) -> double { return val; } + FMT_MAP_API auto map(long double val) -> long double { return val; } + + FMT_MAP_API auto map(char_type* val) -> const char_type* { return val; } + FMT_MAP_API auto map(const char_type* val) -> const char_type* { return val; } + template , + FMT_ENABLE_IF(std::is_same::value && + !std::is_pointer::value)> + FMT_MAP_API auto map(const T& val) -> basic_string_view { + return to_string_view(val); + } + template , + FMT_ENABLE_IF(!std::is_same::value && + !std::is_pointer::value)> + FMT_MAP_API auto map(const T&) -> unformattable_char { + return {}; + } + + FMT_MAP_API auto map(void* val) -> const void* { return val; } + FMT_MAP_API auto map(const void* val) -> const void* { return val; } + FMT_MAP_API auto map(volatile void* val) -> const void* { + return const_cast(val); + } + FMT_MAP_API auto map(const volatile void* val) -> const void* { + return const_cast(val); + } + FMT_MAP_API auto map(std::nullptr_t val) -> const void* { return val; } + + // Use SFINAE instead of a const T* parameter to avoid a conflict with the + // array overload. + template < + typename T, + FMT_ENABLE_IF( + std::is_pointer::value || std::is_member_pointer::value || + std::is_function::type>::value || + (std::is_array::value && + !std::is_convertible::value))> + FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { + return {}; + } + + template ::value)> + FMT_MAP_API auto map(const T (&values)[N]) -> const T (&)[N] { + return values; + } + + // Only map owning types because mapping views can be unsafe. + template , + FMT_ENABLE_IF(std::is_arithmetic::value)> + FMT_MAP_API auto map(const T& val) -> decltype(FMT_DECLTYPE_THIS map(U())) { + return map(format_as(val)); + } + + template > + struct formattable : bool_constant() || + (has_formatter::value && + !std::is_const::value)> {}; + + template ::value)> + FMT_MAP_API auto do_map(T& val) -> T& { + return val; + } + template ::value)> + FMT_MAP_API auto do_map(T&) -> unformattable { + return {}; + } + + // is_fundamental is used to allow formatters for extended FP types. + template , + FMT_ENABLE_IF( + (std::is_class::value || std::is_enum::value || + std::is_union::value || std::is_fundamental::value) && + !has_to_string_view::value && !is_char::value && + !is_named_arg::value && !std::is_integral::value && + !std::is_arithmetic>::value)> + FMT_MAP_API auto map(T& val) -> decltype(FMT_DECLTYPE_THIS do_map(val)) { + return do_map(val); + } + + template ::value)> + FMT_MAP_API auto map(const T& named_arg) + -> decltype(FMT_DECLTYPE_THIS map(named_arg.value)) { + return map(named_arg.value); + } + + auto map(...) -> unformattable { return {}; } +}; + +// A type constant after applying arg_mapper. +template +using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + +enum { packed_arg_bits = 4 }; +// Maximum number of arguments with packed types. +enum { max_packed_args = 62 / packed_arg_bits }; +enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; +enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; + +template +struct is_output_iterator : std::false_type {}; + +template <> struct is_output_iterator : std::true_type {}; + +template +struct is_output_iterator< + It, T, void_t()++ = std::declval())>> + : std::true_type {}; + +// A type-erased reference to an std::locale to avoid a heavy include. +class locale_ref { + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr locale_ref() : locale_(nullptr) {} + template explicit locale_ref(const Locale& loc); + + explicit operator bool() const noexcept { return locale_ != nullptr; } + + template auto get() const -> Locale; +}; + +template constexpr auto encode_types() -> unsigned long long { + return 0; +} + +template +constexpr auto encode_types() -> unsigned long long { + return static_cast(mapped_type_constant::value) | + (encode_types() << packed_arg_bits); +} + +template +constexpr unsigned long long make_descriptor() { + return NUM_ARGS <= max_packed_args ? encode_types() + : is_unpacked_bit | NUM_ARGS; +} + +// This type is intentionally undefined, only used for errors. +template +#if FMT_CLANG_VERSION && FMT_CLANG_VERSION <= 1500 +// https://github.com/fmtlib/fmt/issues/3796 +struct type_is_unformattable_for { +}; +#else +struct type_is_unformattable_for; +#endif + +template +FMT_CONSTEXPR auto make_arg(T& val) -> value { + using arg_type = remove_cvref_t().map(val))>; + + // Use enum instead of constexpr because the latter may generate code. + enum { + formattable_char = !std::is_same::value + }; + static_assert(formattable_char, "Mixing character types is disallowed."); + + // Formatting of arbitrary pointers is disallowed. If you want to format a + // pointer cast it to `void*` or `const void*`. In particular, this forbids + // formatting of `[const] volatile char*` printed as bool by iostreams. + enum { + formattable_pointer = !std::is_same::value + }; + static_assert(formattable_pointer, + "Formatting of non-void pointers is disallowed."); + + enum { formattable = !std::is_same::value }; +#if defined(__cpp_if_constexpr) + if constexpr (!formattable) + type_is_unformattable_for _; +#endif + static_assert( + formattable, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return {arg_mapper().map(val)}; +} + +template +FMT_CONSTEXPR auto make_arg(T& val) -> basic_format_arg { + auto arg = basic_format_arg(); + arg.type_ = mapped_type_constant::value; + arg.value_ = make_arg(val); + return arg; +} + +template +FMT_CONSTEXPR inline auto make_arg(T& val) -> basic_format_arg { + return make_arg(val); +} + +template +using arg_t = conditional_t, + basic_format_arg>; + +template ::value)> +void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) { + ++arg_index; +} +template ::value)> +void init_named_arg(named_arg_info* named_args, int& arg_index, + int& named_arg_index, const T& arg) { + named_args[named_arg_index++] = {arg.name, arg_index++}; +} + +// An array of references to arguments. It can be implicitly converted to +// `fmt::basic_format_args` for passing into type-erased formatting functions +// such as `fmt::vformat`. +template +struct format_arg_store { + // args_[0].named_args points to named_args to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + static constexpr size_t ARGS_ARR_SIZE = 1 + (NUM_ARGS != 0 ? NUM_ARGS : +1); + + arg_t args[ARGS_ARR_SIZE]; + named_arg_info named_args[NUM_NAMED_ARGS]; + + template + FMT_MAP_API format_arg_store(T&... values) + : args{{named_args, NUM_NAMED_ARGS}, + make_arg(values)...} { + using dummy = int[]; + int arg_index = 0, named_arg_index = 0; + (void)dummy{ + 0, + (init_named_arg(named_args, arg_index, named_arg_index, values), 0)...}; + } + + format_arg_store(format_arg_store&& rhs) { + args[0] = {named_args, NUM_NAMED_ARGS}; + for (size_t i = 1; i < ARGS_ARR_SIZE; ++i) args[i] = rhs.args[i]; + for (size_t i = 0; i < NUM_NAMED_ARGS; ++i) + named_args[i] = rhs.named_args[i]; + } + + format_arg_store(const format_arg_store& rhs) = delete; + format_arg_store& operator=(const format_arg_store& rhs) = delete; + format_arg_store& operator=(format_arg_store&& rhs) = delete; +}; + +// A specialization of format_arg_store without named arguments. +// It is a plain struct to reduce binary size in debug mode. +template +struct format_arg_store { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + arg_t args[NUM_ARGS != 0 ? NUM_ARGS : +1]; +}; + +} // namespace detail +FMT_BEGIN_EXPORT + +// A formatting argument. Context is a template parameter for the compiled API +// where output can be unbuffered. +template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + template + friend FMT_CONSTEXPR auto detail::make_arg(T& value) + -> basic_format_arg; + + friend class basic_format_args; + friend class dynamic_format_arg_store; + + using char_type = typename Context::char_type; + + template + friend struct detail::format_arg_store; + + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + + public: + class handle { + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(typename Context::parse_context_type& parse_ctx, + Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + + private: + detail::custom_value custom_; + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + + constexpr explicit operator bool() const noexcept { + return type_ != detail::type::none_type; + } + + auto type() const -> detail::type { return type_; } + + auto is_integral() const -> bool { return detail::is_integral_type(type_); } + auto is_arithmetic() const -> bool { + return detail::is_arithmetic_type(type_); + } + + /** + * Visits an argument dispatching to the appropriate visit method based on + * the argument type. For example, if the argument type is `double` then + * `vis(value)` will be called with the value of type `double`. + */ + template + FMT_CONSTEXPR FMT_INLINE auto visit(Visitor&& vis) const -> decltype(vis(0)) { + switch (type_) { + case detail::type::none_type: + break; + case detail::type::int_type: + return vis(value_.int_value); + case detail::type::uint_type: + return vis(value_.uint_value); + case detail::type::long_long_type: + return vis(value_.long_long_value); + case detail::type::ulong_long_type: + return vis(value_.ulong_long_value); + case detail::type::int128_type: + return vis(detail::convert_for_visit(value_.int128_value)); + case detail::type::uint128_type: + return vis(detail::convert_for_visit(value_.uint128_value)); + case detail::type::bool_type: + return vis(value_.bool_value); + case detail::type::char_type: + return vis(value_.char_value); + case detail::type::float_type: + return vis(value_.float_value); + case detail::type::double_type: + return vis(value_.double_value); + case detail::type::long_double_type: + return vis(value_.long_double_value); + case detail::type::cstring_type: + return vis(value_.string.data); + case detail::type::string_type: + using sv = basic_string_view; + return vis(sv(value_.string.data, value_.string.size)); + case detail::type::pointer_type: + return vis(value_.pointer); + case detail::type::custom_type: + return vis(typename basic_format_arg::handle(value_.custom)); + } + return vis(monostate()); + } + + auto format_custom(const char_type* parse_begin, + typename Context::parse_context_type& parse_ctx, + Context& ctx) -> bool { + if (type_ != detail::type::custom_type) return false; + parse_ctx.advance_to(parse_begin); + value_.custom.format(value_.custom.value, parse_ctx, ctx); + return true; + } +}; + +template +FMT_DEPRECATED FMT_CONSTEXPR auto visit_format_arg( + Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { + return arg.visit(static_cast(vis)); +} + +/** + * A view of a collection of formatting arguments. To avoid lifetime issues it + * should only be used as a parameter type in type-erased functions such as + * `vformat`: + * + * void vlog(fmt::string_view fmt, fmt::format_args args); // OK + * fmt::format_args args = fmt::make_format_args(); // Dangling reference + */ +template class basic_format_args { + public: + using size_type = int; + using format_arg = basic_format_arg; + + private: + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; + union { + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const detail::value* values_; + const format_arg* args_; + }; + + constexpr auto is_packed() const -> bool { + return (desc_ & detail::is_unpacked_bit) == 0; + } + constexpr auto has_named_args() const -> bool { + return (desc_ & detail::has_named_args_bit) != 0; + } + + FMT_CONSTEXPR auto type(int index) const -> detail::type { + int shift = index * detail::packed_arg_bits; + unsigned int mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + public: + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /// Constructs a `basic_format_args` object from `format_arg_store`. + template + constexpr FMT_ALWAYS_INLINE basic_format_args( + const detail::format_arg_store& + store) + : desc_(DESC), values_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {} + + template detail::max_packed_args)> + constexpr basic_format_args( + const detail::format_arg_store& + store) + : desc_(DESC), args_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {} + + /// Constructs a `basic_format_args` object from `dynamic_format_arg_store`. + constexpr basic_format_args(const dynamic_format_arg_store& store) + : desc_(store.get_types()), args_(store.data()) {} + + /// Constructs a `basic_format_args` object from a dynamic list of arguments. + constexpr basic_format_args(const format_arg* args, int count) + : desc_(detail::is_unpacked_bit | detail::to_unsigned(count)), + args_(args) {} + + /// Returns the argument with the specified id. + FMT_CONSTEXPR auto get(int id) const -> format_arg { + format_arg arg; + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (static_cast(id) >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ == detail::type::none_type) return arg; + arg.value_ = values_[id]; + return arg; + } + + template + auto get(basic_string_view name) const -> format_arg { + int id = get_id(name); + return id >= 0 ? get(id) : format_arg(); + } + + template + FMT_CONSTEXPR auto get_id(basic_string_view name) const -> int { + if (!has_named_args()) return -1; + const auto& named_args = + (is_packed() ? values_[-1] : args_[-1].value_).named_args; + for (size_t i = 0; i < named_args.size; ++i) { + if (named_args.data[i].name == name) return named_args.data[i].id; + } + return -1; + } + + auto max_size() const -> int { + unsigned long long max_packed = detail::max_packed_args; + return static_cast(is_packed() ? max_packed + : desc_ & ~detail::is_unpacked_bit); + } +}; + +// A formatting context. +class context { + private: + appender out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + /// The character type for the output. + using char_type = char; + + using iterator = appender; + using format_arg = basic_format_arg; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + /// Constructs a `basic_format_context` object. References to the arguments + /// are stored in the object so make sure they have appropriate lifetimes. + FMT_CONSTEXPR context(iterator out, basic_format_args ctx_args, + detail::locale_ref loc = {}) + : out_(out), args_(ctx_args), loc_(loc) {} + context(context&&) = default; + context(const context&) = delete; + void operator=(const context&) = delete; + + FMT_CONSTEXPR auto arg(int id) const -> format_arg { return args_.get(id); } + auto arg(string_view name) -> format_arg { return args_.get(name); } + FMT_CONSTEXPR auto arg_id(string_view name) -> int { + return args_.get_id(name); + } + auto args() const -> const basic_format_args& { return args_; } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR auto out() -> iterator { return out_; } + + // Advances the begin iterator to `it`. + void advance_to(iterator) {} + + FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } +}; + +template class generic_context; + +// Longer aliases for C++20 compatibility. +template +using basic_format_context = + conditional_t::value, context, + generic_context>; +using format_context = context; + +template +using buffered_context = basic_format_context, Char>; + +template +using is_formattable = bool_constant>() + .map(std::declval()))>::value>; + +#if FMT_USE_CONCEPTS +template +concept formattable = is_formattable, Char>::value; +#endif + +/** + * Constructs an object that stores references to arguments and can be + * implicitly converted to `format_args`. `Context` can be omitted in which case + * it defaults to `format_context`. See `arg` for lifetime considerations. + */ +// Take arguments by lvalue references to avoid some lifetime issues, e.g. +// auto args = make_format_args(std::string()); +template (), + unsigned long long DESC = detail::make_descriptor(), + FMT_ENABLE_IF(NUM_NAMED_ARGS == 0)> +constexpr FMT_ALWAYS_INLINE auto make_format_args(T&... args) + -> detail::format_arg_store { + return {{detail::make_arg( + args)...}}; +} + +#ifndef FMT_DOC +template (), + unsigned long long DESC = + detail::make_descriptor() | + static_cast(detail::has_named_args_bit), + FMT_ENABLE_IF(NUM_NAMED_ARGS != 0)> +constexpr auto make_format_args(T&... args) + -> detail::format_arg_store { + return {args...}; +} +#endif + +/** + * Returns a named argument to be used in a formatting function. + * It should only be used in a call to a formatting function or + * `dynamic_format_arg_store::push_back`. + * + * **Example**: + * + * fmt::print("The answer is {answer}.", fmt::arg("answer", 42)); + */ +template +inline auto arg(const Char* name, const T& arg) -> detail::named_arg { + static_assert(!detail::is_named_arg(), "nested named arguments"); + return {name, arg}; +} +FMT_END_EXPORT + +/// An alias for `basic_format_args`. +// A separate type would result in shorter symbols but break ABI compatibility +// between clang and gcc on ARM (#1919). +FMT_EXPORT using format_args = basic_format_args; + +// We cannot use enum classes as bit fields because of a gcc bug, so we put them +// in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414). +// Additionally, if an underlying type is specified, older gcc incorrectly warns +// that the type is too small. Both bugs are fixed in gcc 9.3. +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903 +# define FMT_ENUM_UNDERLYING_TYPE(type) +#else +# define FMT_ENUM_UNDERLYING_TYPE(type) : type +#endif +namespace align { +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, left, right, center, + numeric}; +} +using align_t = align::type; +namespace sign { +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space}; +} +using sign_t = sign::type; + +namespace detail { + +template +using unsigned_char = typename conditional_t::value, + std::make_unsigned, + type_identity>::type; + +// Character (code unit) type is erased to prevent template bloat. +struct fill_t { + private: + enum { max_size = 4 }; + char data_[max_size] = {' '}; + unsigned char size_ = 1; + + public: + template + FMT_CONSTEXPR void operator=(basic_string_view s) { + auto size = s.size(); + size_ = static_cast(size); + if (size == 1) { + unsigned uchar = static_cast>(s[0]); + data_[0] = static_cast(uchar); + data_[1] = static_cast(uchar >> 8); + return; + } + FMT_ASSERT(size <= max_size, "invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = static_cast(s[i]); + } + + FMT_CONSTEXPR void operator=(char c) { + data_[0] = c; + size_ = 1; + } + + constexpr auto size() const -> size_t { return size_; } + + template constexpr auto get() const -> Char { + using uchar = unsigned char; + return static_cast(static_cast(data_[0]) | + (static_cast(data_[1]) << 8)); + } + + template ::value)> + constexpr auto data() const -> const Char* { + return data_; + } + template ::value)> + constexpr auto data() const -> const Char* { + return nullptr; + } +}; +} // namespace detail + +enum class presentation_type : unsigned char { + // Common specifiers: + none = 0, + debug = 1, // '?' + string = 2, // 's' (string, bool) + + // Integral, bool and character specifiers: + dec = 3, // 'd' + hex, // 'x' or 'X' + oct, // 'o' + bin, // 'b' or 'B' + chr, // 'c' + + // String and pointer specifiers: + pointer = 3, // 'p' + + // Floating-point specifiers: + exp = 1, // 'e' or 'E' (1 since there is no FP debug presentation) + fixed, // 'f' or 'F' + general, // 'g' or 'G' + hexfloat // 'a' or 'A' +}; + +// Format specifiers for built-in and string types. +struct format_specs { + int width; + int precision; + presentation_type type; + align_t align : 4; + sign_t sign : 3; + bool upper : 1; // An uppercase version e.g. 'X' for 'x'. + bool alt : 1; // Alternate form ('#'). + bool localized : 1; + detail::fill_t fill; + + constexpr format_specs() + : width(0), + precision(-1), + type(presentation_type::none), + align(align::none), + sign(sign::none), + upper(false), + alt(false), + localized(false) {} +}; + +namespace detail { + +enum class arg_id_kind { none, index, name }; + +// An argument reference. +template struct arg_ref { + FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} + + FMT_CONSTEXPR explicit arg_ref(int index) + : kind(arg_id_kind::index), val(index) {} + FMT_CONSTEXPR explicit arg_ref(basic_string_view name) + : kind(arg_id_kind::name), val(name) {} + + FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { + kind = arg_id_kind::index; + val.index = idx; + return *this; + } + + arg_id_kind kind; + union value { + FMT_CONSTEXPR value(int idx = 0) : index(idx) {} + FMT_CONSTEXPR value(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; + } val; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow reusing the same parsed specifiers with +// different sets of arguments (precompilation of format strings). +template struct dynamic_format_specs : format_specs { + arg_ref width_ref; + arg_ref precision_ref; +}; + +// Converts a character to ASCII. Returns '\0' on conversion failure. +template ::value)> +constexpr auto to_ascii(Char c) -> char { + return c <= 0xff ? static_cast(c) : '\0'; +} + +// Returns the number of code units in a code point or 1 on error. +template +FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { + if (const_check(sizeof(Char) != 1)) return 1; + auto c = static_cast(*begin); + return static_cast((0x3a55000000000000ull >> (2 * (c >> 3))) & 0x3) + 1; +} + +// Return the result via the out param to workaround gcc bug 77539. +template +FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { + for (out = first; out != last; ++out) { + if (*out == value) return true; + } + return false; +} + +template <> +inline auto find(const char* first, const char* last, char value, + const char*& out) -> bool { + out = + static_cast(memchr(first, value, to_unsigned(last - first))); + return out != nullptr; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template +FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, + int error_value) noexcept -> int { + FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); + unsigned value = 0, prev = 0; + auto p = begin; + do { + prev = value; + value = value * 10 + unsigned(*p - '0'); + ++p; + } while (p != end && '0' <= *p && *p <= '9'); + auto num_digits = p - begin; + begin = p; + int digits10 = static_cast(sizeof(int) * CHAR_BIT * 3 / 10); + if (num_digits <= digits10) return static_cast(value); + // Check for overflow. + unsigned max = INT_MAX; + return num_digits == digits10 + 1 && + prev * 10ull + unsigned(p[-1] - '0') <= max + ? static_cast(value) + : error_value; +} + +FMT_CONSTEXPR inline auto parse_align(char c) -> align_t { + switch (c) { + case '<': + return align::left; + case '>': + return align::right; + case '^': + return align::center; + } + return align::none; +} + +template constexpr auto is_name_start(Char c) -> bool { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_'; +} + +template +FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = parse_nonnegative_int(begin, end, INT_MAX); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + report_error("invalid format string"); + else + handler.on_index(index); + return begin; + } + if (!is_name_start(c)) { + report_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9'))); + handler.on_name({begin, to_unsigned(it - begin)}); + return it; +} + +template +FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + FMT_ASSERT(begin != end, ""); + Char c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler.on_auto(); + return begin; +} + +template struct dynamic_spec_id_handler { + basic_format_parse_context& ctx; + arg_ref& ref; + + FMT_CONSTEXPR void on_auto() { + int id = ctx.next_arg_id(); + ref = arg_ref(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_index(int id) { + ref = arg_ref(id); + ctx.check_arg_id(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_name(basic_string_view id) { + ref = arg_ref(id); + ctx.check_arg_id(id); + } +}; + +// Parses [integer | "{" [arg_id] "}"]. +template +FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, + int& value, arg_ref& ref, + basic_format_parse_context& ctx) + -> const Char* { + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + int val = parse_nonnegative_int(begin, end, -1); + if (val != -1) + value = val; + else + report_error("number is too big"); + } else if (*begin == '{') { + ++begin; + auto handler = dynamic_spec_id_handler{ctx, ref}; + if (begin != end) begin = parse_arg_id(begin, end, handler); + if (begin != end && *begin == '}') return ++begin; + report_error("invalid format string"); + } + return begin; +} + +template +FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, + int& value, arg_ref& ref, + basic_format_parse_context& ctx) + -> const Char* { + ++begin; + if (begin == end || *begin == '}') { + report_error("invalid precision"); + return begin; + } + return parse_dynamic_spec(begin, end, value, ref, ctx); +} + +enum class state { start, align, sign, hash, zero, width, precision, locale }; + +// Parses standard format specifiers. +template +FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, + dynamic_format_specs& specs, + basic_format_parse_context& ctx, + type arg_type) -> const Char* { + auto c = '\0'; + if (end - begin > 1) { + auto next = to_ascii(begin[1]); + c = parse_align(next) == align::none ? to_ascii(*begin) : '\0'; + } else { + if (begin == end) return begin; + c = to_ascii(*begin); + } + + struct { + state current_state = state::start; + FMT_CONSTEXPR void operator()(state s, bool valid = true) { + if (current_state >= s || !valid) + report_error("invalid format specifier"); + current_state = s; + } + } enter_state; + + using pres = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + struct { + const Char*& begin; + dynamic_format_specs& specs; + type arg_type; + + FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* { + if (!in(arg_type, set)) { + if (arg_type == type::none_type) return begin; + report_error("invalid format specifier"); + } + specs.type = pres_type; + return begin + 1; + } + } parse_presentation_type{begin, specs, arg_type}; + + for (;;) { + switch (c) { + case '<': + case '>': + case '^': + enter_state(state::align); + specs.align = parse_align(c); + ++begin; + break; + case '+': + case '-': + case ' ': + if (arg_type == type::none_type) return begin; + enter_state(state::sign, in(arg_type, sint_set | float_set)); + switch (c) { + case '+': + specs.sign = sign::plus; + break; + case '-': + specs.sign = sign::minus; + break; + case ' ': + specs.sign = sign::space; + break; + } + ++begin; + break; + case '#': + if (arg_type == type::none_type) return begin; + enter_state(state::hash, is_arithmetic_type(arg_type)); + specs.alt = true; + ++begin; + break; + case '0': + enter_state(state::zero); + if (!is_arithmetic_type(arg_type)) { + if (arg_type == type::none_type) return begin; + report_error("format specifier requires numeric argument"); + } + if (specs.align == align::none) { + // Ignore 0 if align is specified for compatibility with std::format. + specs.align = align::numeric; + specs.fill = '0'; + } + ++begin; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '{': + enter_state(state::width); + begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx); + break; + case '.': + if (arg_type == type::none_type) return begin; + enter_state(state::precision, + in(arg_type, float_set | string_set | cstring_set)); + begin = parse_precision(begin, end, specs.precision, specs.precision_ref, + ctx); + break; + case 'L': + if (arg_type == type::none_type) return begin; + enter_state(state::locale, is_arithmetic_type(arg_type)); + specs.localized = true; + ++begin; + break; + case 'd': + return parse_presentation_type(pres::dec, integral_set); + case 'X': + specs.upper = true; + FMT_FALLTHROUGH; + case 'x': + return parse_presentation_type(pres::hex, integral_set); + case 'o': + return parse_presentation_type(pres::oct, integral_set); + case 'B': + specs.upper = true; + FMT_FALLTHROUGH; + case 'b': + return parse_presentation_type(pres::bin, integral_set); + case 'E': + specs.upper = true; + FMT_FALLTHROUGH; + case 'e': + return parse_presentation_type(pres::exp, float_set); + case 'F': + specs.upper = true; + FMT_FALLTHROUGH; + case 'f': + return parse_presentation_type(pres::fixed, float_set); + case 'G': + specs.upper = true; + FMT_FALLTHROUGH; + case 'g': + return parse_presentation_type(pres::general, float_set); + case 'A': + specs.upper = true; + FMT_FALLTHROUGH; + case 'a': + return parse_presentation_type(pres::hexfloat, float_set); + case 'c': + if (arg_type == type::bool_type) report_error("invalid format specifier"); + return parse_presentation_type(pres::chr, integral_set); + case 's': + return parse_presentation_type(pres::string, + bool_set | string_set | cstring_set); + case 'p': + return parse_presentation_type(pres::pointer, pointer_set | cstring_set); + case '?': + return parse_presentation_type(pres::debug, + char_set | string_set | cstring_set); + case '}': + return begin; + default: { + if (*begin == '}') return begin; + // Parse fill and alignment. + auto fill_end = begin + code_point_length(begin); + if (end - fill_end <= 0) { + report_error("invalid format specifier"); + return begin; + } + if (*begin == '{') { + report_error("invalid fill character '{'"); + return begin; + } + auto align = parse_align(to_ascii(*fill_end)); + enter_state(state::align, align != align::none); + specs.fill = + basic_string_view(begin, to_unsigned(fill_end - begin)); + specs.align = align; + begin = fill_end + 1; + } + } + if (begin == end) return begin; + c = to_ascii(*begin); + } +} + +template +FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void on_auto() { arg_id = handler.on_arg_id(); } + FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void on_name(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + }; + + ++begin; + if (begin == end) return handler.on_error("invalid format string"), end; + if (*begin == '}') { + handler.on_replacement_field(handler.on_arg_id(), begin); + } else if (*begin == '{') { + handler.on_text(begin, begin + 1); + } else { + auto adapter = id_adapter{handler, 0}; + begin = parse_arg_id(begin, end, adapter); + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(adapter.arg_id, begin); + } else if (c == ':') { + begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + } else { + return handler.on_error("missing '}' in format string"), end; + } + } + return begin + 1; +} + +template +FMT_CONSTEXPR void parse_format_string(basic_string_view format_str, + Handler&& handler) { + auto begin = format_str.data(); + auto end = begin + format_str.size(); + if (end - begin < 32) { + // Use a simple loop instead of memchr for small strings. + const Char* p = begin; + while (p != end) { + auto c = *p++; + if (c == '{') { + handler.on_text(begin, p - 1); + begin = p = parse_replacement_field(p - 1, end, handler); + } else if (c == '}') { + if (p == end || *p != '}') + return handler.on_error("unmatched '}' in format string"); + handler.on_text(begin, p); + begin = ++p; + } + } + handler.on_text(begin, end); + return; + } + struct writer { + FMT_CONSTEXPR void operator()(const Char* from, const Char* to) { + if (from == to) return; + for (;;) { + const Char* p = nullptr; + if (!find(from, to, Char('}'), p)) + return handler_.on_text(from, to); + ++p; + if (p == to || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(from, p); + from = p + 1; + } + } + Handler& handler_; + } write = {handler}; + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char* p = begin; + if (*begin != '{' && !find(begin + 1, end, Char('{'), p)) + return write(begin, end); + write(begin, p); + begin = parse_replacement_field(p, end, handler); + } +} + +template ::value> struct strip_named_arg { + using type = T; +}; +template struct strip_named_arg { + using type = remove_cvref_t; +}; + +template +FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769). +FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) + -> decltype(ctx.begin()) { + using char_type = typename ParseContext::char_type; + using context = buffered_context; + using mapped_type = conditional_t< + mapped_type_constant::value != type::custom_type, + decltype(arg_mapper().map(std::declval())), + typename strip_named_arg::type>; +#if defined(__cpp_if_constexpr) + if constexpr (std::is_default_constructible< + formatter>::value) { + return formatter().parse(ctx); + } else { + type_is_unformattable_for _; + return ctx.begin(); + } +#else + return formatter().parse(ctx); +#endif +} + +// Checks char specs and returns true iff the presentation type is char-like. +FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool { + if (specs.type != presentation_type::none && + specs.type != presentation_type::chr && + specs.type != presentation_type::debug) { + return false; + } + if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) + report_error("invalid format specifier for char"); + return true; +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template +constexpr auto get_arg_index_by_name(basic_string_view name) -> int { + if constexpr (is_statically_named_arg()) { + if (name == T::name) return N; + } + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name(name); + (void)name; // Workaround an MSVC bug about "unused" parameter. + return -1; +} +#endif + +template +FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +#endif + (void)name; + return -1; +} + +template class format_string_checker { + private: + using parse_context_type = compile_parse_context; + static constexpr int num_args = sizeof...(Args); + + // Format specifier parsing function. + // In the future basic_format_parse_context will replace compile_parse_context + // here and will use is_constant_evaluated and downcasting to access the data + // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. + using parse_func = const Char* (*)(parse_context_type&); + + type types_[num_args > 0 ? static_cast(num_args) : 1]; + parse_context_type context_; + parse_func parse_funcs_[num_args > 0 ? static_cast(num_args) : 1]; + + public: + explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt) + : types_{mapped_type_constant>::value...}, + context_(fmt, num_args, types_), + parse_funcs_{&parse_format_specs...} {} + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + return context_.check_arg_id(id), id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + auto index = get_arg_index_by_name(id); + if (index < 0) on_error("named argument is not found"); + return index; +#else + (void)id; + on_error("compile-time checks for named arguments require C++20 support"); + return 0; +#endif + } + + FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { + on_format_specs(id, begin, begin); // Call parse() on empty specs. + } + + FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) + -> const Char* { + context_.advance_to(begin); + // id >= 0 check is a workaround for gcc 10 bug (#2065). + return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + } + + FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) { + report_error(message); + } +}; + +// A base class for compile-time strings. +struct compile_string {}; + +template +using is_compile_string = std::is_base_of; + +// Reports a compile-time error if S is not a valid format string. +template ::value)> +FMT_ALWAYS_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif +} +template ::value)> +void check_format_string(S format_str) { + using char_t = typename S::char_type; + FMT_CONSTEXPR auto s = basic_string_view(format_str); + using checker = format_string_checker...>; + FMT_CONSTEXPR bool error = (parse_format_string(s, checker(s)), true); + ignore_unused(error); +} + +// Report truncation to prevent silent data loss. +inline void report_truncation(bool truncated) { + if (truncated) report_error("output is truncated"); +} + +// Use vformat_args and avoid type_identity to keep symbols short and workaround +// a GCC <= 4.8 bug. +template struct vformat_args { + using type = basic_format_args>; +}; +template <> struct vformat_args { + using type = format_args; +}; + +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc = {}); + +FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool = false); +#ifndef _WIN32 +inline void vprint_mojibake(FILE*, string_view, format_args, bool) {} +#endif + +template struct native_formatter { + private: + dynamic_format_specs specs_; + + public: + using nonlocking = void; + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { + if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); + auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE); + if (const_check(TYPE == type::char_type)) check_char_specs(specs_); + return end; + } + + template + FMT_CONSTEXPR void set_debug_format(bool set = true) { + specs_.type = set ? presentation_type::debug : presentation_type::none; + } + + template + FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const + -> decltype(ctx.out()); +}; +} // namespace detail + +FMT_BEGIN_EXPORT + +// A formatter specialization for natively supported types. +template +struct formatter::value != + detail::type::custom_type>> + : detail::native_formatter::value> { +}; + +template struct runtime_format_string { + basic_string_view str; +}; + +/// A compile-time format string. +template class basic_format_string { + private: + basic_string_view str_; + + public: + template < + typename S, + FMT_ENABLE_IF( + std::is_convertible>::value || + (detail::is_compile_string::value && + std::is_constructible, const S&>::value))> + FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_format_string(const S& s) : str_(s) { + static_assert( + detail::count< + (std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); +#if FMT_USE_CONSTEVAL + if constexpr (detail::count_named_args() == + detail::count_statically_named_args()) { + using checker = + detail::format_string_checker...>; + detail::parse_format_string(str_, checker(s)); + } +#else + detail::check_format_string(s); +#endif + } + basic_format_string(runtime_format_string fmt) : str_(fmt.str) {} + + FMT_ALWAYS_INLINE operator basic_string_view() const { return str_; } + auto get() const -> basic_string_view { return str_; } +}; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +// Workaround broken conversion on older gcc. +template using format_string = string_view; +inline auto runtime(string_view s) -> string_view { return s; } +#else +template +using format_string = basic_format_string...>; +/** + * Creates a runtime format string. + * + * **Example**: + * + * // Check format string at runtime instead of compile-time. + * fmt::print(fmt::runtime("{:d}"), "I am not a number"); + */ +inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; } +#endif + +/// Formats a string and writes the output to `out`. +template , + char>::value)> +auto vformat_to(OutputIt&& out, string_view fmt, format_args args) + -> remove_cvref_t { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, fmt, args, {}); + return detail::get_iterator(buf, out); +} + +/** + * Formats `args` according to specifications in `fmt`, writes the result to + * the output iterator `out` and returns the iterator past the end of the output + * range. `format_to` does not append a terminating null character. + * + * **Example**: + * + * auto out = std::vector(); + * fmt::format_to(std::back_inserter(out), "{}", 42); + */ +template , + char>::value)> +FMT_INLINE auto format_to(OutputIt&& out, format_string fmt, T&&... args) + -> remove_cvref_t { + return vformat_to(FMT_FWD(out), fmt, fmt::make_format_args(args...)); +} + +template struct format_to_n_result { + /// Iterator past the end of the output range. + OutputIt out; + /// Total (not truncated) output size. + size_t size; +}; + +template ::value)> +auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + detail::vformat_to(buf, fmt, args, {}); + return {buf.out(), buf.count()}; +} + +/** + * Formats `args` according to specifications in `fmt`, writes up to `n` + * characters of the result to the output iterator `out` and returns the total + * (not truncated) output size and the iterator past the end of the output + * range. `format_to_n` does not append a terminating null character. + */ +template ::value)> +FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, + T&&... args) -> format_to_n_result { + return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); +} + +template +struct format_to_result { + /// Iterator pointing to just after the last successful write in the range. + OutputIt out; + /// Specifies if the output was truncated. + bool truncated; + + FMT_CONSTEXPR operator OutputIt&() & { + detail::report_truncation(truncated); + return out; + } + FMT_CONSTEXPR operator const OutputIt&() const& { + detail::report_truncation(truncated); + return out; + } + FMT_CONSTEXPR operator OutputIt&&() && { + detail::report_truncation(truncated); + return static_cast(out); + } +}; + +template +auto vformat_to(char (&out)[N], string_view fmt, format_args args) + -> format_to_result { + auto result = vformat_to_n(out, N, fmt, args); + return {result.out, result.size > N}; +} + +template +FMT_INLINE auto format_to(char (&out)[N], format_string fmt, T&&... args) + -> format_to_result { + auto result = fmt::format_to_n(out, N, fmt, static_cast(args)...); + return {result.out, result.size > N}; +} + +/// Returns the number of chars in the output of `format(fmt, args...)`. +template +FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), {}); + return buf.count(); +} + +FMT_API void vprint(string_view fmt, format_args args); +FMT_API void vprint(FILE* f, string_view fmt, format_args args); +FMT_API void vprint_buffered(FILE* f, string_view fmt, format_args args); +FMT_API void vprintln(FILE* f, string_view fmt, format_args args); + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `stdout`. + * + * **Example**: + * + * fmt::print("The answer is {}.", 42); + */ +template +FMT_INLINE void print(format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (!detail::use_utf8()) return detail::vprint_mojibake(stdout, fmt, vargs); + return detail::is_locking() ? vprint_buffered(stdout, fmt, vargs) + : vprint(fmt, vargs); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the + * output to the file `f`. + * + * **Example**: + * + * fmt::print(stderr, "Don't {}!", "panic"); + */ +template +FMT_INLINE void print(FILE* f, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (!detail::use_utf8()) return detail::vprint_mojibake(f, fmt, vargs); + return detail::is_locking() ? vprint_buffered(f, fmt, vargs) + : vprint(f, fmt, vargs); +} + +/// Formats `args` according to specifications in `fmt` and writes the output +/// to the file `f` followed by a newline. +template +FMT_INLINE void println(FILE* f, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + return detail::use_utf8() ? vprintln(f, fmt, vargs) + : detail::vprint_mojibake(f, fmt, vargs, true); +} + +/// Formats `args` according to specifications in `fmt` and writes the output +/// to `stdout` followed by a newline. +template +FMT_INLINE void println(format_string fmt, T&&... args) { + return fmt::println(stdout, fmt, static_cast(args)...); +} + +FMT_END_EXPORT +FMT_GCC_PRAGMA("GCC pop_options") +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_BASE_H_ diff --git a/external/fmt/include/fmt/chrono.h b/external/fmt/include/fmt/chrono.h index 93cf376ed9..c93123fd33 100644 --- a/external/fmt/include/fmt/chrono.h +++ b/external/fmt/include/fmt/chrono.h @@ -8,16 +8,54 @@ #ifndef FMT_CHRONO_H_ #define FMT_CHRONO_H_ -#include -#include -#include -#include +#ifndef FMT_MODULE +# include +# include +# include // std::isfinite +# include // std::memcpy +# include +# include +# include +# include +# include +#endif #include "format.h" -#include "locale.h" FMT_BEGIN_NAMESPACE +// Check if std::chrono::local_t is available. +#ifndef FMT_USE_LOCAL_TIME +# ifdef __cpp_lib_chrono +# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) +# else +# define FMT_USE_LOCAL_TIME 0 +# endif +#endif + +// Check if std::chrono::utc_timestamp is available. +#ifndef FMT_USE_UTC_TIME +# ifdef __cpp_lib_chrono +# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) +# else +# define FMT_USE_UTC_TIME 0 +# endif +#endif + +// Enable tzset. +#ifndef FMT_USE_TZSET +// UWP doesn't provide _tzset. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# define FMT_USE_TZSET 1 +# else +# define FMT_USE_TZSET 0 +# endif +#endif + // Enable safe chrono durations, unless explicitly disabled. #ifndef FMT_SAFE_DURATION_CAST # define FMT_SAFE_DURATION_CAST 1 @@ -36,7 +74,8 @@ template ::value && std::numeric_limits::is_signed == std::numeric_limits::is_signed)> -FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { ec = 0; using F = std::numeric_limits; using T = std::numeric_limits; @@ -44,7 +83,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { static_assert(T::is_integer, "To must be integral"); // A and B are both signed, or both unsigned. - if (F::digits <= T::digits) { + if (detail::const_check(F::digits <= T::digits)) { // From fits in To without any problem. } else { // From does not always fit in To, resort to a dynamic check. @@ -57,62 +96,47 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { return static_cast(from); } -/** - * converts From to To, without loss. If the dynamic value of from - * can't be converted to To without loss, ec is set. - */ +/// Converts From to To, without loss. If the dynamic value of from +/// can't be converted to To without loss, ec is set. template ::value && std::numeric_limits::is_signed != std::numeric_limits::is_signed)> -FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { ec = 0; using F = std::numeric_limits; using T = std::numeric_limits; static_assert(F::is_integer, "From must be integral"); static_assert(T::is_integer, "To must be integral"); - if (F::is_signed && !T::is_signed) { + if (detail::const_check(F::is_signed && !T::is_signed)) { // From may be negative, not allowed! if (fmt::detail::is_negative(from)) { ec = 1; return {}; } - // From is positive. Can it always fit in To? - if (F::digits <= T::digits) { - // yes, From always fits in To. - } else { - // from may not fit in To, we have to do a dynamic check - if (from > static_cast((T::max)())) { - ec = 1; - return {}; - } + if (detail::const_check(F::digits > T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; } } - if (!F::is_signed && T::is_signed) { - // can from be held in To? - if (F::digits < T::digits) { - // yes, From always fits in To. - } else { - // from may not fit in To, we have to do a dynamic check - if (from > static_cast((T::max)())) { - // outside range. - ec = 1; - return {}; - } - } + if (detail::const_check(!F::is_signed && T::is_signed && + F::digits >= T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; } - - // reaching here means all is ok for lossless conversion. - return static_cast(from); - -} // function + return static_cast(from); // Lossless conversion. +} template ::value)> -FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { ec = 0; return from; } // function @@ -133,7 +157,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { // clang-format on template ::value)> -FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { +FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { ec = 0; using T = std::numeric_limits; static_assert(std::is_floating_point::value, "From must be floating"); @@ -155,20 +179,18 @@ FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { template ::value)> -FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { +FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { ec = 0; static_assert(std::is_floating_point::value, "From must be floating"); return from; } -/** - * safe duration cast between integral durations - */ +/// Safe duration cast between integral durations template ::value), FMT_ENABLE_IF(std::is_integral::value)> -To safe_duration_cast(std::chrono::duration from, - int& ec) { +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { using From = std::chrono::duration; ec = 0; // the basic idea is that we need to convert from count() in the from type @@ -190,11 +212,9 @@ To safe_duration_cast(std::chrono::duration from, // safe conversion to IntermediateRep IntermediateRep count = lossless_integral_conversion(from.count(), ec); - if (ec) { - return {}; - } + if (ec) return {}; // multiply with Factor::num without overflow or underflow - if (Factor::num != 1) { + if (detail::const_check(Factor::num != 1)) { const auto max1 = detail::max_value() / Factor::num; if (count > max1) { ec = 1; @@ -202,34 +222,25 @@ To safe_duration_cast(std::chrono::duration from, } const auto min1 = (std::numeric_limits::min)() / Factor::num; - if (count < min1) { + if (detail::const_check(!std::is_unsigned::value) && + count < min1) { ec = 1; return {}; } count *= Factor::num; } - // this can't go wrong, right? den>0 is checked earlier. - if (Factor::den != 1) { - count /= Factor::den; - } - // convert to the to type, safely - using ToRep = typename To::rep; - const ToRep tocount = lossless_integral_conversion(count, ec); - if (ec) { - return {}; - } - return To{tocount}; + if (detail::const_check(Factor::den != 1)) count /= Factor::den; + auto tocount = lossless_integral_conversion(count, ec); + return ec ? To() : To(tocount); } -/** - * safe duration_cast between floating point durations - */ +/// Safe duration_cast between floating point durations template ::value), FMT_ENABLE_IF(std::is_floating_point::value)> -To safe_duration_cast(std::chrono::duration from, - int& ec) { +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { using From = std::chrono::duration; ec = 0; if (std::isnan(from.count())) { @@ -269,7 +280,7 @@ To safe_duration_cast(std::chrono::duration from, } // multiply with Factor::num without overflow or underflow - if (Factor::num != 1) { + if (detail::const_check(Factor::num != 1)) { constexpr auto max1 = detail::max_value() / static_cast(Factor::num); if (count > max1) { @@ -286,7 +297,7 @@ To safe_duration_cast(std::chrono::duration from, } // this can't go wrong, right? den>0 is checked earlier. - if (Factor::den != 1) { + if (detail::const_check(Factor::den != 1)) { using common_t = typename std::common_type::type; count /= static_cast(Factor::den); } @@ -308,38 +319,228 @@ To safe_duration_cast(std::chrono::duration from, #define FMT_NOMACRO namespace detail { -inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } -inline null<> localtime_s(...) { return null<>(); } -inline null<> gmtime_r(...) { return null<>(); } -inline null<> gmtime_s(...) { return null<>(); } +template struct null {}; +inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); } +inline auto localtime_s(...) -> null<> { return null<>(); } +inline auto gmtime_r(...) -> null<> { return null<>(); } +inline auto gmtime_s(...) -> null<> { return null<>(); } + +// It is defined here and not in ostream.h because the latter has expensive +// includes. +template class formatbuf : public Streambuf { + private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; + + buffer& buffer_; + + public: + explicit formatbuf(buffer& buf) : buffer_(buf) {} + + protected: + // The put area is always empty. This makes the implementation simpler and has + // the advantage that the streambuf and the buffer are always in sync and + // sputc never writes into uninitialized memory. A disadvantage is that each + // call to sputc always results in a (virtual) call to overflow. There is no + // disadvantage here for sputn since this always results in a call to xsputn. + + auto overflow(int_type ch) -> int_type override { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type* s, streamsize count) -> streamsize override { + buffer_.append(s, s + count); + return count; + } +}; + +inline auto get_classic_locale() -> const std::locale& { + static const auto& locale = std::locale::classic(); + return locale; +} + +template struct codecvt_result { + static constexpr const size_t max_size = 32; + CodeUnit buf[max_size]; + CodeUnit* end; +}; + +template +void write_codecvt(codecvt_result& out, string_view in_buf, + const std::locale& loc) { +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet>(loc); +# pragma clang diagnostic pop +#else + auto& f = std::use_facet>(loc); +#endif + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, + std::begin(out.buf), std::end(out.buf), out.end); + if (result != std::codecvt_base::ok) + FMT_THROW(format_error("failed to format time")); +} + +template +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { + if (detail::use_utf8() && loc != get_classic_locale()) { + // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and + // gcc-4. +#if FMT_MSC_VERSION != 0 || \ + (defined(__GLIBCXX__) && \ + (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0)) + // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 + // and newer. + using code_unit = wchar_t; +#else + using code_unit = char32_t; +#endif + + using unit_t = codecvt_result; + unit_t unit; + write_codecvt(unit, in, loc); + // In UTF-8 is used one to four one-byte code units. + auto u = + to_utf8>(); + if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)})) + FMT_THROW(format_error("failed to format time")); + return copy(u.c_str(), u.c_str() + u.size(), out); + } + return copy(in.data(), in.data() + in.size(), out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + codecvt_result unit; + write_codecvt(unit, sv, loc); + return copy(unit.buf, unit.end, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + return write_encoded_tm_str(out, sv, loc); +} + +template +inline void do_write(buffer& buf, const std::tm& time, + const std::locale& loc, char format, char modifier) { + auto&& format_buf = formatbuf>(buf); + auto&& os = std::basic_ostream(&format_buf); + os.imbue(loc); + const auto& facet = std::use_facet>(loc); + auto end = facet.put(os, os, Char(' '), &time, format, modifier); + if (end.failed()) FMT_THROW(format_error("failed to format time")); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = get_buffer(out); + do_write(buf, time, loc, format, modifier); + return get_iterator(buf, out); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = basic_memory_buffer(); + do_write(buf, time, loc, format, modifier); + return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); +} + +template +struct is_same_arithmetic_type + : public std::integral_constant::value && + std::is_integral::value) || + (std::is_floating_point::value && + std::is_floating_point::value)> { +}; + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(is_same_arithmetic_type::value)> +auto fmt_duration_cast(std::chrono::duration from) -> To { +#if FMT_SAFE_DURATION_CAST + // Throwing version of safe_duration_cast is only available for + // integer to integer or float to float casts. + int ec; + To to = safe_duration_cast::safe_duration_cast(from, ec); + if (ec) FMT_THROW(format_error("cannot format duration")); + return to; +#else + // Standard duration cast, may overflow. + return std::chrono::duration_cast(from); +#endif +} + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(!is_same_arithmetic_type::value)> +auto fmt_duration_cast(std::chrono::duration from) -> To { + // Mixed integer <-> float cast is not supported by safe_duration_cast. + return std::chrono::duration_cast(from); +} + +template +auto to_time_t( + std::chrono::time_point time_point) + -> std::time_t { + // Cannot use std::chrono::system_clock::to_time_t since this would first + // require a cast to std::chrono::system_clock::time_point, which could + // overflow. + return fmt_duration_cast>( + time_point.time_since_epoch()) + .count(); +} } // namespace detail -// Thread-safe replacement for std::localtime -inline std::tm localtime(std::time_t time) { +FMT_BEGIN_EXPORT + +/** + * Converts given time since epoch as `std::time_t` value into calendar time, + * expressed in local time. Unlike `std::localtime`, this function is + * thread-safe on most platforms. + */ +inline auto localtime(std::time_t time) -> std::tm { struct dispatcher { std::time_t time_; - std::tm tm_{}; + std::tm tm_; dispatcher(std::time_t t) : time_(t) {} - bool run() { + auto run() -> bool { using namespace fmt::detail; return handle(localtime_r(&time_, &tm_)); } - bool handle(std::tm* tm) { return tm != nullptr; } + auto handle(std::tm* tm) -> bool { return tm != nullptr; } - bool handle(detail::null<>) { + auto handle(detail::null<>) -> bool { using namespace fmt::detail; return fallback(localtime_s(&tm_, &time_)); } - bool fallback(int res) { return res == 0; } + auto fallback(int res) -> bool { return res == 0; } -#if !FMT_MSC_VER - bool fallback(detail::null<>) { +#if !FMT_MSC_VERSION + auto fallback(detail::null<>) -> bool { using namespace fmt::detail; - std::tm* tm = std::localtime(&time_); // lgtm[cpp/potentially-dangerous-function] + std::tm* tm = std::localtime(&time_); if (tm) tm_ = *tm; return tm != nullptr; } @@ -351,121 +552,121 @@ inline std::tm localtime(std::time_t time) { return lt.tm_; } -// Thread-safe replacement for std::gmtime -inline std::tm gmtime(std::time_t time) { +#if FMT_USE_LOCAL_TIME +template +inline auto localtime(std::chrono::local_time time) -> std::tm { + return localtime( + detail::to_time_t(std::chrono::current_zone()->to_sys(time))); +} +#endif + +/** + * Converts given time since epoch as `std::time_t` value into calendar time, + * expressed in Coordinated Universal Time (UTC). Unlike `std::gmtime`, this + * function is thread-safe on most platforms. + */ +inline auto gmtime(std::time_t time) -> std::tm { struct dispatcher { std::time_t time_; std::tm tm_; dispatcher(std::time_t t) : time_(t) {} - bool run() { + auto run() -> bool { using namespace fmt::detail; return handle(gmtime_r(&time_, &tm_)); } - bool handle(std::tm* tm) { return tm != nullptr; } + auto handle(std::tm* tm) -> bool { return tm != nullptr; } - bool handle(detail::null<>) { + auto handle(detail::null<>) -> bool { using namespace fmt::detail; return fallback(gmtime_s(&tm_, &time_)); } - bool fallback(int res) { return res == 0; } + auto fallback(int res) -> bool { return res == 0; } -#if !FMT_MSC_VER - bool fallback(detail::null<>) { - std::tm* tm = std::gmtime(&time_); // lgtm[cpp/potentially-dangerous-function] +#if !FMT_MSC_VERSION + auto fallback(detail::null<>) -> bool { + std::tm* tm = std::gmtime(&time_); if (tm) tm_ = *tm; return tm != nullptr; } #endif }; - dispatcher gt(time); + auto gt = dispatcher(time); // Too big time values may be unsupported. if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); return gt.tm_; } -namespace detail { -inline size_t strftime(char* str, size_t count, const char* format, - const std::tm* time) { - return std::strftime(str, count, format, time); -} - -inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format, - const std::tm* time) { - return std::wcsftime(str, count, format, time); +template +inline auto gmtime( + std::chrono::time_point time_point) + -> std::tm { + return gmtime(detail::to_time_t(time_point)); } -} // namespace detail -template struct formatter { - template - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto it = ctx.begin(); - if (it != ctx.end() && *it == ':') ++it; - auto end = it; - while (end != ctx.end() && *end != '}') ++end; - tm_format.reserve(detail::to_unsigned(end - it + 1)); - tm_format.append(it, end); - tm_format.push_back('\0'); - return end; - } +namespace detail { - template - auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) { - basic_memory_buffer buf; - size_t start = buf.size(); - for (;;) { - size_t size = buf.capacity() - start; - size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm); - if (count != 0) { - buf.resize(start + count); - break; - } - if (size >= tm_format.size() * 256) { - // If the buffer is 256 times larger than the format string, assume - // that `strftime` gives an empty result. There doesn't seem to be a - // better way to distinguish the two cases: - // https://github.com/fmtlib/fmt/issues/367 - break; - } - const size_t MIN_GROWTH = 10; - buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - return std::copy(buf.begin(), buf.end(), ctx.out()); +// Writes two-digit numbers a, b and c separated by sep to buf. +// The method by Pavel Novikov based on +// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +inline void write_digit2_separated(char* buf, unsigned a, unsigned b, + unsigned c, char sep) { + unsigned long long digits = + a | (b << 24) | (static_cast(c) << 48); + // Convert each value to BCD. + // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. + // The difference is + // y - x = a * 6 + // a can be found from x: + // a = floor(x / 10) + // then + // y = x + a * 6 = x + floor(x / 10) * 6 + // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). + digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; + // Put low nibbles to high bytes and high nibbles to low bytes. + digits = ((digits & 0x00f00000f00000f0) >> 4) | + ((digits & 0x000f00000f00000f) << 8); + auto usep = static_cast(sep); + // Add ASCII '0' to each digit byte and insert separators. + digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); + + constexpr const size_t len = 8; + if (const_check(is_big_endian())) { + char tmp[len]; + std::memcpy(tmp, &digits, len); + std::reverse_copy(tmp, tmp + len, buf); + } else { + std::memcpy(buf, &digits, len); } +} - basic_memory_buffer tm_format; -}; - -namespace detail { -template FMT_CONSTEXPR const char* get_units() { +template +FMT_CONSTEXPR inline auto get_units() -> const char* { + if (std::is_same::value) return "as"; + if (std::is_same::value) return "fs"; + if (std::is_same::value) return "ps"; + if (std::is_same::value) return "ns"; + if (std::is_same::value) return "µs"; + if (std::is_same::value) return "ms"; + if (std::is_same::value) return "cs"; + if (std::is_same::value) return "ds"; + if (std::is_same>::value) return "s"; + if (std::is_same::value) return "das"; + if (std::is_same::value) return "hs"; + if (std::is_same::value) return "ks"; + if (std::is_same::value) return "Ms"; + if (std::is_same::value) return "Gs"; + if (std::is_same::value) return "Ts"; + if (std::is_same::value) return "Ps"; + if (std::is_same::value) return "Es"; + if (std::is_same>::value) return "min"; + if (std::is_same>::value) return "h"; + if (std::is_same>::value) return "d"; return nullptr; } -template <> FMT_CONSTEXPR const char* get_units() { return "as"; } -template <> FMT_CONSTEXPR const char* get_units() { return "fs"; } -template <> FMT_CONSTEXPR const char* get_units() { return "ps"; } -template <> FMT_CONSTEXPR const char* get_units() { return "ns"; } -template <> FMT_CONSTEXPR const char* get_units() { return "µs"; } -template <> FMT_CONSTEXPR const char* get_units() { return "ms"; } -template <> FMT_CONSTEXPR const char* get_units() { return "cs"; } -template <> FMT_CONSTEXPR const char* get_units() { return "ds"; } -template <> FMT_CONSTEXPR const char* get_units>() { return "s"; } -template <> FMT_CONSTEXPR const char* get_units() { return "das"; } -template <> FMT_CONSTEXPR const char* get_units() { return "hs"; } -template <> FMT_CONSTEXPR const char* get_units() { return "ks"; } -template <> FMT_CONSTEXPR const char* get_units() { return "Ms"; } -template <> FMT_CONSTEXPR const char* get_units() { return "Gs"; } -template <> FMT_CONSTEXPR const char* get_units() { return "Ts"; } -template <> FMT_CONSTEXPR const char* get_units() { return "Ps"; } -template <> FMT_CONSTEXPR const char* get_units() { return "Es"; } -template <> FMT_CONSTEXPR const char* get_units>() { - return "m"; -} -template <> FMT_CONSTEXPR const char* get_units>() { - return "h"; -} enum class numeric_system { standard, @@ -473,13 +674,37 @@ enum class numeric_system { alternative }; +// Glibc extensions for formatting numeric values. +enum class pad_type { + // Pad a numeric result string with zeros (the default). + zero, + // Do not pad a numeric result string. + none, + // Pad a numeric result string with spaces. + space, +}; + +template +auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt { + if (pad == pad_type::none) return out; + return detail::fill_n(out, width, pad == pad_type::space ? ' ' : '0'); +} + +template +auto write_padding(OutputIt out, pad_type pad) -> OutputIt { + if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0'; + return out; +} + // Parses a put_time-like format string and invokes handler actions. template -FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, - const Char* end, - Handler&& handler) { +FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + if (begin == end || *begin == '}') return begin; + if (*begin != '%') FMT_THROW(format_error("invalid format")); auto ptr = begin; while (ptr != end) { + pad_type pad = pad_type::zero; auto c = *ptr; if (c == '}') break; if (c != '%') { @@ -489,6 +714,18 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (begin != ptr) handler.on_text(begin, ptr); ++ptr; // consume '%' if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr; + switch (c) { + case '_': + pad = pad_type::space; + ++ptr; + break; + case '-': + pad = pad_type::none; + ++ptr; + break; + } + if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { case '%': @@ -504,6 +741,22 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, handler.on_text(tab, tab + 1); break; } + // Year: + case 'Y': + handler.on_year(numeric_system::standard); + break; + case 'y': + handler.on_short_year(numeric_system::standard); + break; + case 'C': + handler.on_century(numeric_system::standard); + break; + case 'G': + handler.on_iso_week_based_year(); + break; + case 'g': + handler.on_iso_week_based_short_year(); + break; // Day of the week: case 'a': handler.on_abbr_weekday(); @@ -519,23 +772,46 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, break; // Month: case 'b': + case 'h': handler.on_abbr_month(); break; case 'B': handler.on_full_month(); break; + case 'm': + handler.on_dec_month(numeric_system::standard); + break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard, pad); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard, pad); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::standard, pad); + break; + case 'j': + handler.on_day_of_year(); + break; + case 'd': + handler.on_day_of_month(numeric_system::standard, pad); + break; + case 'e': + handler.on_day_of_month(numeric_system::standard, pad_type::space); + break; // Hour, minute, second: case 'H': - handler.on_24_hour(numeric_system::standard); + handler.on_24_hour(numeric_system::standard, pad); break; case 'I': - handler.on_12_hour(numeric_system::standard); + handler.on_12_hour(numeric_system::standard, pad); break; case 'M': - handler.on_minute(numeric_system::standard); + handler.on_minute(numeric_system::standard, pad); break; case 'S': - handler.on_second(numeric_system::standard); + handler.on_second(numeric_system::standard, pad); break; // Other: case 'c': @@ -572,7 +848,7 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, handler.on_duration_unit(); break; case 'z': - handler.on_utc_offset(); + handler.on_utc_offset(numeric_system::standard); break; case 'Z': handler.on_tz_name(); @@ -582,6 +858,15 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { + case 'Y': + handler.on_year(numeric_system::alternative); + break; + case 'y': + handler.on_offset_year(); + break; + case 'C': + handler.on_century(numeric_system::alternative); + break; case 'c': handler.on_datetime(numeric_system::alternative); break; @@ -591,6 +876,9 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, case 'X': handler.on_loc_time(numeric_system::alternative); break; + case 'z': + handler.on_utc_offset(numeric_system::alternative); + break; default: FMT_THROW(format_error("invalid format")); } @@ -600,6 +888,27 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { + case 'y': + handler.on_short_year(numeric_system::alternative); + break; + case 'm': + handler.on_dec_month(numeric_system::alternative); + break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative, pad); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative, pad); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative, pad); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative, pad); + break; + case 'e': + handler.on_day_of_month(numeric_system::alternative, pad_type::space); + break; case 'w': handler.on_dec0_weekday(numeric_system::alternative); break; @@ -607,16 +916,19 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, handler.on_dec1_weekday(numeric_system::alternative); break; case 'H': - handler.on_24_hour(numeric_system::alternative); + handler.on_24_hour(numeric_system::alternative, pad); break; case 'I': - handler.on_12_hour(numeric_system::alternative); + handler.on_12_hour(numeric_system::alternative, pad); break; case 'M': - handler.on_minute(numeric_system::alternative); + handler.on_minute(numeric_system::alternative, pad); break; case 'S': - handler.on_second(numeric_system::alternative); + handler.on_second(numeric_system::alternative, pad); + break; + case 'z': + handler.on_utc_offset(numeric_system::alternative); break; default: FMT_THROW(format_error("invalid format")); @@ -631,75 +943,747 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, return ptr; } -struct chrono_format_checker { - FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); } - - template void on_text(const Char*, const Char*) {} - FMT_NORETURN void on_abbr_weekday() { report_no_date(); } - FMT_NORETURN void on_full_weekday() { report_no_date(); } - FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); } - FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); } - FMT_NORETURN void on_abbr_month() { report_no_date(); } - FMT_NORETURN void on_full_month() { report_no_date(); } - void on_24_hour(numeric_system) {} - void on_12_hour(numeric_system) {} - void on_minute(numeric_system) {} - void on_second(numeric_system) {} - FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); } - FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); } - FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); } - FMT_NORETURN void on_us_date() { report_no_date(); } - FMT_NORETURN void on_iso_date() { report_no_date(); } - void on_12_hour_time() {} - void on_24_hour_time() {} - void on_iso_time() {} - void on_am_pm() {} - void on_duration_value() {} - void on_duration_unit() {} - FMT_NORETURN void on_utc_offset() { report_no_date(); } - FMT_NORETURN void on_tz_name() { report_no_date(); } +template struct null_chrono_spec_handler { + FMT_CONSTEXPR void unsupported() { + static_cast(this)->unsupported(); + } + FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_offset_year() { unsupported(); } + FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } + FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } + FMT_CONSTEXPR void on_full_weekday() { unsupported(); } + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_abbr_month() { unsupported(); } + FMT_CONSTEXPR void on_full_month() { unsupported(); } + FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_day_of_year() { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_us_date() { unsupported(); } + FMT_CONSTEXPR void on_iso_date() { unsupported(); } + FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_iso_time() { unsupported(); } + FMT_CONSTEXPR void on_am_pm() { unsupported(); } + FMT_CONSTEXPR void on_duration_value() { unsupported(); } + FMT_CONSTEXPR void on_duration_unit() { unsupported(); } + FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_tz_name() { unsupported(); } }; -template ::value)> -inline bool isnan(T) { - return false; +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_year(numeric_system) {} + FMT_CONSTEXPR void on_short_year(numeric_system) {} + FMT_CONSTEXPR void on_offset_year() {} + FMT_CONSTEXPR void on_century(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_based_year() {} + FMT_CONSTEXPR void on_iso_week_based_short_year() {} + FMT_CONSTEXPR void on_abbr_weekday() {} + FMT_CONSTEXPR void on_full_weekday() {} + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} + FMT_CONSTEXPR void on_abbr_month() {} + FMT_CONSTEXPR void on_full_month() {} + FMT_CONSTEXPR void on_dec_month(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_datetime(numeric_system) {} + FMT_CONSTEXPR void on_loc_date(numeric_system) {} + FMT_CONSTEXPR void on_loc_time(numeric_system) {} + FMT_CONSTEXPR void on_us_date() {} + FMT_CONSTEXPR void on_iso_date() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_utc_offset(numeric_system) {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline auto tm_wday_full_name(int wday) -> const char* { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; } -template ::value)> -inline bool isnan(T value) { - return std::isnan(value); +inline auto tm_wday_short_name(int wday) -> const char* { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; } -template ::value)> -inline bool isfinite(T) { - return true; +inline auto tm_mon_full_name(int mon) -> const char* { + static constexpr const char* full_name_list[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; } -template ::value)> -inline bool isfinite(T value) { - return std::isfinite(value); +inline auto tm_mon_short_name(int mon) -> const char* { + static constexpr const char* short_name_list[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; } -// Converts value to int and checks that it's in the range [0, upper). -template ::value)> -inline int to_nonnegative_int(T value, int upper) { - FMT_ASSERT(value >= 0 && value <= upper, "invalid value"); - (void)upper; - return static_cast(value); +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + +#if FMT_USE_TZSET +inline void tzset_once() { + static bool init = []() -> bool { + _tzset(); + return true; + }(); + ignore_unused(init); } -template ::value)> -inline int to_nonnegative_int(T value, int upper) { - FMT_ASSERT( - std::isnan(value) || (value >= 0 && value <= static_cast(upper)), - "invalid value"); - (void)upper; - return static_cast(value); +#endif + +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + if (!std::is_unsigned::value && + (value < 0 || to_unsigned(value) > to_unsigned(upper))) { + FMT_THROW(fmt::format_error("chrono value is out of range")); + } + return static_cast(value); +} +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + auto int_value = static_cast(value); + if (int_value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return int_value; +} + +constexpr auto pow10(std::uint32_t n) -> long long { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +// Counts the number of fractional digits in the range [0, 18] according to the +// C++20 spec. If more than 18 fractional digits are required then returns 6 for +// microseconds precision. +template () / 10)> +struct count_fractional_digits { + static constexpr int value = + Num % Den == 0 ? N : count_fractional_digits::value; +}; + +// Base case that doesn't instantiate any more templates +// in order to avoid overflow. +template +struct count_fractional_digits { + static constexpr int value = (Num % Den == 0) ? N : 6; +}; + +// Format subseconds which are given as an integer type with an appropriate +// number of digits. +template +void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { + constexpr auto num_fractional_digits = + count_fractional_digits::value; + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, detail::pow10(num_fractional_digits)>>; + + const auto fractional = d - fmt_duration_cast(d); + const auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : fmt_duration_cast(fractional).count(); + auto n = static_cast>(subseconds); + const int num_digits = detail::count_digits(n); + + int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits); + if (precision < 0) { + FMT_ASSERT(!std::is_floating_point::value, ""); + if (std::ratio_less::value) { + *out++ = '.'; + out = detail::fill_n(out, leading_zeroes, '0'); + out = format_decimal(out, n, num_digits).end; + } + } else if (precision > 0) { + *out++ = '.'; + leading_zeroes = (std::min)(leading_zeroes, precision); + int remaining = precision - leading_zeroes; + out = detail::fill_n(out, leading_zeroes, '0'); + if (remaining < num_digits) { + int num_truncated_digits = num_digits - remaining; + n /= to_unsigned(detail::pow10(to_unsigned(num_truncated_digits))); + if (n) { + out = format_decimal(out, n, remaining).end; + } + return; + } + if (n) { + out = format_decimal(out, n, num_digits).end; + remaining -= num_digits; + } + out = detail::fill_n(out, remaining, '0'); + } +} + +// Format subseconds which are given as a floating point type with an +// appropriate number of digits. We cannot pass the Duration here, as we +// explicitly need to pass the Rep value in the chrono_formatter. +template +void write_floating_seconds(memory_buffer& buf, Duration duration, + int num_fractional_digits = -1) { + using rep = typename Duration::rep; + FMT_ASSERT(std::is_floating_point::value, ""); + + auto val = duration.count(); + + if (num_fractional_digits < 0) { + // For `std::round` with fallback to `round`: + // On some toolchains `std::round` is not available (e.g. GCC 6). + using namespace std; + num_fractional_digits = + count_fractional_digits::value; + if (num_fractional_digits < 6 && static_cast(round(val)) != val) + num_fractional_digits = 6; + } + + fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"), + std::fmod(val * static_cast(Duration::period::num) / + static_cast(Duration::period::den), + static_cast(60)), + num_fractional_digits); +} + +template +class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const Duration* subsecs_; + const std::tm& tm_; + + auto tm_sec() const noexcept -> int { + FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); + return tm_.tm_sec; + } + auto tm_min() const noexcept -> int { + FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); + return tm_.tm_min; + } + auto tm_hour() const noexcept -> int { + FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); + return tm_.tm_hour; + } + auto tm_mday() const noexcept -> int { + FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); + return tm_.tm_mday; + } + auto tm_mon() const noexcept -> int { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); + return tm_.tm_mon; + } + auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } + auto tm_wday() const noexcept -> int { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); + return tm_.tm_wday; + } + auto tm_yday() const noexcept -> int { + FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); + return tm_.tm_yday; + } + + auto tm_hour12() const noexcept -> int { + const auto h = tm_hour(); + const auto z = h < 12 ? h : h - 12; + return z == 0 ? 12 : z; + } + + // POSIX and the C Standard are unclear or inconsistent about what %C and %y + // do if the year is negative or exceeds 9999. Use the convention that %C + // concatenated with %y yields the same output as %Y, and that %Y contains at + // least 4 characters, with more only if necessary. + auto split_year_lower(long long year) const noexcept -> int { + auto l = year % 100; + if (l < 0) l = -l; // l in [0, 99] + return static_cast(l); + } + + // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date. + auto iso_year_weeks(long long curr_year) const noexcept -> int { + const auto prev_year = curr_year - 1; + const auto curr_p = + (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % + days_per_week; + const auto prev_p = + (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % + days_per_week; + return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); + } + auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { + return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / + days_per_week; + } + auto tm_iso_week_year() const noexcept -> long long { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return year - 1; + if (w > iso_year_weeks(year)) return year + 1; + return year; + } + auto tm_iso_week_of_year() const noexcept -> int { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return iso_year_weeks(year - 1); + if (w > iso_year_weeks(year)) return 1; + return w; + } + + void write1(int value) { + *out_++ = static_cast('0' + to_unsigned(value) % 10); + } + void write2(int value) { + const char* d = digits2(to_unsigned(value) % 100); + *out_++ = *d++; + *out_++ = *d; + } + void write2(int value, pad_type pad) { + unsigned int v = to_unsigned(value) % 100; + if (v >= 10) { + const char* d = digits2(v); + *out_++ = *d++; + *out_++ = *d; + } else { + out_ = detail::write_padding(out_, pad); + *out_++ = static_cast('0' + v); + } + } + + void write_year_extended(long long year) { + // At least 4 characters. + int width = 4; + if (year < 0) { + *out_++ = '-'; + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (width > num_digits) + out_ = detail::fill_n(out_, width - num_digits, '0'); + out_ = format_decimal(out_, n, num_digits).end; + } + void write_year(long long year) { + if (year >= 0 && year < 10000) { + write2(static_cast(year / 100)); + write2(static_cast(year % 100)); + } else { + write_year_extended(year); + } + } + + void write_utc_offset(long offset, numeric_system ns) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + if (ns != numeric_system::standard) *out_++ = ':'; + write2(static_cast(offset % 60)); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { + write_utc_offset(tm.tm_gmtoff, ns); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { +#if defined(_WIN32) && defined(_UCRT) +# if FMT_USE_TZSET + tzset_once(); +# endif + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset, ns); +#else + if (ns == numeric_system::standard) return format_localized('z'); + + // Extract timezone offset from timezone conversion functions. + std::tm gtm = tm; + std::time_t gt = std::mktime(>m); + std::tm ltm = gmtime(gt); + std::time_t lt = std::mktime(<m); + long offset = gt - lt; + write_utc_offset(offset, ns); +#endif + } + + template ::value)> + void format_tz_name_impl(const T& tm) { + if (is_classic_) + out_ = write_tm_str(out_, tm.tm_zone, loc_); + else + format_localized('Z'); + } + template ::value)> + void format_tz_name_impl(const T&) { + format_localized('Z'); + } + + void format_localized(char format, char modifier = 0) { + out_ = write(out_, tm_, loc_, format, modifier); + } + + public: + tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm, + const Duration* subsecs = nullptr) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + subsecs_(subsecs), + tm_(tm) {} + + auto out() const -> OutputIt { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy(begin, end, out_); + } + + void on_abbr_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_short_name(tm_wday())); + else + format_localized('a'); + } + void on_full_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_full_name(tm_wday())); + else + format_localized('A'); + } + void on_dec0_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); + format_localized('w', 'O'); + } + void on_dec1_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write1(wday == 0 ? days_per_week : wday); + } else { + format_localized('u', 'O'); + } + } + + void on_abbr_month() { + if (is_classic_) + out_ = write(out_, tm_mon_short_name(tm_mon())); + else + format_localized('b'); + } + void on_full_month() { + if (is_classic_) + out_ = write(out_, tm_mon_full_name(tm_mon())); + else + format_localized('B'); + } + + void on_datetime(numeric_system ns) { + if (is_classic_) { + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month(numeric_system::standard, pad_type::space); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); + } else { + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + } + } + void on_loc_date(numeric_system ns) { + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_loc_time(numeric_system ns) { + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_us_date() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_mon() + 1), + to_unsigned(tm_mday()), + to_unsigned(split_year_lower(tm_year())), '/'); + out_ = copy(std::begin(buf), std::end(buf), out_); + } + void on_iso_date() { + auto year = tm_year(); + char buf[10]; + size_t offset = 0; + if (year >= 0 && year < 10000) { + copy2(buf, digits2(static_cast(year / 100))); + } else { + offset = 4; + write_year_extended(year); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year()); + format_localized('Y', 'E'); + } + void on_short_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(split_year_lower(tm_year())); + format_localized('y', 'O'); + } + void on_offset_year() { + if (is_classic_) return write2(split_year_lower(tm_year())); + format_localized('y', 'E'); + } + + void on_century(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto year = tm_year(); + auto upper = year / 100; + if (year >= -99 && year < 0) { + // Zero upper on negative year. + *out_++ = '-'; + *out_++ = '0'; + } else if (upper >= 0 && upper < 100) { + write2(static_cast(upper)); + } else { + out_ = write(out_, upper); + } + } else { + format_localized('C', 'E'); + } + } + + void on_dec_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, + pad); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write2((tm_yday() + days_per_week - + (wday == 0 ? (days_per_week - 1) : (wday - 1))) / + days_per_week, + pad); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year(), pad); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { write_year(tm_iso_week_year()); } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year() { + auto yday = tm_yday() + 1; + write1(yday / 100); + write2(yday % 100); + } + void on_day_of_month(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mday(), pad); + format_localized('d', 'O'); + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour(), pad); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12(), pad); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_min(), pad); + format_localized('M', 'O'); + } + + void on_second(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) { + write2(tm_sec(), pad); + if (subsecs_) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, *subsecs_); + if (buf.size() > 1) { + // Remove the leading "0", write something like ".123". + out_ = std::copy(buf.begin() + 1, buf.end(), out_); + } + } else { + write_fractional_seconds(out_, *subsecs_); + } + } + } else { + // Currently no formatting of subseconds when a locale is set. + format_localized('S', 'O'); + } + } + + void on_12_hour_time() { + if (is_classic_) { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); + out_ = copy(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); + } else { + format_localized('r'); + } + } + void on_24_hour_time() { + write2(tm_hour()); + *out_++ = ':'; + write2(tm_min()); + } + void on_iso_time() { + on_24_hour_time(); + *out_++ = ':'; + on_second(numeric_system::standard, pad_type::zero); + } + + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_hour() < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else { + format_localized('p'); + } + } + + // These apply to chrono durations but not tm. + void on_duration_value() {} + void on_duration_unit() {} +}; + +struct chrono_format_checker : null_chrono_spec_handler { + bool has_precision_integral = false; + + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_duration_value() const { + if (has_precision_integral) { + FMT_THROW(format_error("precision not allowed for this argument type")); + } + } + FMT_CONSTEXPR void on_duration_unit() {} +}; + +template ::value&& has_isfinite::value)> +inline auto isfinite(T) -> bool { + return true; } template ::value)> -inline T mod(T x, int y) { +inline auto mod(T x, int y) -> T { return x % static_cast(y); } template ::value)> -inline T mod(T x, int y) { +inline auto mod(T x, int y) -> T { return std::fmod(x, static_cast(y)); } @@ -714,67 +1698,52 @@ template struct make_unsigned_or_unchanged { using type = typename std::make_unsigned::type; }; -#if FMT_SAFE_DURATION_CAST -// throwing version of safe_duration_cast -template -To fmt_safe_duration_cast(std::chrono::duration from) { - int ec; - To to = safe_duration_cast::safe_duration_cast(from, ec); - if (ec) FMT_THROW(format_error("cannot format duration")); - return to; -} -#endif - template ::value)> -inline std::chrono::duration get_milliseconds( - std::chrono::duration d) { +inline auto get_milliseconds(std::chrono::duration d) + -> std::chrono::duration { // this may overflow and/or the result may not fit in the // target type. #if FMT_SAFE_DURATION_CAST using CommonSecondsType = typename std::common_type::type; - const auto d_as_common = fmt_safe_duration_cast(d); + const auto d_as_common = fmt_duration_cast(d); const auto d_as_whole_seconds = - fmt_safe_duration_cast(d_as_common); + fmt_duration_cast(d_as_common); // this conversion should be nonproblematic const auto diff = d_as_common - d_as_whole_seconds; const auto ms = - fmt_safe_duration_cast>(diff); + fmt_duration_cast>(diff); return ms; #else - auto s = std::chrono::duration_cast(d); - return std::chrono::duration_cast(d - s); + auto s = fmt_duration_cast(d); + return fmt_duration_cast(d - s); #endif } -template ::value)> -inline std::chrono::duration get_milliseconds( - std::chrono::duration d) { - using common_type = typename std::common_type::type; - auto ms = mod(d.count() * static_cast(Period::num) / - static_cast(Period::den) * 1000, - 1000); - return std::chrono::duration(static_cast(ms)); +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt { + return write(out, val); } -template -OutputIt format_duration_value(OutputIt out, Rep val, int precision) { - const Char pr_f[] = {'{', ':', '.', '{', '}', 'f', '}', 0}; - if (precision >= 0) return format_to(out, pr_f, val, precision); - const Char fp_f[] = {'{', ':', 'g', '}', 0}; - const Char format[] = {'{', '}', 0}; - return format_to(out, std::is_floating_point::value ? fp_f : format, - val); +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt { + auto specs = format_specs(); + specs.precision = precision; + specs.type = + precision >= 0 ? presentation_type::fixed : presentation_type::general; + return write(out, val, specs); } + template -OutputIt copy_unit(string_view unit, OutputIt out, Char) { +auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt { return std::copy(unit.begin(), unit.end(), out); } template -OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) { +auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt { // This works when wchar_t is UTF-32 because units only contain characters // that have the same representation in UTF-16 and UTF-32. utf8_to_utf16 u(unit); @@ -782,21 +1751,49 @@ OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) { } template -OutputIt format_duration_unit(OutputIt out) { +auto format_duration_unit(OutputIt out) -> OutputIt { if (const char* unit = get_units()) return copy_unit(string_view(unit), out, Char()); - const Char num_f[] = {'[', '{', '}', ']', 's', 0}; - if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num); - const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0}; - return format_to(out, num_def_f, Period::num, Period::den); + *out++ = '['; + out = write(out, Period::num); + if (const_check(Period::den != 1)) { + *out++ = '/'; + out = write(out, Period::den); + } + *out++ = ']'; + *out++ = 's'; + return out; } +class get_locale { + private: + union { + std::locale locale_; + }; + bool has_locale_ = false; + + public: + get_locale(bool localized, locale_ref loc) : has_locale_(localized) { +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR + if (localized) + ::new (&locale_) std::locale(loc.template get()); +#endif + } + ~get_locale() { + if (has_locale_) locale_.~locale(); + } + operator const std::locale&() const { + return has_locale_ ? locale_ : get_classic_locale(); + } +}; + template struct chrono_formatter { FormatContext& context; OutputIt out; int precision; + bool localized = false; // rep is unsigned to avoid overflow. using rep = conditional_t::value && sizeof(Rep) < sizeof(int), @@ -808,9 +1805,10 @@ struct chrono_formatter { bool negative; using char_type = typename FormatContext::char_type; + using tm_writer_type = tm_writer; - explicit chrono_formatter(FormatContext& ctx, OutputIt o, - std::chrono::duration d) + chrono_formatter(FormatContext& ctx, OutputIt o, + std::chrono::duration d) : context(ctx), out(o), val(static_cast(d.count())), @@ -822,18 +1820,12 @@ struct chrono_formatter { // this may overflow and/or the result may not fit in the // target type. -#if FMT_SAFE_DURATION_CAST // might need checked conversion (rep!=Rep) - auto tmpval = std::chrono::duration(val); - s = fmt_safe_duration_cast(tmpval); -#else - s = std::chrono::duration_cast( - std::chrono::duration(val)); -#endif + s = fmt_duration_cast(std::chrono::duration(val)); } // returns true if nan or inf, writes to out. - bool handle_nan_inf() { + auto handle_nan_inf() -> bool { if (isfinite(val)) { return false; } @@ -850,17 +1842,22 @@ struct chrono_formatter { return true; } - Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } + auto days() const -> Rep { return static_cast(s.count() / 86400); } + auto hour() const -> Rep { + return static_cast(mod((s.count() / 3600), 24)); + } - Rep hour12() const { + auto hour12() const -> Rep { Rep hour = static_cast(mod((s.count() / 3600), 12)); return hour <= 0 ? 12 : hour; } - Rep minute() const { return static_cast(mod((s.count() / 60), 60)); } - Rep second() const { return static_cast(mod(s.count(), 60)); } + auto minute() const -> Rep { + return static_cast(mod((s.count() / 60), 60)); + } + auto second() const -> Rep { return static_cast(mod(s.count(), 60)); } - std::tm time() const { + auto time() const -> std::tm { auto time = std::tm(); time.tm_hour = to_nonnegative_int(hour(), 24); time.tm_min = to_nonnegative_int(minute(), 60); @@ -875,13 +1872,15 @@ struct chrono_formatter { } } - void write(Rep value, int width) { + void write(Rep value, int width, pad_type pad = pad_type::zero) { write_sign(); if (isnan(value)) return write_nan(); uint32_or_64_or_128_t n = to_unsigned(to_nonnegative_int(value, max_value())); int num_digits = detail::count_digits(n); - if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); + if (width > num_digits) { + out = detail::write_padding(out, pad, width - num_digits); + } out = format_decimal(out, n, num_digits).end; } @@ -889,15 +1888,13 @@ struct chrono_formatter { void write_pinf() { std::copy_n("inf", 3, out); } void write_ninf() { std::copy_n("-inf", 4, out); } - void format_localized(const tm& time, char format, char modifier = 0) { + template + void format_tm(const tm& time, Callback cb, Args... args) { if (isnan(val)) return write_nan(); - auto locale = context.locale().template get(); - auto& facet = std::use_facet>(locale); - std::basic_ostringstream os; - os.imbue(locale); - facet.put(os, os, ' ', &time, format, modifier); - auto str = os.str(); - std::copy(str.begin(), str.end(), out); + get_locale loc(localized, context.locale()); + auto w = tm_writer_type(loc, out, time); + (w.*cb)(args...); + out = w.out(); } void on_text(const char_type* begin, const char_type* end) { @@ -916,64 +1913,80 @@ struct chrono_formatter { void on_loc_time(numeric_system) {} void on_us_date() {} void on_iso_date() {} - void on_utc_offset() {} + void on_utc_offset(numeric_system) {} void on_tz_name() {} + void on_year(numeric_system) {} + void on_short_year(numeric_system) {} + void on_offset_year() {} + void on_century(numeric_system) {} + void on_iso_week_based_year() {} + void on_iso_week_based_short_year() {} + void on_dec_month(numeric_system) {} + void on_dec0_week_of_year(numeric_system, pad_type) {} + void on_dec1_week_of_year(numeric_system, pad_type) {} + void on_iso_week_of_year(numeric_system, pad_type) {} + void on_day_of_month(numeric_system, pad_type) {} + + void on_day_of_year() { + if (handle_nan_inf()) return; + write(days(), 0); + } - void on_24_hour(numeric_system ns) { + void on_24_hour(numeric_system ns, pad_type pad) { if (handle_nan_inf()) return; - if (ns == numeric_system::standard) return write(hour(), 2); + if (ns == numeric_system::standard) return write(hour(), 2, pad); auto time = tm(); time.tm_hour = to_nonnegative_int(hour(), 24); - format_localized(time, 'H', 'O'); + format_tm(time, &tm_writer_type::on_24_hour, ns, pad); } - void on_12_hour(numeric_system ns) { + void on_12_hour(numeric_system ns, pad_type pad) { if (handle_nan_inf()) return; - if (ns == numeric_system::standard) return write(hour12(), 2); + if (ns == numeric_system::standard) return write(hour12(), 2, pad); auto time = tm(); time.tm_hour = to_nonnegative_int(hour12(), 12); - format_localized(time, 'I', 'O'); + format_tm(time, &tm_writer_type::on_12_hour, ns, pad); } - void on_minute(numeric_system ns) { + void on_minute(numeric_system ns, pad_type pad) { if (handle_nan_inf()) return; - if (ns == numeric_system::standard) return write(minute(), 2); + if (ns == numeric_system::standard) return write(minute(), 2, pad); auto time = tm(); time.tm_min = to_nonnegative_int(minute(), 60); - format_localized(time, 'M', 'O'); + format_tm(time, &tm_writer_type::on_minute, ns, pad); } - void on_second(numeric_system ns) { + void on_second(numeric_system ns, pad_type pad) { if (handle_nan_inf()) return; if (ns == numeric_system::standard) { - write(second(), 2); -#if FMT_SAFE_DURATION_CAST - // convert rep->Rep - using duration_rep = std::chrono::duration; - using duration_Rep = std::chrono::duration; - auto tmpval = fmt_safe_duration_cast(duration_rep{val}); -#else - auto tmpval = std::chrono::duration(val); -#endif - auto ms = get_milliseconds(tmpval); - if (ms != std::chrono::milliseconds(0)) { - *out++ = '.'; - write(ms.count(), 3); + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, std::chrono::duration(val), + precision); + if (negative) *out++ = '-'; + if (buf.size() < 2 || buf[1] == '.') { + out = detail::write_padding(out, pad); + } + out = std::copy(buf.begin(), buf.end(), out); + } else { + write(second(), 2, pad); + write_fractional_seconds( + out, std::chrono::duration(val), precision); } return; } auto time = tm(); time.tm_sec = to_nonnegative_int(second(), 60); - format_localized(time, 'S', 'O'); + format_tm(time, &tm_writer_type::on_second, ns, pad); } void on_12_hour_time() { if (handle_nan_inf()) return; - format_localized(time(), 'r'); + format_tm(time(), &tm_writer_type::on_12_hour_time); } void on_24_hour_time() { @@ -992,12 +2005,12 @@ struct chrono_formatter { on_24_hour_time(); *out++ = ':'; if (handle_nan_inf()) return; - write(second(), 2); + on_second(numeric_system::standard, pad_type::zero); } void on_am_pm() { if (handle_nan_inf()) return; - format_localized(time(), 'p'); + format_tm(time(), &tm_writer_type::on_am_pm); } void on_duration_value() { @@ -1010,114 +2023,410 @@ struct chrono_formatter { out = format_duration_unit(out); } }; + } // namespace detail -template -struct formatter, Char> { +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 +using weekday = std::chrono::weekday; +using day = std::chrono::day; +using month = std::chrono::month; +using year = std::chrono::year; +using year_month_day = std::chrono::year_month_day; +#else +// A fallback version of weekday. +class weekday { private: - basic_format_specs specs; - int precision; - using arg_ref_type = detail::arg_ref; - arg_ref_type width_ref; - arg_ref_type precision_ref; - mutable basic_string_view format_str; - using duration = std::chrono::duration; - - struct spec_handler { - formatter& f; - basic_format_parse_context& context; - basic_string_view format_str; - - template FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) { - context.check_arg_id(arg_id); - return arg_ref_type(arg_id); - } + unsigned char value_; - FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view arg_id) { - context.check_arg_id(arg_id); - return arg_ref_type(arg_id); - } + public: + weekday() = default; + constexpr explicit weekday(unsigned wd) noexcept + : value_(static_cast(wd != 7 ? wd : 0)) {} + constexpr auto c_encoding() const noexcept -> unsigned { return value_; } +}; - FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) { - return arg_ref_type(context.next_arg_id()); - } +class day { + private: + unsigned char value_; - void on_error(const char* msg) { FMT_THROW(format_error(msg)); } - void on_fill(basic_string_view fill) { f.specs.fill = fill; } - void on_align(align_t align) { f.specs.align = align; } - void on_width(int width) { f.specs.width = width; } - void on_precision(int _precision) { f.precision = _precision; } - void end_precision() {} + public: + day() = default; + constexpr explicit day(unsigned d) noexcept + : value_(static_cast(d)) {} + constexpr explicit operator unsigned() const noexcept { return value_; } +}; - template void on_dynamic_width(Id arg_id) { - f.width_ref = make_arg_ref(arg_id); - } +class month { + private: + unsigned char value_; - template void on_dynamic_precision(Id arg_id) { - f.precision_ref = make_arg_ref(arg_id); + public: + month() = default; + constexpr explicit month(unsigned m) noexcept + : value_(static_cast(m)) {} + constexpr explicit operator unsigned() const noexcept { return value_; } +}; + +class year { + private: + int value_; + + public: + year() = default; + constexpr explicit year(int y) noexcept : value_(y) {} + constexpr explicit operator int() const noexcept { return value_; } +}; + +class year_month_day { + private: + fmt::year year_; + fmt::month month_; + fmt::day day_; + + public: + year_month_day() = default; + constexpr year_month_day(const year& y, const month& m, const day& d) noexcept + : year_(y), month_(m), day_(d) {} + constexpr auto year() const noexcept -> fmt::year { return year_; } + constexpr auto month() const noexcept -> fmt::month { return month_; } + constexpr auto day() const noexcept -> fmt::day { return day_; } +}; +#endif + +template +struct formatter : private formatter { + private: + bool localized_ = false; + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == 'L') { + ++it; + localized_ = true; + return it; } - }; + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } - using iterator = typename basic_format_parse_context::iterator; - struct parse_range { - iterator begin; - iterator end; - }; + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(localized_, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_weekday(); + return w.out(); + } +}; - FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context& ctx) { - auto begin = ctx.begin(), end = ctx.end(); - if (begin == end || *begin == '}') return {begin, begin}; - spec_handler handler{*this, ctx, format_str}; - begin = detail::parse_align(begin, end, handler); - if (begin == end) return {begin, begin}; - begin = detail::parse_width(begin, end, handler); - if (begin == end) return {begin, begin}; - if (*begin == '.') { - if (std::is_floating_point::value) - begin = detail::parse_precision(begin, end, handler); - else - handler.on_error("precision not allowed for this argument type"); +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_mday = static_cast(static_cast(d)); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(false, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool localized_ = false; + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == 'L') { + ++it; + localized_ = true; + return it; } - end = parse_chrono_format(begin, end, detail::chrono_format_checker()); - return {begin, end}; + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; } + template + auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_mon = static_cast(static_cast(m)) - 1; + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(localized_, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_month(); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + public: - formatter() : precision(-1) {} + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_year = static_cast(y) - 1900; + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(false, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_year(detail::numeric_system::standard); + return w.out(); + } +}; +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) -> decltype(ctx.begin()) { - auto range = do_parse(ctx); - format_str = basic_string_view( - &*range.begin, detail::to_unsigned(range.end - range.begin)); - return range.end; + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; } template - auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) { - auto begin = format_str.begin(), end = format_str.end(); + auto format(year_month_day val, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_year = static_cast(val.year()) - 1900; + time.tm_mon = static_cast(static_cast(val.month())) - 1; + time.tm_mday = static_cast(static_cast(val.day())); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(true, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_iso_date(); + return w.out(); + } +}; + +template +struct formatter, Char> { + private: + format_specs specs_; + detail::arg_ref width_ref_; + detail::arg_ref precision_ref_; + bool localized_ = false; + basic_string_view format_str_; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + + auto checker = detail::chrono_format_checker(); + if (*it == '.') { + checker.has_precision_integral = !std::is_floating_point::value; + it = detail::parse_precision(it, end, specs_.precision, precision_ref_, + ctx); + } + if (it != end && *it == 'L') { + localized_ = true; + ++it; + } + end = detail::parse_chrono_format(it, end, checker); + format_str_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(std::chrono::duration d, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + auto precision = specs.precision; + specs.precision = -1; + auto begin = format_str_.begin(), end = format_str_.end(); // As a possible future optimization, we could avoid extra copying if width // is not specified. - basic_memory_buffer buf; + auto buf = basic_memory_buffer(); auto out = std::back_inserter(buf); - detail::handle_dynamic_spec(specs.width, width_ref, + detail::handle_dynamic_spec(specs.width, width_ref_, ctx); detail::handle_dynamic_spec(precision, - precision_ref, ctx); + precision_ref_, ctx); if (begin == end || *begin == '}') { out = detail::format_duration_value(out, d.count(), precision); detail::format_duration_unit(out); } else { - detail::chrono_formatter f( - ctx, out, d); + using chrono_formatter = + detail::chrono_formatter; + auto f = chrono_formatter(ctx, out, d); f.precision = precision; - parse_chrono_format(begin, end, f); + f.localized = localized_; + detail::parse_chrono_format(begin, end, f); + } + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } +}; + +template +struct formatter, + Char> : formatter { + FMT_CONSTEXPR formatter() { + this->format_str_ = detail::string_literal{}; + } + + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + std::tm tm = gmtime(val); + using period = typename Duration::period; + if (detail::const_check( + period::num == 1 && period::den == 1 && + !std::is_floating_point::value)) { + return formatter::format(tm, ctx); + } + Duration epoch = val.time_since_epoch(); + Duration subsecs = detail::fmt_duration_cast( + epoch - detail::fmt_duration_cast(epoch)); + if (subsecs.count() < 0) { + auto second = + detail::fmt_duration_cast(std::chrono::seconds(1)); + if (tm.tm_sec != 0) + --tm.tm_sec; + else + tm = gmtime(val - second); + subsecs += detail::fmt_duration_cast(std::chrono::seconds(1)); + } + return formatter::do_format(tm, ctx, &subsecs); + } +}; + +#if FMT_USE_LOCAL_TIME +template +struct formatter, Char> + : formatter { + FMT_CONSTEXPR formatter() { + this->format_str_ = detail::string_literal{}; + } + + template + auto format(std::chrono::local_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { + using period = typename Duration::period; + if (period::num != 1 || period::den != 1 || + std::is_floating_point::value) { + const auto epoch = val.time_since_epoch(); + const auto subsecs = detail::fmt_duration_cast( + epoch - detail::fmt_duration_cast(epoch)); + + return formatter::do_format(localtime(val), ctx, &subsecs); } + + return formatter::format(localtime(val), ctx); + } +}; +#endif + +#if FMT_USE_UTC_TIME +template +struct formatter, + Char> + : formatter, + Char> { + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + return formatter< + std::chrono::time_point, + Char>::format(std::chrono::utc_clock::to_sys(val), ctx); + } +}; +#endif + +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + + protected: + basic_string_view format_str_; + + template + auto do_format(const std::tm& tm, FormatContext& ctx, + const Duration* subsecs) const -> decltype(ctx.out()) { + auto specs = specs_; + auto buf = basic_memory_buffer(); + auto out = std::back_inserter(buf); + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + + auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = + detail::tm_writer(loc, out, tm, subsecs); + detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w); return detail::write( ctx.out(), basic_string_view(buf.data(), buf.size()), specs); } + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + + end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); + // Replace the default format_str only if the new spec is not empty. + if (end != it) format_str_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + return do_format(tm, ctx, nullptr); + } }; +FMT_END_EXPORT FMT_END_NAMESPACE #endif // FMT_CHRONO_H_ diff --git a/external/fmt/include/fmt/color.h b/external/fmt/include/fmt/color.h index b65f892afc..f0e9dd94ef 100644 --- a/external/fmt/include/fmt/color.h +++ b/external/fmt/include/fmt/color.h @@ -11,6 +11,7 @@ #include "format.h" FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT enum class color : uint32_t { alice_blue = 0xF0F8FF, // rgb(240,248,255) @@ -177,9 +178,13 @@ enum class terminal_color : uint8_t { enum class emphasis : uint8_t { bold = 1, - italic = 1 << 1, - underline = 1 << 2, - strikethrough = 1 << 3 + faint = 1 << 1, + italic = 1 << 2, + underline = 1 << 3, + blink = 1 << 4, + reverse = 1 << 5, + conceal = 1 << 6, + strikethrough = 1 << 7, }; // rgb is a struct for red, green and blue colors. @@ -202,17 +207,16 @@ namespace detail { // color is a struct of either a rgb color or a terminal color. struct color_type { - FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} - FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), - value{} { + FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { value.rgb_color = static_cast(rgb_color); } - FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { + FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { value.rgb_color = (static_cast(rgb_color.r) << 16) | (static_cast(rgb_color.g) << 8) | rgb_color.b; } - FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), - value{} { + FMT_CONSTEXPR color_type(terminal_color term_color) noexcept + : is_rgb(), value{} { value.term_color = static_cast(term_color); } bool is_rgb; @@ -223,21 +227,19 @@ struct color_type { }; } // namespace detail -// Experimental text formatting support. +/// A text style consisting of foreground and background colors and emphasis. class text_style { public: - FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT - : set_foreground_color(), - set_background_color(), - ems(em) {} + FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept + : set_foreground_color(), set_background_color(), ems(em) {} - FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { + FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& { if (!set_foreground_color) { set_foreground_color = rhs.set_foreground_color; foreground_color = rhs.foreground_color; } else if (rhs.set_foreground_color) { if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) - FMT_THROW(format_error("can't OR a terminal color")); + report_error("can't OR a terminal color"); foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; } @@ -246,7 +248,7 @@ class text_style { background_color = rhs.background_color; } else if (rhs.set_background_color) { if (!background_color.is_rgb || !rhs.background_color.is_rgb) - FMT_THROW(format_error("can't OR a terminal color")); + report_error("can't OR a terminal color"); background_color.value.rgb_color |= rhs.background_color.value.rgb_color; } @@ -255,68 +257,37 @@ class text_style { return *this; } - friend FMT_CONSTEXPR text_style operator|(text_style lhs, - const text_style& rhs) { + friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs) + -> text_style { return lhs |= rhs; } - FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) { - if (!set_foreground_color) { - set_foreground_color = rhs.set_foreground_color; - foreground_color = rhs.foreground_color; - } else if (rhs.set_foreground_color) { - if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) - FMT_THROW(format_error("can't AND a terminal color")); - foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; - } - - if (!set_background_color) { - set_background_color = rhs.set_background_color; - background_color = rhs.background_color; - } else if (rhs.set_background_color) { - if (!background_color.is_rgb || !rhs.background_color.is_rgb) - FMT_THROW(format_error("can't AND a terminal color")); - background_color.value.rgb_color &= rhs.background_color.value.rgb_color; - } - - ems = static_cast(static_cast(ems) & - static_cast(rhs.ems)); - return *this; - } - - friend FMT_CONSTEXPR text_style operator&(text_style lhs, - const text_style& rhs) { - return lhs &= rhs; - } - - FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { + FMT_CONSTEXPR auto has_foreground() const noexcept -> bool { return set_foreground_color; } - FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { + FMT_CONSTEXPR auto has_background() const noexcept -> bool { return set_background_color; } - FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { + FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool { return static_cast(ems) != 0; } - FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT { + FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type { FMT_ASSERT(has_foreground(), "no foreground specified for this style"); return foreground_color; } - FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT { + FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type { FMT_ASSERT(has_background(), "no background specified for this style"); return background_color; } - FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { + FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis { FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); return ems; } private: FMT_CONSTEXPR text_style(bool is_foreground, - detail::color_type text_color) FMT_NOEXCEPT - : set_foreground_color(), - set_background_color(), - ems() { + detail::color_type text_color) noexcept + : set_foreground_color(), set_background_color(), ems() { if (is_foreground) { foreground_color = text_color; set_foreground_color = true; @@ -326,10 +297,11 @@ class text_style { } } - friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground) - FMT_NOEXCEPT; - friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background) - FMT_NOEXCEPT; + friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept + -> text_style; + + friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept + -> text_style; detail::color_type foreground_color; detail::color_type background_color; @@ -338,15 +310,20 @@ class text_style { emphasis ems; }; -FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT { - return text_style(/*is_foreground=*/true, foreground); +/// Creates a text style from the foreground (text) color. +FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept + -> text_style { + return text_style(true, foreground); } -FMT_CONSTEXPR text_style bg(detail::color_type background) FMT_NOEXCEPT { - return text_style(/*is_foreground=*/false, background); +/// Creates a text style from the background color. +FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept + -> text_style { + return text_style(false, background); } -FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { +FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept + -> text_style { return text_style(lhs) | rhs; } @@ -354,11 +331,11 @@ namespace detail { template struct ansi_color_escape { FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, - const char* esc) FMT_NOEXCEPT { + const char* esc) noexcept { // If we have a terminal color, we need to output another escape code // sequence. if (!text_color.is_rgb) { - bool is_background = esc == detail::data::background_color; + bool is_background = esc == string_view("\x1b[48;2;"); uint32_t value = text_color.value.term_color; // Background ASCII codes are the same as the foreground ones but with // 10 more. @@ -389,17 +366,19 @@ template struct ansi_color_escape { to_esc(color.b, buffer + 15, 'm'); buffer[19] = static_cast(0); } - FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { - uint8_t em_codes[4] = {}; - uint8_t em_bits = static_cast(em); - if (em_bits & static_cast(emphasis::bold)) em_codes[0] = 1; - if (em_bits & static_cast(emphasis::italic)) em_codes[1] = 3; - if (em_bits & static_cast(emphasis::underline)) em_codes[2] = 4; - if (em_bits & static_cast(emphasis::strikethrough)) - em_codes[3] = 9; + FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { + uint8_t em_codes[num_emphases] = {}; + if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; + if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; + if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; + if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; + if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; + if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; + if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; + if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; size_t index = 0; - for (int i = 0; i < 4; ++i) { + for (size_t i = 0; i < num_emphases; ++i) { if (!em_codes[i]) continue; buffer[index++] = static_cast('\x1b'); buffer[index++] = static_cast('['); @@ -408,71 +387,63 @@ template struct ansi_color_escape { } buffer[index++] = static_cast(0); } - FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } + FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } - FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } - FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT { - return buffer + std::char_traits::length(buffer); + FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; } + FMT_CONSTEXPR20 auto end() const noexcept -> const Char* { + return buffer + basic_string_view(buffer).size(); } private: - Char buffer[7u + 3u * 4u + 1u]; + static constexpr size_t num_emphases = 8; + Char buffer[7u + 3u * num_emphases + 1u]; static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, - char delimiter) FMT_NOEXCEPT { + char delimiter) noexcept { out[0] = static_cast('0' + c / 100); out[1] = static_cast('0' + c / 10 % 10); out[2] = static_cast('0' + c % 10); out[3] = static_cast(delimiter); } + static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept + -> bool { + return static_cast(em) & static_cast(mask); + } }; template -FMT_CONSTEXPR ansi_color_escape make_foreground_color( - detail::color_type foreground) FMT_NOEXCEPT { - return ansi_color_escape(foreground, detail::data::foreground_color); +FMT_CONSTEXPR auto make_foreground_color(detail::color_type foreground) noexcept + -> ansi_color_escape { + return ansi_color_escape(foreground, "\x1b[38;2;"); } template -FMT_CONSTEXPR ansi_color_escape make_background_color( - detail::color_type background) FMT_NOEXCEPT { - return ansi_color_escape(background, detail::data::background_color); +FMT_CONSTEXPR auto make_background_color(detail::color_type background) noexcept + -> ansi_color_escape { + return ansi_color_escape(background, "\x1b[48;2;"); } template -FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) FMT_NOEXCEPT { +FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept + -> ansi_color_escape { return ansi_color_escape(em); } -template -inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { - std::fputs(chars, stream); -} - -template <> -inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { - std::fputws(chars, stream); +template inline void reset_color(buffer& buffer) { + auto reset_color = string_view("\x1b[0m"); + buffer.append(reset_color.begin(), reset_color.end()); } -template inline void reset_color(FILE* stream) FMT_NOEXCEPT { - fputs(detail::data::reset_color, stream); -} - -template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT { - fputs(detail::data::wreset_color, stream); -} - -template -inline void reset_color(basic_memory_buffer& buffer) FMT_NOEXCEPT { - const char* begin = data::reset_color; - const char* end = begin + sizeof(data::reset_color) - 1; - buffer.append(begin, end); -} +template struct styled_arg : detail::view { + const T& value; + text_style style; + styled_arg(const T& v, text_style s) : value(v), style(s) {} +}; template -void vformat_to(basic_memory_buffer& buf, const text_style& ts, - basic_string_view format_str, - basic_format_args> args) { +void vformat_to( + buffer& buf, const text_style& ts, basic_string_view format_str, + basic_format_args>> args) { bool has_style = false; if (ts.has_emphasis()) { has_style = true; @@ -489,78 +460,153 @@ void vformat_to(basic_memory_buffer& buf, const text_style& ts, auto background = detail::make_background_color(ts.get_background()); buf.append(background.begin(), background.end()); } - detail::vformat_to(buf, format_str, args); + detail::vformat_to(buf, format_str, args, {}); if (has_style) detail::reset_color(buf); } + } // namespace detail -template > -void vprint(std::FILE* f, const text_style& ts, const S& format, - basic_format_args> args) { - basic_memory_buffer buf; - detail::vformat_to(buf, ts, to_string_view(format), args); - buf.push_back(Char(0)); - detail::fputs(buf.data(), f); +inline void vprint(FILE* f, const text_style& ts, string_view fmt, + format_args args) { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size())); } /** - Formats a string and prints it to the specified file stream using ANSI - escape sequences to specify text formatting. - Example: - fmt::print(fmt::emphasis::bold | fg(fmt::color::red), - "Elapsed time: {0:.2f} seconds", 1.23); + * Formats a string and prints it to the specified file stream using ANSI + * escape sequences to specify text formatting. + * + * **Example**: + * + * fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + * "Elapsed time: {0:.2f} seconds", 1.23); */ -template ::value)> -void print(std::FILE* f, const text_style& ts, const S& format_str, - const Args&... args) { - detail::check_format_string(format_str); - using context = buffer_context>; - format_arg_store as{args...}; - vprint(f, ts, format_str, basic_format_args(as)); +template +void print(FILE* f, const text_style& ts, format_string fmt, + T&&... args) { + vprint(f, ts, fmt, fmt::make_format_args(args...)); } /** - Formats a string and prints it to stdout using ANSI escape sequences to - specify text formatting. - Example: - fmt::print(fmt::emphasis::bold | fg(fmt::color::red), - "Elapsed time: {0:.2f} seconds", 1.23); + * Formats a string and prints it to stdout using ANSI escape sequences to + * specify text formatting. + * + * **Example**: + * + * fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + * "Elapsed time: {0:.2f} seconds", 1.23); */ -template ::value)> -void print(const text_style& ts, const S& format_str, const Args&... args) { - return print(stdout, ts, format_str, args...); +template +void print(const text_style& ts, format_string fmt, T&&... args) { + return print(stdout, ts, fmt, std::forward(args)...); } -template > -inline std::basic_string vformat( - const text_style& ts, const S& format_str, - basic_format_args>> args) { - basic_memory_buffer buf; - detail::vformat_to(buf, ts, to_string_view(format_str), args); +inline auto vformat(const text_style& ts, string_view fmt, format_args args) + -> std::string { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); return fmt::to_string(buf); } /** - \rst - Formats arguments and returns the result as a string using ANSI - escape sequences to specify text formatting. - - **Example**:: - - #include - std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), - "The answer is {}", 42); - \endrst -*/ -template > -inline std::basic_string format(const text_style& ts, const S& format_str, - const Args&... args) { - return vformat(ts, to_string_view(format_str), - detail::make_args_checked(format_str, args...)); + * Formats arguments and returns the result as a string using ANSI escape + * sequences to specify text formatting. + * + * **Example**: + * + * ``` + * #include + * std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), + * "The answer is {}", 42); + * ``` + */ +template +inline auto format(const text_style& ts, format_string fmt, T&&... args) + -> std::string { + return fmt::vformat(ts, fmt, fmt::make_format_args(args...)); +} + +/// Formats a string with the given text_style and writes the output to `out`. +template ::value)> +auto vformat_to(OutputIt out, const text_style& ts, string_view fmt, + format_args args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, ts, fmt, args); + return detail::get_iterator(buf, out); +} + +/** + * Formats arguments with the given text style, writes the result to the output + * iterator `out` and returns the iterator past the end of the output range. + * + * **Example**: + * + * std::vector out; + * fmt::format_to(std::back_inserter(out), + * fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); + */ +template ::value)> +inline auto format_to(OutputIt out, const text_style& ts, + format_string fmt, T&&... args) -> OutputIt { + return vformat_to(out, ts, fmt, fmt::make_format_args(args...)); +} + +template +struct formatter, Char> : formatter { + template + auto format(const detail::styled_arg& arg, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto& ts = arg.style; + const auto& value = arg.value; + auto out = ctx.out(); + + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + out = std::copy(emphasis.begin(), emphasis.end(), out); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = + detail::make_foreground_color(ts.get_foreground()); + out = std::copy(foreground.begin(), foreground.end(), out); + } + if (ts.has_background()) { + has_style = true; + auto background = + detail::make_background_color(ts.get_background()); + out = std::copy(background.begin(), background.end(), out); + } + out = formatter::format(value, ctx); + if (has_style) { + auto reset_color = string_view("\x1b[0m"); + out = std::copy(reset_color.begin(), reset_color.end(), out); + } + return out; + } +}; + +/** + * Returns an argument that will be formatted using ANSI escape sequences, + * to be used in a formatting function. + * + * **Example**: + * + * fmt::print("Elapsed time: {0:.2f} seconds", + * fmt::styled(1.23, fmt::fg(fmt::color::green) | + * fmt::bg(fmt::color::blue))); + */ +template +FMT_CONSTEXPR auto styled(const T& value, text_style ts) + -> detail::styled_arg> { + return detail::styled_arg>{value, ts}; } +FMT_END_EXPORT FMT_END_NAMESPACE #endif // FMT_COLOR_H_ diff --git a/external/fmt/include/fmt/compile.h b/external/fmt/include/fmt/compile.h index d7e6449ebb..b2afc2c309 100644 --- a/external/fmt/include/fmt/compile.h +++ b/external/fmt/include/fmt/compile.h @@ -8,378 +8,86 @@ #ifndef FMT_COMPILE_H_ #define FMT_COMPILE_H_ -#include +#ifndef FMT_MODULE +# include // std::back_inserter +#endif #include "format.h" FMT_BEGIN_NAMESPACE -namespace detail { // A compile-time string which is compiled into fast formatting code. -class compiled_string {}; - -template -struct is_compiled_string : std::is_base_of {}; - -/** - \rst - Converts a string literal *s* into a format string that will be parsed at - compile time and converted into efficient formatting code. Requires C++17 - ``constexpr if`` compiler support. - - **Example**:: - - // Converts 42 into std::string using the most efficient method and no - // runtime format string processing. - std::string s = fmt::format(FMT_COMPILE("{}"), 42); - \endrst - */ -#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string) - -template -const T& first(const T& value, const Tail&...) { - return value; -} - -// Part of a compiled format string. It can be either literal text or a -// replacement field. -template struct format_part { - enum class kind { arg_index, arg_name, text, replacement }; - - struct replacement { - arg_ref arg_id; - dynamic_format_specs specs; - }; - - kind part_kind; - union value { - int arg_index; - basic_string_view str; - replacement repl; - - FMT_CONSTEXPR value(int index = 0) : arg_index(index) {} - FMT_CONSTEXPR value(basic_string_view s) : str(s) {} - FMT_CONSTEXPR value(replacement r) : repl(r) {} - } val; - // Position past the end of the argument id. - const Char* arg_id_end = nullptr; - - FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {}) - : part_kind(k), val(v) {} - - static FMT_CONSTEXPR format_part make_arg_index(int index) { - return format_part(kind::arg_index, index); - } - static FMT_CONSTEXPR format_part make_arg_name(basic_string_view name) { - return format_part(kind::arg_name, name); - } - static FMT_CONSTEXPR format_part make_text(basic_string_view text) { - return format_part(kind::text, text); - } - static FMT_CONSTEXPR format_part make_replacement(replacement repl) { - return format_part(kind::replacement, repl); - } -}; - -template struct part_counter { - unsigned num_parts = 0; - - FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { - if (begin != end) ++num_parts; - } - - FMT_CONSTEXPR int on_arg_id() { return ++num_parts, 0; } - FMT_CONSTEXPR int on_arg_id(int) { return ++num_parts, 0; } - FMT_CONSTEXPR int on_arg_id(basic_string_view) { - return ++num_parts, 0; - } - - FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} - - FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin, - const Char* end) { - // Find the matching brace. - unsigned brace_counter = 0; - for (; begin != end; ++begin) { - if (*begin == '{') { - ++brace_counter; - } else if (*begin == '}') { - if (brace_counter == 0u) break; - --brace_counter; - } - } - return begin; - } - - FMT_CONSTEXPR void on_error(const char*) {} -}; - -// Counts the number of parts in a format string. -template -FMT_CONSTEXPR unsigned count_parts(basic_string_view format_str) { - part_counter counter; - parse_format_string(format_str, counter); - return counter.num_parts; -} - -template -class format_string_compiler : public error_handler { - private: - using part = format_part; - - PartHandler handler_; - part part_; - basic_string_view format_str_; - basic_format_parse_context parse_context_; - - public: - FMT_CONSTEXPR format_string_compiler(basic_string_view format_str, - PartHandler handler) - : handler_(handler), - format_str_(format_str), - parse_context_(format_str) {} - - FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { - if (begin != end) - handler_(part::make_text({begin, to_unsigned(end - begin)})); - } - - FMT_CONSTEXPR int on_arg_id() { - part_ = part::make_arg_index(parse_context_.next_arg_id()); - return 0; - } - - FMT_CONSTEXPR int on_arg_id(int id) { - parse_context_.check_arg_id(id); - part_ = part::make_arg_index(id); - return 0; - } - - FMT_CONSTEXPR int on_arg_id(basic_string_view id) { - part_ = part::make_arg_name(id); - return 0; - } +FMT_EXPORT class compiled_string {}; - FMT_CONSTEXPR void on_replacement_field(int, const Char* ptr) { - part_.arg_id_end = ptr; - handler_(part_); - } - - FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin, - const Char* end) { - auto repl = typename part::replacement(); - dynamic_specs_handler> handler( - repl.specs, parse_context_); - auto it = parse_format_specs(begin, end, handler); - if (*it != '}') on_error("missing '}' in format string"); - repl.arg_id = part_.part_kind == part::kind::arg_index - ? arg_ref(part_.val.arg_index) - : arg_ref(part_.val.str); - auto part = part::make_replacement(repl); - part.arg_id_end = begin; - handler_(part); - return it; - } -}; - -// Compiles a format string and invokes handler(part) for each parsed part. -template -FMT_CONSTEXPR void compile_format_string(basic_string_view format_str, - PartHandler handler) { - parse_format_string( - format_str, - format_string_compiler(format_str, handler)); -} - -template -void format_arg( - basic_format_parse_context& parse_ctx, - Context& ctx, Id arg_id) { - ctx.advance_to(visit_format_arg( - arg_formatter(ctx, &parse_ctx), - ctx.arg(arg_id))); -} - -// vformat_to is defined in a subnamespace to prevent ADL. -namespace cf { -template -auto vformat_to(OutputIt out, CompiledFormat& cf, - basic_format_args args) -> typename Context::iterator { - using char_type = typename Context::char_type; - basic_format_parse_context parse_ctx( - to_string_view(cf.format_str_)); - Context ctx(out, args); - - const auto& parts = cf.parts(); - for (auto part_it = std::begin(parts); part_it != std::end(parts); - ++part_it) { - const auto& part = *part_it; - const auto& value = part.val; - - using format_part_t = format_part; - switch (part.part_kind) { - case format_part_t::kind::text: { - const auto text = value.str; - auto output = ctx.out(); - auto&& it = reserve(output, text.size()); - it = std::copy_n(text.begin(), text.size(), it); - ctx.advance_to(output); - break; - } - - case format_part_t::kind::arg_index: - advance_to(parse_ctx, part.arg_id_end); - detail::format_arg(parse_ctx, ctx, value.arg_index); - break; - - case format_part_t::kind::arg_name: - advance_to(parse_ctx, part.arg_id_end); - detail::format_arg(parse_ctx, ctx, value.str); - break; - - case format_part_t::kind::replacement: { - const auto& arg_id_value = value.repl.arg_id.val; - const auto arg = value.repl.arg_id.kind == arg_id_kind::index - ? ctx.arg(arg_id_value.index) - : ctx.arg(arg_id_value.name); - - auto specs = value.repl.specs; - - handle_dynamic_spec(specs.width, specs.width_ref, ctx); - handle_dynamic_spec(specs.precision, - specs.precision_ref, ctx); - - error_handler h; - numeric_specs_checker checker(h, arg.type()); - if (specs.align == align::numeric) checker.require_numeric_argument(); - if (specs.sign != sign::none) checker.check_sign(); - if (specs.alt) checker.require_numeric_argument(); - if (specs.precision >= 0) checker.check_precision(); - - advance_to(parse_ctx, part.arg_id_end); - ctx.advance_to( - visit_format_arg(arg_formatter( - ctx, nullptr, &specs), - arg)); - break; - } - } - } - return ctx.out(); -} -} // namespace cf - -struct basic_compiled_format {}; - -template -struct compiled_format_base : basic_compiled_format { - using char_type = char_t; - using parts_container = std::vector>; - - parts_container compiled_parts; - - explicit compiled_format_base(basic_string_view format_str) { - compile_format_string(format_str, - [this](const format_part& part) { - compiled_parts.push_back(part); - }); - } - - const parts_container& parts() const { return compiled_parts; } -}; - -template struct format_part_array { - format_part data[N] = {}; - FMT_CONSTEXPR format_part_array() = default; -}; - -template -FMT_CONSTEXPR format_part_array compile_to_parts( - basic_string_view format_str) { - format_part_array parts; - unsigned counter = 0; - // This is not a lambda for compatibility with older compilers. - struct { - format_part* parts; - unsigned* counter; - FMT_CONSTEXPR void operator()(const format_part& part) { - parts[(*counter)++] = part; - } - } collector{parts.data, &counter}; - compile_format_string(format_str, collector); - if (counter < N) { - parts.data[counter] = - format_part::make_text(basic_string_view()); - } - return parts; -} +namespace detail { -template constexpr const T& constexpr_max(const T& a, const T& b) { - return (a < b) ? b : a; +template +FMT_CONSTEXPR inline auto copy(InputIt begin, InputIt end, counting_iterator it) + -> counting_iterator { + return it + (end - begin); } template -struct compiled_format_base::value>> - : basic_compiled_format { - using char_type = char_t; - - FMT_CONSTEXPR explicit compiled_format_base(basic_string_view) {} +struct is_compiled_string : std::is_base_of {}; -// Workaround for old compilers. Format string compilation will not be -// performed there anyway. -#if FMT_USE_CONSTEXPR - static FMT_CONSTEXPR_DECL const unsigned num_format_parts = - constexpr_max(count_parts(to_string_view(S())), 1u); +/** + * Converts a string literal `s` into a format string that will be parsed at + * compile time and converted into efficient formatting code. Requires C++17 + * `constexpr if` compiler support. + * + * **Example**: + * + * // Converts 42 into std::string using the most efficient method and no + * // runtime format string processing. + * std::string s = fmt::format(FMT_COMPILE("{}"), 42); + */ +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string, explicit) #else - static const unsigned num_format_parts = 1; +# define FMT_COMPILE(s) FMT_STRING(s) #endif - using parts_container = format_part[num_format_parts]; - - const parts_container& parts() const { - static FMT_CONSTEXPR_DECL const auto compiled_parts = - compile_to_parts( - detail::to_string_view(S())); - return compiled_parts.data; +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct udl_compiled_string : compiled_string { + using char_type = Char; + explicit constexpr operator basic_string_view() const { + return {Str.data, N - 1}; } }; +#endif -template -class compiled_format : private compiled_format_base { - public: - using typename compiled_format_base::char_type; - - private: - basic_string_view format_str_; - - template - friend auto cf::vformat_to(OutputIt out, CompiledFormat& cf, - basic_format_args args) -> - typename Context::iterator; - - public: - compiled_format() = delete; - explicit constexpr compiled_format(basic_string_view format_str) - : compiled_format_base(format_str), format_str_(format_str) {} -}; +template +auto first(const T& value, const Tail&...) -> const T& { + return value; +} -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template struct type_list {}; // Returns a reference to the argument at index N from [first, rest...]. template -constexpr const auto& get(const T& first, const Args&... rest) { +constexpr const auto& get([[maybe_unused]] const T& first, + [[maybe_unused]] const Args&... rest) { static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); if constexpr (N == 0) return first; else - return get(rest...); + return detail::get(rest...); +} + +template +constexpr int get_arg_index_by_name(basic_string_view name, + type_list) { + return get_arg_index_by_name(name); } template struct get_type_impl; template struct get_type_impl> { - using type = remove_cvref_t(std::declval()...))>; + using type = + remove_cvref_t(std::declval()...))>; }; template @@ -392,7 +100,7 @@ template struct text { using char_type = Char; template - OutputIt format(OutputIt out, const Args&...) const { + constexpr OutputIt format(OutputIt out, const Args&...) const { return write(out, data); } }; @@ -406,14 +114,42 @@ constexpr text make_text(basic_string_view s, size_t pos, return {{&s[pos], size}}; } +template struct code_unit { + Char value; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + *out++ = value; + return out; + } +}; + +// This ensures that the argument type is convertible to `const T&`. +template +constexpr const T& get_arg_checked(const Args&... args) { + const auto& arg = detail::get(args...); + if constexpr (detail::is_named_arg>()) { + return arg.value; + } else { + return arg; + } +} + +template +struct is_compiled_format> : std::true_type {}; + // A replacement field that refers to argument N. template struct field { using char_type = Char; template - OutputIt format(OutputIt out, const Args&... args) const { - // This ensures that the argument type is convertile to `const T&`. - const T& arg = get(args...); + constexpr OutputIt format(OutputIt out, const Args&... args) const { + const T& arg = get_arg_checked(args...); + if constexpr (std::is_convertible>::value) { + auto s = basic_string_view(arg); + return copy(s.begin(), s.end(), out); + } return write(out, arg); } }; @@ -421,17 +157,50 @@ template struct field { template struct is_compiled_format> : std::true_type {}; +// A replacement field that refers to argument with name. +template struct runtime_named_field { + using char_type = Char; + basic_string_view name; + + template + constexpr static bool try_format_argument( + OutputIt& out, + // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 + [[maybe_unused]] basic_string_view arg_name, const T& arg) { + if constexpr (is_named_arg::type>::value) { + if (arg_name == arg.name) { + out = write(out, arg.value); + return true; + } + } + return false; + } + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + bool found = (try_format_argument(out, name, args) || ...); + if (!found) { + FMT_THROW(format_error("argument with specified name is not found")); + } + return out; + } +}; + +template +struct is_compiled_format> : std::true_type {}; + // A replacement field that refers to argument N and has format specifiers. template struct spec_field { using char_type = Char; - mutable formatter fmt; + formatter fmt; template - OutputIt format(OutputIt out, const Args&... args) const { - // This ensures that the argument type is convertile to `const T&`. - const T& arg = get(args...); - basic_format_context ctx(out, {}); - return fmt.format(arg, ctx); + constexpr FMT_INLINE OutputIt format(OutputIt out, + const Args&... args) const { + const auto& vargs = + fmt::make_format_args>(args...); + basic_format_context ctx(out, vargs); + return fmt.format(get_arg_checked(args...), ctx); } }; @@ -444,7 +213,7 @@ template struct concat { using char_type = typename L::char_type; template - OutputIt format(OutputIt out, const Args&... args) const { + constexpr OutputIt format(OutputIt out, const Args&... args) const { out = lhs.format(out, args...); return rhs.format(out, args...); } @@ -469,13 +238,12 @@ constexpr size_t parse_text(basic_string_view str, size_t pos) { } template -constexpr auto compile_format_string(S format_str); +constexpr auto compile_format_string(S fmt); template -constexpr auto parse_tail(T head, S format_str) { - if constexpr (POS != - basic_string_view(format_str).size()) { - constexpr auto tail = compile_format_string(format_str); +constexpr auto parse_tail(T head, S fmt) { + if constexpr (POS != basic_string_view(fmt).size()) { + constexpr auto tail = compile_format_string(fmt); if constexpr (std::is_same, unknown_format>()) return tail; @@ -489,177 +257,273 @@ constexpr auto parse_tail(T head, S format_str) { template struct parse_specs_result { formatter fmt; size_t end; + int next_arg_id; }; +enum { manual_indexing_id = -1 }; + template constexpr parse_specs_result parse_specs(basic_string_view str, - size_t pos) { + size_t pos, int next_arg_id) { str.remove_prefix(pos); - auto ctx = basic_format_parse_context(str); + auto ctx = + compile_parse_context(str, max_value(), nullptr, next_arg_id); auto f = formatter(); auto end = f.parse(ctx); - return {f, pos + (end - str.data()) + 1}; + return {f, pos + fmt::detail::to_unsigned(end - str.data()), + next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; +} + +template struct arg_id_handler { + arg_ref arg_id; + + constexpr int on_auto() { + FMT_ASSERT(false, "handler cannot be used with automatic indexing"); + return 0; + } + constexpr int on_index(int id) { + arg_id = arg_ref(id); + return 0; + } + constexpr int on_name(basic_string_view id) { + arg_id = arg_ref(id); + return 0; + } +}; + +template struct parse_arg_id_result { + arg_ref arg_id; + const Char* arg_id_end; +}; + +template +constexpr auto parse_arg_id(const Char* begin, const Char* end) { + auto handler = arg_id_handler{arg_ref{}}; + auto arg_id_end = parse_arg_id(begin, end, handler); + return parse_arg_id_result{handler.arg_id, arg_id_end}; +} + +template struct field_type { + using type = remove_cvref_t; +}; + +template +struct field_type::value>> { + using type = remove_cvref_t; +}; + +template +constexpr auto parse_replacement_field_then_tail(S fmt) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(fmt); + constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); + if constexpr (c == '}') { + return parse_tail( + field::type, ARG_INDEX>(), fmt); + } else if constexpr (c != ':') { + FMT_THROW(format_error("expected ':'")); + } else { + constexpr auto result = parse_specs::type>( + str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); + if constexpr (result.end >= str.size() || str[result.end] != '}') { + FMT_THROW(format_error("expected '}'")); + return 0; + } else { + return parse_tail( + spec_field::type, ARG_INDEX>{ + result.fmt}, + fmt); + } + } } // Compiles a non-empty format string and returns the compiled representation // or unknown_format() on unrecognized input. template -constexpr auto compile_format_string(S format_str) { +constexpr auto compile_format_string(S fmt) { using char_type = typename S::char_type; - constexpr basic_string_view str = format_str; + constexpr auto str = basic_string_view(fmt); if constexpr (str[POS] == '{') { - if (POS + 1 == str.size()) - throw format_error("unmatched '{' in format string"); + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '{' in format string")); if constexpr (str[POS + 1] == '{') { - return parse_tail(make_text(str, POS, 1), format_str); - } else if constexpr (str[POS + 1] == '}') { - using type = get_type; - return parse_tail(field(), - format_str); - } else if constexpr (str[POS + 1] == ':') { - using type = get_type; - constexpr auto result = parse_specs(str, POS + 2); - return parse_tail( - spec_field{result.fmt}, format_str); + return parse_tail(make_text(str, POS, 1), fmt); + } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { + static_assert(ID != manual_indexing_id, + "cannot switch from manual to automatic argument indexing"); + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail, Args, + POS + 1, ID, next_id>(fmt); } else { - return unknown_format(); + constexpr auto arg_id_result = + parse_arg_id(str.data() + POS + 1, str.data() + str.size()); + constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); + constexpr char_type c = + arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); + static_assert(c == '}' || c == ':', "missing '}' in format string"); + if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { + static_assert( + ID == manual_indexing_id || ID == 0, + "cannot switch from automatic to manual argument indexing"); + constexpr auto arg_index = arg_id_result.arg_id.val.index; + return parse_replacement_field_then_tail, + Args, arg_id_end_pos, + arg_index, manual_indexing_id>( + fmt); + } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { + constexpr auto arg_index = + get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); + if constexpr (arg_index >= 0) { + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail< + decltype(get_type::value), Args, arg_id_end_pos, + arg_index, next_id>(fmt); + } else if constexpr (c == '}') { + return parse_tail( + runtime_named_field{arg_id_result.arg_id.val.name}, + fmt); + } else if constexpr (c == ':') { + return unknown_format(); // no type info for specs parsing + } + } } } else if constexpr (str[POS] == '}') { - if (POS + 1 == str.size()) - throw format_error("unmatched '}' in format string"); - return parse_tail(make_text(str, POS, 1), format_str); + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '}' in format string")); + return parse_tail(make_text(str, POS, 1), fmt); } else { constexpr auto end = parse_text(str, POS + 1); - return parse_tail(make_text(str, POS, end - POS), - format_str); + if constexpr (end - POS > 1) { + return parse_tail(make_text(str, POS, end - POS), fmt); + } else { + return parse_tail(code_unit{str[POS]}, fmt); + } } } template ::value || - detail::is_compiled_string::value)> -constexpr auto compile(S format_str) { - constexpr basic_string_view str = format_str; + FMT_ENABLE_IF(detail::is_compiled_string::value)> +constexpr auto compile(S fmt) { + constexpr auto str = basic_string_view(fmt); if constexpr (str.size() == 0) { return detail::make_text(str, 0, 0); } else { constexpr auto result = - detail::compile_format_string, 0, 0>( - format_str); - if constexpr (std::is_same, - detail::unknown_format>()) { - return detail::compiled_format(to_string_view(format_str)); - } else { - return result; - } + detail::compile_format_string, 0, 0>(fmt); + return result; } } -#else -template ::value)> -constexpr auto compile(S format_str) -> detail::compiled_format { - return detail::compiled_format(to_string_view(format_str)); -} -#endif // __cpp_if_constexpr - -// Compiles the format string which must be a string literal. -template -auto compile(const Char (&format_str)[N]) - -> detail::compiled_format { - return detail::compiled_format( - basic_string_view(format_str, N - 1)); -} +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) } // namespace detail -// DEPRECATED! use FMT_COMPILE instead. -template -FMT_DEPRECATED auto compile(const Args&... args) - -> decltype(detail::compile(args...)) { - return detail::compile(args...); -} +FMT_BEGIN_EXPORT -#if FMT_USE_CONSTEXPR -# ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template ::value)> FMT_INLINE std::basic_string format(const CompiledFormat& cf, const Args&... args) { - basic_memory_buffer buffer; - detail::buffer& base = buffer; - cf.format(std::back_inserter(base), args...); - return to_string(buffer); + auto s = std::basic_string(); + cf.format(std::back_inserter(s), args...); + return s; } template ::value)> -OutputIt format_to(OutputIt out, const CompiledFormat& cf, - const Args&... args) { +constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, + const Args&... args) { return cf.format(out, args...); } -# endif // __cpp_if_constexpr -#endif // FMT_USE_CONSTEXPR - -template ::value)> -std::basic_string format(const CompiledFormat& cf, const Args&... args) { - basic_memory_buffer buffer; - using context = buffer_context; - detail::buffer& base = buffer; - detail::cf::vformat_to(std::back_inserter(base), cf, - make_format_args(args...)); - return to_string(buffer); -} template ::value)> FMT_INLINE std::basic_string format(const S&, Args&&... args) { - constexpr basic_string_view str = S(); - if (str.size() == 2 && str[0] == '{' && str[1] == '}') - return fmt::to_string(detail::first(args...)); + if constexpr (std::is_same::value) { + constexpr auto str = basic_string_view(S()); + if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { + const auto& first = detail::first(args...); + if constexpr (detail::is_named_arg< + remove_cvref_t>::value) { + return fmt::to_string(first.value); + } else { + return fmt::to_string(first); + } + } + } constexpr auto compiled = detail::compile(S()); - return format(compiled, std::forward(args)...); + if constexpr (std::is_same, + detail::unknown_format>()) { + return fmt::format( + static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format(compiled, std::forward(args)...); + } } -template ::value)> -OutputIt format_to(OutputIt out, const CompiledFormat& cf, - const Args&... args) { - using char_type = typename CompiledFormat::char_type; - using context = format_context_t; - return detail::cf::vformat_to(out, cf, - make_format_args(args...)); +template ::value)> +FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return fmt::format_to( + out, static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format_to(out, compiled, std::forward(args)...); + } } +#endif template ::value)> -OutputIt format_to(OutputIt out, const S&, const Args&... args) { - constexpr auto compiled = detail::compile(S()); - return format_to(out, compiled, args...); +auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + fmt::format_to(std::back_inserter(buf), fmt, std::forward(args)...); + return {buf.out(), buf.count()}; } -template < - typename OutputIt, typename CompiledFormat, typename... Args, - FMT_ENABLE_IF(detail::is_output_iterator::value&& std::is_base_of< - detail::basic_compiled_format, CompiledFormat>::value)> -format_to_n_result format_to_n(OutputIt out, size_t n, - const CompiledFormat& cf, - const Args&... args) { - auto it = - format_to(detail::truncating_iterator(out, n), cf, args...); - return {it.base(), it.count()}; +template ::value)> +FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args) + -> size_t { + return fmt::format_to(detail::counting_iterator(), fmt, args...).count(); } -template -size_t formatted_size(const CompiledFormat& cf, const Args&... args) { - return format_to(detail::counting_iterator(), cf, args...).count(); +template ::value)> +void print(std::FILE* f, const S& fmt, const Args&... args) { + memory_buffer buffer; + fmt::format_to(std::back_inserter(buffer), fmt, args...); + detail::print(f, {buffer.data(), buffer.size()}); } +template ::value)> +void print(const S& fmt, const Args&... args) { + print(stdout, fmt, args...); +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +inline namespace literals { +template constexpr auto operator""_cf() { + using char_t = remove_cvref_t; + return detail::udl_compiled_string(); +} +} // namespace literals +#endif + +FMT_END_EXPORT FMT_END_NAMESPACE #endif // FMT_COMPILE_H_ diff --git a/external/fmt/include/fmt/core.h b/external/fmt/include/fmt/core.h index 3c9fea1aca..8ca735f0c0 100644 --- a/external/fmt/include/fmt/core.h +++ b/external/fmt/include/fmt/core.h @@ -1,1887 +1,5 @@ -// Formatting library for C++ - the core API -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. +// This file is only provided for compatibility and may be removed in future +// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h +// otherwise. -#ifndef FMT_CORE_H_ -#define FMT_CORE_H_ - -#include -#include // std::FILE -#include -#include -#include -#include -#include -#include -#include - -// The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 70003 - -#ifdef __clang__ -# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) -#else -# define FMT_CLANG_VERSION 0 -#endif - -#if defined(__GNUC__) && !defined(__clang__) -# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#else -# define FMT_GCC_VERSION 0 -#endif - -#if defined(__INTEL_COMPILER) -# define FMT_ICC_VERSION __INTEL_COMPILER -#else -# define FMT_ICC_VERSION 0 -#endif - -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) -# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION -#else -# define FMT_HAS_GXX_CXX11 0 -#endif - -#ifdef __NVCC__ -# define FMT_NVCC __NVCC__ -#else -# define FMT_NVCC 0 -#endif - -#ifdef _MSC_VER -# define FMT_MSC_VER _MSC_VER -# define FMT_SUPPRESS_MSC_WARNING(n) __pragma(warning(suppress : n)) -#else -# define FMT_MSC_VER 0 -# define FMT_SUPPRESS_MSC_WARNING(n) -#endif -#ifdef __has_feature -# define FMT_HAS_FEATURE(x) __has_feature(x) -#else -# define FMT_HAS_FEATURE(x) 0 -#endif - -#if defined(__has_include) && !defined(__INTELLISENSE__) && \ - !(FMT_ICC_VERSION && FMT_ICC_VERSION < 1600) -# define FMT_HAS_INCLUDE(x) __has_include(x) -#else -# define FMT_HAS_INCLUDE(x) 0 -#endif - -#ifdef __has_cpp_attribute -# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ - (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) - -#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ - (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) - -// Check if relaxed C++14 constexpr is supported. -// GCC doesn't allow throw in constexpr until version 6 (bug 67371). -#ifndef FMT_USE_CONSTEXPR -# define FMT_USE_CONSTEXPR \ - (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ - (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ - !FMT_NVCC && !FMT_ICC_VERSION -#endif -#if FMT_USE_CONSTEXPR -# define FMT_CONSTEXPR constexpr -# define FMT_CONSTEXPR_DECL constexpr -#else -# define FMT_CONSTEXPR inline -# define FMT_CONSTEXPR_DECL -#endif - -#ifndef FMT_OVERRIDE -# if FMT_HAS_FEATURE(cxx_override) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 || \ - FMT_CLANG_VERSION > 600 -# define FMT_OVERRIDE override -# else -# define FMT_OVERRIDE -# endif -#endif - -// Check if exceptions are disabled. -#ifndef FMT_EXCEPTIONS -# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ - FMT_MSC_VER && !_HAS_EXCEPTIONS -# define FMT_EXCEPTIONS 0 -# else -# define FMT_EXCEPTIONS 1 -# endif -#endif - -// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -# define FMT_USE_NOEXCEPT 0 -#endif - -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 -# define FMT_DETECTED_NOEXCEPT noexcept -# define FMT_HAS_CXX11_NOEXCEPT 1 -#else -# define FMT_DETECTED_NOEXCEPT throw() -# define FMT_HAS_CXX11_NOEXCEPT 0 -#endif - -#ifndef FMT_NOEXCEPT -# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT -# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT -# else -# define FMT_NOEXCEPT -# endif -#endif - -// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code -// warnings. -#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ - !FMT_NVCC -# define FMT_NORETURN [[noreturn]] -#else -# define FMT_NORETURN -#endif - -#ifndef FMT_DEPRECATED -# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 -# define FMT_DEPRECATED [[deprecated]] -# else -# if defined(__GNUC__) || defined(__clang__) -# define FMT_DEPRECATED __attribute__((deprecated)) -# elif FMT_MSC_VER -# define FMT_DEPRECATED __declspec(deprecated) -# else -# define FMT_DEPRECATED /* deprecated */ -# endif -# endif -#endif - -// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. -#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC -# define FMT_DEPRECATED_ALIAS -#else -# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED -#endif - -#ifndef FMT_INLINE -# if FMT_GCC_VERSION || FMT_CLANG_VERSION -# define FMT_INLINE inline __attribute__((always_inline)) -# else -# define FMT_INLINE inline -# endif -#endif - -#ifndef FMT_BEGIN_NAMESPACE -# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ - FMT_MSC_VER >= 1900 -# define FMT_INLINE_NAMESPACE inline namespace -# define FMT_END_NAMESPACE \ - } \ - } -# else -# define FMT_INLINE_NAMESPACE namespace -# define FMT_END_NAMESPACE \ - } \ - using namespace v7; \ - } -# endif -# define FMT_BEGIN_NAMESPACE \ - namespace fmt { \ - FMT_INLINE_NAMESPACE v7 { -#endif - -#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) -# define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275) -# ifdef FMT_EXPORT -# define FMT_API __declspec(dllexport) -# define FMT_EXTERN_TEMPLATE_API FMT_API -# define FMT_EXPORTED -# elif defined(FMT_SHARED) -# define FMT_API __declspec(dllimport) -# define FMT_EXTERN_TEMPLATE_API FMT_API -# endif -#else -# define FMT_CLASS_API -#endif -#ifndef FMT_API -# define FMT_API -#endif -#ifndef FMT_EXTERN_TEMPLATE_API -# define FMT_EXTERN_TEMPLATE_API -#endif -#ifndef FMT_INSTANTIATION_DEF_API -# define FMT_INSTANTIATION_DEF_API FMT_API -#endif - -#ifndef FMT_HEADER_ONLY -# define FMT_EXTERN extern -#else -# define FMT_EXTERN -#endif - -// libc++ supports string_view in pre-c++17. -#if (FMT_HAS_INCLUDE() && \ - (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ - (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) -# include -# define FMT_USE_STRING_VIEW -#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L -# include -# define FMT_USE_EXPERIMENTAL_STRING_VIEW -#endif - -#ifndef FMT_UNICODE -# define FMT_UNICODE !FMT_MSC_VER -#endif -#if FMT_UNICODE && FMT_MSC_VER -# pragma execution_character_set("utf-8") -#endif - -FMT_BEGIN_NAMESPACE - -// Implementations of enable_if_t and other metafunctions for older systems. -template -using enable_if_t = typename std::enable_if::type; -template -using conditional_t = typename std::conditional::type; -template using bool_constant = std::integral_constant; -template -using remove_reference_t = typename std::remove_reference::type; -template -using remove_const_t = typename std::remove_const::type; -template -using remove_cvref_t = typename std::remove_cv>::type; -template struct type_identity { using type = T; }; -template using type_identity_t = typename type_identity::type; - -struct monostate {}; - -// An enable_if helper to be used in template parameters which results in much -// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed -// to workaround a bug in MSVC 2019 (see #1140 and #1186). -#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 - -namespace detail { - -// A helper function to suppress bogus "conditional expression is constant" -// warnings. -template constexpr T const_check(T value) { return value; } - -FMT_NORETURN FMT_API void assert_fail(const char* file, int line, - const char* message); - -#ifndef FMT_ASSERT -# ifdef NDEBUG -// FMT_ASSERT is not empty to avoid -Werror=empty-body. -# define FMT_ASSERT(condition, message) ((void)0) -# else -# define FMT_ASSERT(condition, message) \ - ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ - ? (void)0 \ - : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) -# endif -#endif - -#if defined(FMT_USE_STRING_VIEW) -template using std_string_view = std::basic_string_view; -#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) -template -using std_string_view = std::experimental::basic_string_view; -#else -template struct std_string_view {}; -#endif - -#ifdef FMT_USE_INT128 -// Do nothing. -#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER) -# define FMT_USE_INT128 1 -using int128_t = __int128_t; -using uint128_t = __uint128_t; -#else -# define FMT_USE_INT128 0 -#endif -#if !FMT_USE_INT128 -struct int128_t {}; -struct uint128_t {}; -#endif - -// Casts a nonnegative integer to unsigned. -template -FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { - FMT_ASSERT(value >= 0, "negative value"); - return static_cast::type>(value); -} - -FMT_SUPPRESS_MSC_WARNING(4566) constexpr unsigned char micro[] = "\u00B5"; - -template constexpr bool is_unicode() { - return FMT_UNICODE || sizeof(Char) != 1 || - (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5); -} - -#ifdef __cpp_char8_t -using char8_type = char8_t; -#else -enum char8_type : unsigned char {}; -#endif -} // namespace detail - -#ifdef FMT_USE_INTERNAL -namespace internal = detail; // DEPRECATED -#endif - -/** - An implementation of ``std::basic_string_view`` for pre-C++17. It provides a - subset of the API. ``fmt::basic_string_view`` is used for format strings even - if ``std::string_view`` is available to prevent issues when a library is - compiled with a different ``-std`` option than the client code (which is not - recommended). - */ -template class basic_string_view { - private: - const Char* data_; - size_t size_; - - public: - using value_type = Char; - using iterator = const Char*; - - constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} - - /** Constructs a string reference object from a C string and a size. */ - constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT - : data_(s), - size_(count) {} - - /** - \rst - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - \endrst - */ -#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr. - FMT_CONSTEXPR -#endif - basic_string_view(const Char* s) - : data_(s), size_(std::char_traits::length(s)) {} - - /** Constructs a string reference from a ``std::basic_string`` object. */ - template - FMT_CONSTEXPR basic_string_view( - const std::basic_string& s) FMT_NOEXCEPT - : data_(s.data()), - size_(s.size()) {} - - template >::value)> - FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), - size_(s.size()) {} - - /** Returns a pointer to the string data. */ - constexpr const Char* data() const { return data_; } - - /** Returns the string size. */ - constexpr size_t size() const { return size_; } - - constexpr iterator begin() const { return data_; } - constexpr iterator end() const { return data_ + size_; } - - constexpr const Char& operator[](size_t pos) const { return data_[pos]; } - - FMT_CONSTEXPR void remove_prefix(size_t n) { - data_ += n; - size_ -= n; - } - - // Lexicographically compare this string reference to other. - int compare(basic_string_view other) const { - size_t str_size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits::compare(data_, other.data_, str_size); - if (result == 0) - result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); - return result; - } - - friend bool operator==(basic_string_view lhs, basic_string_view rhs) { - return lhs.compare(rhs) == 0; - } - friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { - return lhs.compare(rhs) != 0; - } - friend bool operator<(basic_string_view lhs, basic_string_view rhs) { - return lhs.compare(rhs) < 0; - } - friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { - return lhs.compare(rhs) <= 0; - } - friend bool operator>(basic_string_view lhs, basic_string_view rhs) { - return lhs.compare(rhs) > 0; - } - friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { - return lhs.compare(rhs) >= 0; - } -}; - -using string_view = basic_string_view; -using wstring_view = basic_string_view; - -/** Specifies if ``T`` is a character type. Can be specialized by users. */ -template struct is_char : std::false_type {}; -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; -template <> struct is_char : std::true_type {}; - -/** - \rst - Returns a string view of `s`. In order to add custom string type support to - {fmt} provide an overload of `to_string_view` for it in the same namespace as - the type for the argument-dependent lookup to work. - - **Example**:: - - namespace my_ns { - inline string_view to_string_view(const my_string& s) { - return {s.data(), s.length()}; - } - } - std::string message = fmt::format(my_string("The answer is {}"), 42); - \endrst - */ -template ::value)> -inline basic_string_view to_string_view(const Char* s) { - return s; -} - -template -inline basic_string_view to_string_view( - const std::basic_string& s) { - return s; -} - -template -inline basic_string_view to_string_view(basic_string_view s) { - return s; -} - -template >::value)> -inline basic_string_view to_string_view(detail::std_string_view s) { - return s; -} - -// A base class for compile-time strings. It is defined in the fmt namespace to -// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). -struct compile_string {}; - -template -struct is_compile_string : std::is_base_of {}; - -template ::value)> -constexpr basic_string_view to_string_view(const S& s) { - return s; -} - -namespace detail { -void to_string_view(...); -using fmt::v7::to_string_view; - -// Specifies whether S is a string type convertible to fmt::basic_string_view. -// It should be a constexpr function but MSVC 2017 fails to compile it in -// enable_if and MSVC 2015 fails to compile it as an alias template. -template -struct is_string : std::is_class()))> { -}; - -template struct char_t_impl {}; -template struct char_t_impl::value>> { - using result = decltype(to_string_view(std::declval())); - using type = typename result::value_type; -}; - -struct error_handler { - constexpr error_handler() = default; - constexpr error_handler(const error_handler&) = default; - error_handler& operator=(const error_handler&) = default; - - // This function is intentionally not constexpr to give a compile-time error. - FMT_NORETURN FMT_API void on_error(const char* message); -}; -} // namespace detail - -/** String's character type. */ -template using char_t = typename detail::char_t_impl::type; - -/** - \rst - Parsing context consisting of a format string range being parsed and an - argument counter for automatic indexing. - - You can use one of the following type aliases for common character types: - - +-----------------------+-------------------------------------+ - | Type | Definition | - +=======================+=====================================+ - | format_parse_context | basic_format_parse_context | - +-----------------------+-------------------------------------+ - | wformat_parse_context | basic_format_parse_context | - +-----------------------+-------------------------------------+ - \endrst - */ -template -class basic_format_parse_context : private ErrorHandler { - private: - basic_string_view format_str_; - int next_arg_id_; - - public: - using char_type = Char; - using iterator = typename basic_string_view::iterator; - - explicit constexpr basic_format_parse_context( - basic_string_view format_str, ErrorHandler eh = {}) - : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} - - /** - Returns an iterator to the beginning of the format string range being - parsed. - */ - constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); } - - /** - Returns an iterator past the end of the format string range being parsed. - */ - constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); } - - /** Advances the begin iterator to ``it``. */ - FMT_CONSTEXPR void advance_to(iterator it) { - format_str_.remove_prefix(detail::to_unsigned(it - begin())); - } - - /** - Reports an error if using the manual argument indexing; otherwise returns - the next argument index and switches to the automatic indexing. - */ - FMT_CONSTEXPR int next_arg_id() { - // Don't check if the argument id is valid to avoid overhead and because it - // will be checked during formatting anyway. - if (next_arg_id_ >= 0) return next_arg_id_++; - on_error("cannot switch from manual to automatic argument indexing"); - return 0; - } - - /** - Reports an error if using the automatic argument indexing; otherwise - switches to the manual indexing. - */ - FMT_CONSTEXPR void check_arg_id(int) { - if (next_arg_id_ > 0) - on_error("cannot switch from automatic to manual argument indexing"); - else - next_arg_id_ = -1; - } - - FMT_CONSTEXPR void check_arg_id(basic_string_view) {} - - FMT_CONSTEXPR void on_error(const char* message) { - ErrorHandler::on_error(message); - } - - constexpr ErrorHandler error_handler() const { return *this; } -}; - -using format_parse_context = basic_format_parse_context; -using wformat_parse_context = basic_format_parse_context; - -template class basic_format_arg; -template class basic_format_args; -template class dynamic_format_arg_store; - -// A formatter for objects of type T. -template -struct formatter { - // A deleted default constructor indicates a disabled formatter. - formatter() = delete; -}; - -// Specifies if T has an enabled formatter specialization. A type can be -// formattable even if it doesn't have a formatter e.g. via a conversion. -template -using has_formatter = - std::is_constructible>; - -namespace detail { - -/** - \rst - A contiguous memory buffer with an optional growing ability. It is an internal - class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. - \endrst - */ -template class buffer { - private: - T* ptr_; - size_t size_; - size_t capacity_; - - protected: - // Don't initialize ptr_ since it is not accessed to save a few cycles. - FMT_SUPPRESS_MSC_WARNING(26495) - buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} - - buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT - : ptr_(p), - size_(sz), - capacity_(cap) {} - - /** Sets the buffer data and capacity. */ - void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { - ptr_ = buf_data; - capacity_ = buf_capacity; - } - - /** Increases the buffer capacity to hold at least *capacity* elements. */ - virtual void grow(size_t capacity) = 0; - - public: - using value_type = T; - using const_reference = const T&; - - buffer(const buffer&) = delete; - void operator=(const buffer&) = delete; - virtual ~buffer() = default; - - T* begin() FMT_NOEXCEPT { return ptr_; } - T* end() FMT_NOEXCEPT { return ptr_ + size_; } - - const T* begin() const FMT_NOEXCEPT { return ptr_; } - const T* end() const FMT_NOEXCEPT { return ptr_ + size_; } - - /** Returns the size of this buffer. */ - size_t size() const FMT_NOEXCEPT { return size_; } - - /** Returns the capacity of this buffer. */ - size_t capacity() const FMT_NOEXCEPT { return capacity_; } - - /** Returns a pointer to the buffer data. */ - T* data() FMT_NOEXCEPT { return ptr_; } - - /** Returns a pointer to the buffer data. */ - const T* data() const FMT_NOEXCEPT { return ptr_; } - - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ - void resize(size_t new_size) { - reserve(new_size); - size_ = new_size; - } - - /** Clears this buffer. */ - void clear() { size_ = 0; } - - /** Reserves space to store at least *capacity* elements. */ - void reserve(size_t new_capacity) { - if (new_capacity > capacity_) grow(new_capacity); - } - - void push_back(const T& value) { - reserve(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template void append(const U* begin, const U* end); - - template T& operator[](I index) { return ptr_[index]; } - template const T& operator[](I index) const { - return ptr_[index]; - } -}; - -// A container-backed buffer. -template -class container_buffer : public buffer { - private: - Container& container_; - - protected: - void grow(size_t capacity) FMT_OVERRIDE { - container_.resize(capacity); - this->set(&container_[0], capacity); - } - - public: - explicit container_buffer(Container& c_) - : buffer(c_.size()), container_(c_) {} -}; - -// Extracts a reference to the container from back_insert_iterator. -template -inline Container& get_container(std::back_insert_iterator it) { - using bi_iterator = std::back_insert_iterator; - struct accessor : bi_iterator { - accessor(bi_iterator iter) : bi_iterator(iter) {} - using bi_iterator::container; - }; - return *accessor(it).container; -} - -template -struct fallback_formatter { - fallback_formatter() = delete; -}; - -// Specifies if T has an enabled fallback_formatter specialization. -template -using has_fallback_formatter = - std::is_constructible>; - -struct view {}; - -template struct named_arg : view { - const Char* name; - const T& value; - named_arg(const Char* n, const T& v) : name(n), value(v) {} -}; - -template struct named_arg_info { - const Char* name; - int id; -}; - -template -struct arg_data { - // args_[0].named_args points to named_args_ to avoid bloating format_args. - T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : 1)]; - named_arg_info named_args_[NUM_NAMED_ARGS]; - - template - arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} - arg_data(const arg_data& other) = delete; - const T* args() const { return args_ + 1; } - named_arg_info* named_args() { return named_args_; } -}; - -template -struct arg_data { - T args_[NUM_ARGS != 0 ? NUM_ARGS : 1]; - - template - FMT_INLINE arg_data(const U&... init) : args_{init...} {} - FMT_INLINE const T* args() const { return args_; } - FMT_INLINE std::nullptr_t named_args() { return nullptr; } -}; - -template -inline void init_named_args(named_arg_info*, int, int) {} - -template -void init_named_args(named_arg_info* named_args, int arg_count, - int named_arg_count, const T&, const Tail&... args) { - init_named_args(named_args, arg_count + 1, named_arg_count, args...); -} - -template -void init_named_args(named_arg_info* named_args, int arg_count, - int named_arg_count, const named_arg& arg, - const Tail&... args) { - named_args[named_arg_count++] = {arg.name, arg_count}; - init_named_args(named_args, arg_count + 1, named_arg_count, args...); -} - -template -FMT_INLINE void init_named_args(std::nullptr_t, int, int, const Args&...) {} - -template struct is_named_arg : std::false_type {}; - -template -struct is_named_arg> : std::true_type {}; - -template constexpr size_t count() { return B ? 1 : 0; } -template constexpr size_t count() { - return (B1 ? 1 : 0) + count(); -} - -template constexpr size_t count_named_args() { - return count::value...>(); -} - -enum class type { - none_type, - // Integer types should go first, - int_type, - uint_type, - long_long_type, - ulong_long_type, - int128_type, - uint128_type, - bool_type, - char_type, - last_integer_type = char_type, - // followed by floating-point types. - float_type, - double_type, - long_double_type, - last_numeric_type = long_double_type, - cstring_type, - string_type, - pointer_type, - custom_type -}; - -// Maps core type T to the corresponding type enum constant. -template -struct type_constant : std::integral_constant {}; - -#define FMT_TYPE_CONSTANT(Type, constant) \ - template \ - struct type_constant \ - : std::integral_constant {} - -FMT_TYPE_CONSTANT(int, int_type); -FMT_TYPE_CONSTANT(unsigned, uint_type); -FMT_TYPE_CONSTANT(long long, long_long_type); -FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); -FMT_TYPE_CONSTANT(int128_t, int128_type); -FMT_TYPE_CONSTANT(uint128_t, uint128_type); -FMT_TYPE_CONSTANT(bool, bool_type); -FMT_TYPE_CONSTANT(Char, char_type); -FMT_TYPE_CONSTANT(float, float_type); -FMT_TYPE_CONSTANT(double, double_type); -FMT_TYPE_CONSTANT(long double, long_double_type); -FMT_TYPE_CONSTANT(const Char*, cstring_type); -FMT_TYPE_CONSTANT(basic_string_view, string_type); -FMT_TYPE_CONSTANT(const void*, pointer_type); - -constexpr bool is_integral_type(type t) { - return t > type::none_type && t <= type::last_integer_type; -} - -constexpr bool is_arithmetic_type(type t) { - return t > type::none_type && t <= type::last_numeric_type; -} - -template struct string_value { - const Char* data; - size_t size; -}; - -template struct named_arg_value { - const named_arg_info* data; - size_t size; -}; - -template struct custom_value { - using parse_context = typename Context::parse_context_type; - const void* value; - void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); -}; - -// A formatting argument value. -template class value { - public: - using char_type = typename Context::char_type; - - union { - int int_value; - unsigned uint_value; - long long long_long_value; - unsigned long long ulong_long_value; - int128_t int128_value; - uint128_t uint128_value; - bool bool_value; - char_type char_value; - float float_value; - double double_value; - long double long_double_value; - const void* pointer; - string_value string; - custom_value custom; - named_arg_value named_args; - }; - - constexpr FMT_INLINE value(int val = 0) : int_value(val) {} - constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} - FMT_INLINE value(long long val) : long_long_value(val) {} - FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} - FMT_INLINE value(int128_t val) : int128_value(val) {} - FMT_INLINE value(uint128_t val) : uint128_value(val) {} - FMT_INLINE value(float val) : float_value(val) {} - FMT_INLINE value(double val) : double_value(val) {} - FMT_INLINE value(long double val) : long_double_value(val) {} - FMT_INLINE value(bool val) : bool_value(val) {} - FMT_INLINE value(char_type val) : char_value(val) {} - FMT_INLINE value(const char_type* val) { string.data = val; } - FMT_INLINE value(basic_string_view val) { - string.data = val.data(); - string.size = val.size(); - } - FMT_INLINE value(const void* val) : pointer(val) {} - FMT_INLINE value(const named_arg_info* args, size_t size) - : named_args{args, size} {} - - template FMT_INLINE value(const T& val) { - custom.value = &val; - // Get the formatter type through the context to allow different contexts - // have different extension points, e.g. `formatter` for `format` and - // `printf_formatter` for `printf`. - custom.format = format_custom_arg< - T, conditional_t::value, - typename Context::template formatter_type, - fallback_formatter>>; - } - - private: - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg(const void* arg, - typename Context::parse_context_type& parse_ctx, - Context& ctx) { - Formatter f; - parse_ctx.advance_to(f.parse(parse_ctx)); - ctx.advance_to(f.format(*static_cast(arg), ctx)); - } -}; - -template -FMT_CONSTEXPR basic_format_arg make_arg(const T& value); - -// To minimize the number of types we need to deal with, long is translated -// either to int or to long long depending on its size. -enum { long_short = sizeof(long) == sizeof(int) }; -using long_type = conditional_t; -using ulong_type = conditional_t; - -// Maps formatting arguments to core types. -template struct arg_mapper { - using char_type = typename Context::char_type; - - FMT_CONSTEXPR int map(signed char val) { return val; } - FMT_CONSTEXPR unsigned map(unsigned char val) { return val; } - FMT_CONSTEXPR int map(short val) { return val; } - FMT_CONSTEXPR unsigned map(unsigned short val) { return val; } - FMT_CONSTEXPR int map(int val) { return val; } - FMT_CONSTEXPR unsigned map(unsigned val) { return val; } - FMT_CONSTEXPR long_type map(long val) { return val; } - FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; } - FMT_CONSTEXPR long long map(long long val) { return val; } - FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; } - FMT_CONSTEXPR int128_t map(int128_t val) { return val; } - FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; } - FMT_CONSTEXPR bool map(bool val) { return val; } - - template ::value)> - FMT_CONSTEXPR char_type map(T val) { - static_assert( - std::is_same::value || std::is_same::value, - "mixing character types is disallowed"); - return val; - } - - FMT_CONSTEXPR float map(float val) { return val; } - FMT_CONSTEXPR double map(double val) { return val; } - FMT_CONSTEXPR long double map(long double val) { return val; } - - FMT_CONSTEXPR const char_type* map(char_type* val) { return val; } - FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; } - template ::value)> - FMT_CONSTEXPR basic_string_view map(const T& val) { - static_assert(std::is_same>::value, - "mixing character types is disallowed"); - return to_string_view(val); - } - template , T>::value && - !is_string::value && !has_formatter::value && - !has_fallback_formatter::value)> - FMT_CONSTEXPR basic_string_view map(const T& val) { - return basic_string_view(val); - } - template < - typename T, - FMT_ENABLE_IF( - std::is_constructible, T>::value && - !std::is_constructible, T>::value && - !is_string::value && !has_formatter::value && - !has_fallback_formatter::value)> - FMT_CONSTEXPR basic_string_view map(const T& val) { - return std_string_view(val); - } - FMT_CONSTEXPR const char* map(const signed char* val) { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); - } - FMT_CONSTEXPR const char* map(const unsigned char* val) { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); - } - FMT_CONSTEXPR const char* map(signed char* val) { - const auto* const_val = val; - return map(const_val); - } - FMT_CONSTEXPR const char* map(unsigned char* val) { - const auto* const_val = val; - return map(const_val); - } - - FMT_CONSTEXPR const void* map(void* val) { return val; } - FMT_CONSTEXPR const void* map(const void* val) { return val; } - FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; } - template FMT_CONSTEXPR int map(const T*) { - // Formatting of arbitrary pointers is disallowed. If you want to output - // a pointer cast it to "void *" or "const void *". In particular, this - // forbids formatting of "[const] volatile char *" which is printed as bool - // by iostreams. - static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); - return 0; - } - - template ::value && - !has_formatter::value && - !has_fallback_formatter::value)> - FMT_CONSTEXPR auto map(const T& val) - -> decltype(std::declval().map( - static_cast::type>(val))) { - return map(static_cast::type>(val)); - } - template ::value && !is_char::value && - (has_formatter::value || - has_fallback_formatter::value))> - FMT_CONSTEXPR const T& map(const T& val) { - return val; - } - - template - FMT_CONSTEXPR auto map(const named_arg& val) - -> decltype(std::declval().map(val.value)) { - return map(val.value); - } - - int map(...) { - constexpr bool formattable = sizeof(Context) == 0; - static_assert( - formattable, - "Cannot format argument. To make type T formattable provide a " - "formatter specialization: " - "https://fmt.dev/latest/api.html#formatting-user-defined-types"); - return 0; - } -}; - -// A type constant after applying arg_mapper. -template -using mapped_type_constant = - type_constant().map(std::declval())), - typename Context::char_type>; - -enum { packed_arg_bits = 4 }; -// Maximum number of arguments with packed types. -enum { max_packed_args = 62 / packed_arg_bits }; -enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; -enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; -} // namespace detail - -// A formatting argument. It is a trivially copyable/constructible type to -// allow storage in basic_memory_buffer. -template class basic_format_arg { - private: - detail::value value_; - detail::type type_; - - template - friend FMT_CONSTEXPR basic_format_arg detail::make_arg( - const T& value); - - template - friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, - const basic_format_arg& arg) - -> decltype(vis(0)); - - friend class basic_format_args; - friend class dynamic_format_arg_store; - - using char_type = typename Context::char_type; - - template - friend struct detail::arg_data; - - basic_format_arg(const detail::named_arg_info* args, size_t size) - : value_(args, size) {} - - public: - class handle { - public: - explicit handle(detail::custom_value custom) : custom_(custom) {} - - void format(typename Context::parse_context_type& parse_ctx, - Context& ctx) const { - custom_.format(custom_.value, parse_ctx, ctx); - } - - private: - detail::custom_value custom_; - }; - - constexpr basic_format_arg() : type_(detail::type::none_type) {} - - constexpr explicit operator bool() const FMT_NOEXCEPT { - return type_ != detail::type::none_type; - } - - detail::type type() const { return type_; } - - bool is_integral() const { return detail::is_integral_type(type_); } - bool is_arithmetic() const { return detail::is_arithmetic_type(type_); } -}; - -/** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - ``vis(value)`` will be called with the value of type ``double``. - \endrst - */ -template -FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( - Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { - using char_type = typename Context::char_type; - switch (arg.type_) { - case detail::type::none_type: - break; - case detail::type::int_type: - return vis(arg.value_.int_value); - case detail::type::uint_type: - return vis(arg.value_.uint_value); - case detail::type::long_long_type: - return vis(arg.value_.long_long_value); - case detail::type::ulong_long_type: - return vis(arg.value_.ulong_long_value); -#if FMT_USE_INT128 - case detail::type::int128_type: - return vis(arg.value_.int128_value); - case detail::type::uint128_type: - return vis(arg.value_.uint128_value); -#else - case detail::type::int128_type: - case detail::type::uint128_type: - break; -#endif - case detail::type::bool_type: - return vis(arg.value_.bool_value); - case detail::type::char_type: - return vis(arg.value_.char_value); - case detail::type::float_type: - return vis(arg.value_.float_value); - case detail::type::double_type: - return vis(arg.value_.double_value); - case detail::type::long_double_type: - return vis(arg.value_.long_double_value); - case detail::type::cstring_type: - return vis(arg.value_.string.data); - case detail::type::string_type: - return vis(basic_string_view(arg.value_.string.data, - arg.value_.string.size)); - case detail::type::pointer_type: - return vis(arg.value_.pointer); - case detail::type::custom_type: - return vis(typename basic_format_arg::handle(arg.value_.custom)); - } - return vis(monostate()); -} - -// Checks whether T is a container with contiguous storage. -template struct is_contiguous : std::false_type {}; -template -struct is_contiguous> : std::true_type {}; -template -struct is_contiguous> : std::true_type {}; - -namespace detail { - -template -struct is_back_insert_iterator : std::false_type {}; -template -struct is_back_insert_iterator> - : std::true_type {}; - -template -struct is_contiguous_back_insert_iterator : std::false_type {}; -template -struct is_contiguous_back_insert_iterator> - : is_contiguous {}; - -// A type-erased reference to an std::locale to avoid heavy include. -class locale_ref { - private: - const void* locale_; // A type-erased pointer to std::locale. - - public: - locale_ref() : locale_(nullptr) {} - template explicit locale_ref(const Locale& loc); - - explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } - - template Locale get() const; -}; - -template constexpr unsigned long long encode_types() { return 0; } - -template -constexpr unsigned long long encode_types() { - return static_cast(mapped_type_constant::value) | - (encode_types() << packed_arg_bits); -} - -template -FMT_CONSTEXPR basic_format_arg make_arg(const T& value) { - basic_format_arg arg; - arg.type_ = mapped_type_constant::value; - arg.value_ = arg_mapper().map(value); - return arg; -} - -// The type template parameter is there to avoid an ODR violation when using -// a fallback formatter in one translation unit and an implicit conversion in -// another (not recommended). -template -inline value make_arg(const T& val) { - return arg_mapper().map(val); -} - -template -inline basic_format_arg make_arg(const T& value) { - return make_arg(value); -} - -template struct is_reference_wrapper : std::false_type {}; -template -struct is_reference_wrapper> : std::true_type {}; - -template const T& unwrap(const T& v) { return v; } -template const T& unwrap(const std::reference_wrapper& v) { - return static_cast(v); -} - -class dynamic_arg_list { - // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for - // templates it doesn't complain about inability to deduce single translation - // unit for placing vtable. So storage_node_base is made a fake template. - template struct node { - virtual ~node() = default; - std::unique_ptr> next; - }; - - template struct typed_node : node<> { - T value; - - template - FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} - - template - FMT_CONSTEXPR typed_node(const basic_string_view& arg) - : value(arg.data(), arg.size()) {} - }; - - std::unique_ptr> head_; - - public: - template const T& push(const Arg& arg) { - auto new_node = std::unique_ptr>(new typed_node(arg)); - auto& value = new_node->value; - new_node->next = std::move(head_); - head_ = std::move(new_node); - return value; - } -}; -} // namespace detail - -// Formatting context. -template class basic_format_context { - public: - /** The character type for the output. */ - using char_type = Char; - - private: - OutputIt out_; - basic_format_args args_; - detail::locale_ref loc_; - - public: - using iterator = OutputIt; - using format_arg = basic_format_arg; - using parse_context_type = basic_format_parse_context; - template using formatter_type = formatter; - - basic_format_context(const basic_format_context&) = delete; - void operator=(const basic_format_context&) = delete; - /** - Constructs a ``basic_format_context`` object. References to the arguments are - stored in the object so make sure they have appropriate lifetimes. - */ - basic_format_context(OutputIt out, - basic_format_args ctx_args, - detail::locale_ref loc = detail::locale_ref()) - : out_(out), args_(ctx_args), loc_(loc) {} - - format_arg arg(int id) const { return args_.get(id); } - format_arg arg(basic_string_view name) { return args_.get(name); } - int arg_id(basic_string_view name) { return args_.get_id(name); } - const basic_format_args& args() const { return args_; } - - detail::error_handler error_handler() { return {}; } - void on_error(const char* message) { error_handler().on_error(message); } - - // Returns an iterator to the beginning of the output range. - iterator out() { return out_; } - - // Advances the begin iterator to ``it``. - void advance_to(iterator it) { - if (!detail::is_back_insert_iterator()) out_ = it; - } - - detail::locale_ref locale() { return loc_; } -}; - -template -using buffer_context = - basic_format_context>, Char>; -using format_context = buffer_context; -using wformat_context = buffer_context; - -// Workaround a bug in gcc: https://stackoverflow.com/q/62767544/471164. -#define FMT_BUFFER_CONTEXT(Char) \ - basic_format_context>, Char> - -/** - \rst - An array of references to arguments. It can be implicitly converted into - `~fmt::basic_format_args` for passing into type-erased formatting functions - such as `~fmt::vformat`. - \endrst - */ -template -class format_arg_store -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - // Workaround a GCC template argument substitution bug. - : public basic_format_args -#endif -{ - private: - static const size_t num_args = sizeof...(Args); - static const size_t num_named_args = detail::count_named_args(); - static const bool is_packed = num_args <= detail::max_packed_args; - - using value_type = conditional_t, - basic_format_arg>; - - detail::arg_data - data_; - - friend class basic_format_args; - - static constexpr unsigned long long desc = - (is_packed ? detail::encode_types() - : detail::is_unpacked_bit | num_args) | - (num_named_args != 0 - ? static_cast(detail::has_named_args_bit) - : 0); - - public: - format_arg_store(const Args&... args) - : -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - basic_format_args(*this), -#endif - data_{detail::make_arg< - is_packed, Context, - detail::mapped_type_constant::value>(args)...} { - detail::init_named_args(data_.named_args(), 0, 0, args...); - } -}; - -/** - \rst - Constructs an `~fmt::format_arg_store` object that contains references to - arguments and can be implicitly converted to `~fmt::format_args`. `Context` - can be omitted in which case it defaults to `~fmt::context`. - See `~fmt::arg` for lifetime considerations. - \endrst - */ -template -inline format_arg_store make_format_args( - const Args&... args) { - return {args...}; -} - -/** - \rst - Returns a named argument to be used in a formatting function. It should only - be used in a call to a formatting function. - - **Example**:: - - fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); - \endrst - */ -template -inline detail::named_arg arg(const Char* name, const T& arg) { - static_assert(!detail::is_named_arg(), "nested named arguments"); - return {name, arg}; -} - -/** - \rst - A dynamic version of `fmt::format_arg_store`. - It's equipped with a storage to potentially temporary objects which lifetimes - could be shorter than the format arguments object. - - It can be implicitly converted into `~fmt::basic_format_args` for passing - into type-erased formatting functions such as `~fmt::vformat`. - \endrst - */ -template -class dynamic_format_arg_store -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - // Workaround a GCC template argument substitution bug. - : public basic_format_args -#endif -{ - private: - using char_type = typename Context::char_type; - - template struct need_copy { - static constexpr detail::type mapped_type = - detail::mapped_type_constant::value; - - enum { - value = !(detail::is_reference_wrapper::value || - std::is_same>::value || - std::is_same>::value || - (mapped_type != detail::type::cstring_type && - mapped_type != detail::type::string_type && - mapped_type != detail::type::custom_type)) - }; - }; - - template - using stored_type = conditional_t::value, - std::basic_string, T>; - - // Storage of basic_format_arg must be contiguous. - std::vector> data_; - std::vector> named_info_; - - // Storage of arguments not fitting into basic_format_arg must grow - // without relocation because items in data_ refer to it. - detail::dynamic_arg_list dynamic_args_; - - friend class basic_format_args; - - unsigned long long get_types() const { - return detail::is_unpacked_bit | data_.size() | - (named_info_.empty() - ? 0ULL - : static_cast(detail::has_named_args_bit)); - } - - const basic_format_arg* data() const { - return named_info_.empty() ? data_.data() : data_.data() + 1; - } - - template void emplace_arg(const T& arg) { - data_.emplace_back(detail::make_arg(arg)); - } - - template - void emplace_arg(const detail::named_arg& arg) { - if (named_info_.empty()) { - constexpr const detail::named_arg_info* zero_ptr{nullptr}; - data_.insert(data_.begin(), {zero_ptr, 0}); - } - data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); - auto pop_one = [](std::vector>* data) { - data->pop_back(); - }; - std::unique_ptr>, decltype(pop_one)> - guard{&data_, pop_one}; - named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); - data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; - guard.release(); - } - - public: - /** - \rst - Adds an argument into the dynamic store for later passing to a formatting - function. - - Note that custom types and string types (but not string views) are copied - into the store dynamically allocating memory if necessary. - - **Example**:: - - fmt::dynamic_format_arg_store store; - store.push_back(42); - store.push_back("abc"); - store.push_back(1.5f); - std::string result = fmt::vformat("{} and {} and {}", store); - \endrst - */ - template - void push_back(const T& arg) { - if (detail::const_check(need_copy::value)) { - emplace_arg(dynamic_args_.push >(arg)); - } else { - emplace_arg(detail::unwrap(arg)); - } - } - - /** - \rst - Adds a reference to the argument into the dynamic store for later passing to - a formatting function. Supports named arguments wrapped in - ``std::reference_wrapper`` via ``std::ref()``/``std::cref()``. - - **Example**:: - - fmt::dynamic_format_arg_store store; - char str[] = "1234567890"; - store.push_back(std::cref(str)); - int a1_val{42}; - auto a1 = fmt::arg("a1_", a1_val); - store.push_back(std::cref(a1)); - - // Changing str affects the output but only for string and custom types. - str[0] = 'X'; - - std::string result = fmt::vformat("{} and {a1_}"); - assert(result == "X234567890 and 42"); - \endrst - */ - template void push_back(std::reference_wrapper arg) { - static_assert( - detail::is_named_arg::type>::value || - need_copy::value, - "objects of built-in types and string views are always copied"); - emplace_arg(arg.get()); - } - - /** - Adds named argument into the dynamic store for later passing to a formatting - function. ``std::reference_wrapper`` is supported to avoid copying of the - argument. - */ - template - void push_back(const detail::named_arg& arg) { - const char_type* arg_name = - dynamic_args_.push>(arg.name).c_str(); - if (detail::const_check(need_copy::value)) { - emplace_arg( - fmt::arg(arg_name, dynamic_args_.push>(arg.value))); - } else { - emplace_arg(fmt::arg(arg_name, arg.value)); - } - } - - /** Erase all elements from the store */ - void clear() { - data_.clear(); - named_info_.clear(); - dynamic_args_ = detail::dynamic_arg_list(); - } - - /** - \rst - Reserves space to store at least *new_cap* arguments including - *new_cap_named* named arguments. - \endrst - */ - void reserve(size_t new_cap, size_t new_cap_named) { - FMT_ASSERT(new_cap >= new_cap_named, - "Set of arguments includes set of named arguments"); - data_.reserve(new_cap); - named_info_.reserve(new_cap_named); - } -}; - -/** - \rst - A view of a collection of formatting arguments. To avoid lifetime issues it - should only be used as a parameter type in type-erased functions such as - ``vformat``:: - - void vlog(string_view format_str, format_args args); // OK - format_args args = make_format_args(42); // Error: dangling reference - \endrst - */ -template class basic_format_args { - public: - using size_type = int; - using format_arg = basic_format_arg; - - private: - // A descriptor that contains information about formatting arguments. - // If the number of arguments is less or equal to max_packed_args then - // argument types are passed in the descriptor. This reduces binary code size - // per formatting function call. - unsigned long long desc_; - union { - // If is_packed() returns true then argument values are stored in values_; - // otherwise they are stored in args_. This is done to improve cache - // locality and reduce compiled code size since storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const detail::value* values_; - const format_arg* args_; - }; - - bool is_packed() const { return (desc_ & detail::is_unpacked_bit) == 0; } - bool has_named_args() const { - return (desc_ & detail::has_named_args_bit) != 0; - } - - detail::type type(int index) const { - int shift = index * detail::packed_arg_bits; - unsigned int mask = (1 << detail::packed_arg_bits) - 1; - return static_cast((desc_ >> shift) & mask); - } - - basic_format_args(unsigned long long desc, - const detail::value* values) - : desc_(desc), values_(values) {} - basic_format_args(unsigned long long desc, const format_arg* args) - : desc_(desc), args_(args) {} - - public: - basic_format_args() : desc_(0) {} - - /** - \rst - Constructs a `basic_format_args` object from `~fmt::format_arg_store`. - \endrst - */ - template - FMT_INLINE basic_format_args(const format_arg_store& store) - : basic_format_args(store.desc, store.data_.args()) {} - - /** - \rst - Constructs a `basic_format_args` object from - `~fmt::dynamic_format_arg_store`. - \endrst - */ - FMT_INLINE basic_format_args(const dynamic_format_arg_store& store) - : basic_format_args(store.get_types(), store.data()) {} - - /** - \rst - Constructs a `basic_format_args` object from a dynamic set of arguments. - \endrst - */ - basic_format_args(const format_arg* args, int count) - : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), - args) {} - - /** Returns the argument with the specified id. */ - format_arg get(int id) const { - format_arg arg; - if (!is_packed()) { - if (id < max_size()) arg = args_[id]; - return arg; - } - if (id >= detail::max_packed_args) return arg; - arg.type_ = type(id); - if (arg.type_ == detail::type::none_type) return arg; - arg.value_ = values_[id]; - return arg; - } - - template format_arg get(basic_string_view name) const { - int id = get_id(name); - return id >= 0 ? get(id) : format_arg(); - } - - template int get_id(basic_string_view name) const { - if (!has_named_args()) return -1; - const auto& named_args = - (is_packed() ? values_[-1] : args_[-1].value_).named_args; - for (size_t i = 0; i < named_args.size; ++i) { - if (named_args.data[i].name == name) return named_args.data[i].id; - } - return -1; - } - - int max_size() const { - unsigned long long max_packed = detail::max_packed_args; - return static_cast(is_packed() ? max_packed - : desc_ & ~detail::is_unpacked_bit); - } -}; - -/** An alias to ``basic_format_args``. */ -// It is a separate type rather than an alias to make symbols readable. -struct format_args : basic_format_args { - template - FMT_INLINE format_args(const Args&... args) : basic_format_args(args...) {} -}; -struct wformat_args : basic_format_args { - using basic_format_args::basic_format_args; -}; - -namespace detail { - -// Reports a compile-time error if S is not a valid format string. -template ::value)> -FMT_INLINE void check_format_string(const S&) { -#ifdef FMT_ENFORCE_COMPILE_STRING - static_assert(is_compile_string::value, - "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " - "FMT_STRING."); -#endif -} -template ::value)> -void check_format_string(S); - -template > -inline format_arg_store, remove_reference_t...> -make_args_checked(const S& format_str, - const remove_reference_t&... args) { - static_assert(count<(std::is_base_of>::value && - std::is_reference::value)...>() == 0, - "passing views as lvalues is disallowed"); - check_format_string(format_str); - return {args...}; -} - -template ::value)> -std::basic_string vformat( - basic_string_view format_str, - basic_format_args>> args); - -FMT_API std::string vformat(string_view format_str, format_args args); - -template -typename FMT_BUFFER_CONTEXT(Char)::iterator vformat_to( - buffer& buf, basic_string_view format_str, - basic_format_args)> args); - -template ::value)> -inline void vprint_mojibake(std::FILE*, basic_string_view, const Args&) {} - -FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); -#ifndef _WIN32 -inline void vprint_mojibake(std::FILE*, string_view, format_args) {} -#endif -} // namespace detail - -/** Formats a string and writes the output to ``out``. */ -// GCC 8 and earlier cannot handle std::back_insert_iterator with -// vformat_to(...) overload, so SFINAE on iterator type instead. -template < - typename OutputIt, typename S, typename Char = char_t, - FMT_ENABLE_IF(detail::is_contiguous_back_insert_iterator::value)> -OutputIt vformat_to( - OutputIt out, const S& format_str, - basic_format_args>> args) { - auto& c = detail::get_container(out); - detail::container_buffer> buf(c); - detail::vformat_to(buf, to_string_view(format_str), args); - return out; -} - -template ::value&& detail::is_string::value)> -inline std::back_insert_iterator format_to( - std::back_insert_iterator out, const S& format_str, - Args&&... args) { - return vformat_to(out, to_string_view(format_str), - detail::make_args_checked(format_str, args...)); -} - -template > -FMT_INLINE std::basic_string vformat( - const S& format_str, - basic_format_args>> args) { - return detail::vformat(to_string_view(format_str), args); -} - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - #include - std::string message = fmt::format("The answer is {}", 42); - \endrst -*/ -// Pass char_t as a default template parameter instead of using -// std::basic_string> to reduce the symbol size. -template > -FMT_INLINE std::basic_string format(const S& format_str, Args&&... args) { - const auto& vargs = detail::make_args_checked(format_str, args...); - return detail::vformat(to_string_view(format_str), vargs); -} - -FMT_API void vprint(string_view, format_args); -FMT_API void vprint(std::FILE*, string_view, format_args); - -/** - \rst - Formats ``args`` according to specifications in ``format_str`` and writes the - output to the file ``f``. Strings are assumed to be Unicode-encoded unless the - ``FMT_UNICODE`` macro is set to 0. - - **Example**:: - - fmt::print(stderr, "Don't {}!", "panic"); - \endrst - */ -template > -inline void print(std::FILE* f, const S& format_str, Args&&... args) { - const auto& vargs = detail::make_args_checked(format_str, args...); - return detail::is_unicode() - ? vprint(f, to_string_view(format_str), vargs) - : detail::vprint_mojibake(f, to_string_view(format_str), vargs); -} - -/** - \rst - Formats ``args`` according to specifications in ``format_str`` and writes - the output to ``stdout``. Strings are assumed to be Unicode-encoded unless - the ``FMT_UNICODE`` macro is set to 0. - - **Example**:: - - fmt::print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -template > -inline void print(const S& format_str, Args&&... args) { - const auto& vargs = detail::make_args_checked(format_str, args...); - return detail::is_unicode() - ? vprint(to_string_view(format_str), vargs) - : detail::vprint_mojibake(stdout, to_string_view(format_str), - vargs); -} -FMT_END_NAMESPACE - -#endif // FMT_CORE_H_ +#include "format.h" diff --git a/external/fmt/include/fmt/format-inl.h b/external/fmt/include/fmt/format-inl.h index d8c9c8a5ee..a887483b6f 100644 --- a/external/fmt/include/fmt/format-inl.h +++ b/external/fmt/include/fmt/format-inl.h @@ -8,42 +8,23 @@ #ifndef FMT_FORMAT_INL_H_ #define FMT_FORMAT_INL_H_ -#include -#include -#include -#include -#include -#include // for std::memmove -#include -#include - -#include "format.h" -#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) -# include -#endif - -#ifdef _WIN32 -# if !defined(NOMINMAX) && !defined(WIN32_LEAN_AND_MEAN) -# define NOMINMAX -# define WIN32_LEAN_AND_MEAN -# include -# undef WIN32_LEAN_AND_MEAN -# undef NOMINMAX -# else -# include +#ifndef FMT_MODULE +# include +# include // errno +# include +# include +# include + +# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# include # endif -# include #endif -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4702) // unreachable code +#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) +# include // _isatty #endif -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -inline fmt::detail::null<> strerror_r(int, char*, ...) { return {}; } -inline fmt::detail::null<> strerror_s(char*, size_t, ...) { return {}; } +#include "format.h" FMT_BEGIN_NAMESPACE namespace detail { @@ -57,95 +38,12 @@ FMT_FUNC void assert_fail(const char* file, int line, const char* message) { std::terminate(); } -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -// A portable thread-safe version of strerror. -// Sets buffer to point to a string describing the error code. -// This can be either a pointer to a string stored in buffer, -// or a pointer to some static immutable string. -// Returns one of the following values: -// 0 - success -// ERANGE - buffer is not large enough to store the error message -// other - failure -// Buffer should be at least of size 1. -FMT_FUNC int safe_strerror(int error_code, char*& buffer, - size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != nullptr && buffer_size != 0, "invalid buffer"); - - class dispatcher { - private: - int error_code_; - char*& buffer_; - size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const dispatcher&) {} - - // Handle the result of XSI-compliant version of strerror_r. - int handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - FMT_MAYBE_UNUSED - int handle(char* message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) - return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - FMT_MAYBE_UNUSED - int handle(detail::null<>) { - return fallback(strerror_s(buffer_, buffer_size_, error_code_)); - } - - // Fallback to strerror_s when strerror_r is not available. - FMT_MAYBE_UNUSED - int fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE - : result; - } - -#if !FMT_MSC_VER - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(detail::null<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } -#endif - - public: - dispatcher(int err_code, char*& buf, size_t buf_size) - : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} - - int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); } - }; - return dispatcher(error_code, buffer, buffer_size).run(); -} - FMT_FUNC void format_error_code(detail::buffer& out, int error_code, - string_view message) FMT_NOEXCEPT { + string_view message) noexcept { // Report error code making sure that the output fits into // inline_buffer_size to avoid dynamic memory allocation and potential // bad_alloc. - out.resize(0); + out.try_resize(0); static const char SEP[] = ": "; static const char ERROR_STR[] = "error "; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. @@ -156,1178 +54,1352 @@ FMT_FUNC void format_error_code(detail::buffer& out, int error_code, ++error_code_size; } error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); - auto it = std::back_inserter(out); + auto it = appender(out); if (message.size() <= inline_buffer_size - error_code_size) - format_to(it, "{}{}", message, SEP); - format_to(it, "{}{}", ERROR_STR, error_code); - assert(out.size() <= inline_buffer_size); + fmt::format_to(it, FMT_STRING("{}{}"), message, SEP); + fmt::format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); + FMT_ASSERT(out.size() <= inline_buffer_size, ""); } FMT_FUNC void report_error(format_func func, int error_code, - string_view message) FMT_NOEXCEPT { + const char* message) noexcept { memory_buffer full_message; func(full_message, error_code, message); // Don't use fwrite_fully because the latter may throw. - (void)std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); + if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) + std::fputc('\n', stderr); } // A wrapper around fwrite that throws on error. -FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count, - FILE* stream) { - size_t written = std::fwrite(ptr, size, count, stream); - if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); +inline void fwrite_fully(const void* ptr, size_t count, FILE* stream) { + size_t written = std::fwrite(ptr, 1, count, stream); + if (written < count) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); } -} // namespace detail - -#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) -namespace detail { +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR template locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { static_assert(std::is_same::value, ""); } -template Locale locale_ref::get() const { +template auto locale_ref::get() const -> Locale { static_assert(std::is_same::value, ""); return locale_ ? *static_cast(locale_) : std::locale(); } -template FMT_FUNC std::string grouping_impl(locale_ref loc) { - return std::use_facet>(loc.get()).grouping(); -} -template FMT_FUNC Char thousands_sep_impl(locale_ref loc) { - return std::use_facet>(loc.get()) - .thousands_sep(); +template +FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { + auto& facet = std::use_facet>(loc.get()); + auto grouping = facet.grouping(); + auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); + return {std::move(grouping), thousands_sep}; } -template FMT_FUNC Char decimal_point_impl(locale_ref loc) { +template +FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char { return std::use_facet>(loc.get()) .decimal_point(); } -} // namespace detail #else template -FMT_FUNC std::string detail::grouping_impl(locale_ref) { - return "\03"; -} -template FMT_FUNC Char detail::thousands_sep_impl(locale_ref) { - return FMT_STATIC_THOUSANDS_SEPARATOR; +FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { + return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; } -template FMT_FUNC Char detail::decimal_point_impl(locale_ref) { +template FMT_FUNC Char decimal_point_impl(locale_ref) { return '.'; } #endif -FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default; -FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT = default; +FMT_FUNC auto write_loc(appender out, loc_value value, + const format_specs& specs, locale_ref loc) -> bool { +#ifdef FMT_STATIC_THOUSANDS_SEPARATOR + value.visit(loc_writer<>{ + out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."}); + return true; +#else + auto locale = loc.get(); + // We cannot use the num_put facet because it may produce output in + // a wrong encoding. + using facet = format_facet; + if (std::has_facet(locale)) + return std::use_facet(locale).put(out, value, specs); + return facet(locale).put(out, value, specs); +#endif +} +} // namespace detail -FMT_FUNC void system_error::init(int err_code, string_view format_str, - format_args args) { - error_code_ = err_code; - memory_buffer buffer; - format_system_error(buffer, err_code, vformat(format_str, args)); - std::runtime_error& base = *this; - base = std::runtime_error(to_string(buffer)); +FMT_FUNC void report_error(const char* message) { + FMT_THROW(format_error(message)); } -namespace detail { +template typename Locale::id format_facet::id; -template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) { - // fallback_uintptr is always stored in little endian. - int i = static_cast(sizeof(void*)) - 1; - while (i > 0 && n.value[i] == 0) --i; - auto char_digits = std::numeric_limits::digits / 4; - return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template format_facet::format_facet(Locale& loc) { + auto& numpunct = std::use_facet>(loc); + grouping_ = numpunct.grouping(); + if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep()); } -template -const typename basic_data::digit_pair basic_data::digits[] = { - {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, - {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, - {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, - {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'}, - {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'}, - {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, - {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, - {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, - {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'}, - {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'}, - {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'}, - {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, - {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, - {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, - {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'}, - {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'}, - {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'}, - {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, - {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, - {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; +template <> +FMT_API FMT_FUNC auto format_facet::do_put( + appender out, loc_value val, const format_specs& specs) const -> bool { + return val.visit( + detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_}); +} +#endif -template -const char basic_data::hex_digits[] = "0123456789abcdef"; +FMT_FUNC auto vsystem_error(int error_code, string_view fmt, format_args args) + -> std::system_error { + auto ec = std::error_code(error_code, std::generic_category()); + return std::system_error(ec, vformat(fmt, args)); +} -#define FMT_POWERS_OF_10(factor) \ - factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ - (factor)*1000000, (factor)*10000000, (factor)*100000000, \ - (factor)*1000000000 +namespace detail { -template -const uint64_t basic_data::powers_of_10_64[] = { - 1, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; +template +inline auto operator==(basic_fp x, basic_fp y) -> bool { + return x.f == y.f && x.e == y.e; +} -template -const uint32_t basic_data::zero_or_powers_of_10_32[] = {0, - FMT_POWERS_OF_10(1)}; +// Compilers should be able to optimize this into the ror instruction. +FMT_CONSTEXPR inline auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t { + r &= 31; + return (n >> r) | (n << (32 - r)); +} +FMT_CONSTEXPR inline auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t { + r &= 63; + return (n >> r) | (n << (64 - r)); +} -template -const uint64_t basic_data::zero_or_powers_of_10_64[] = { - 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; +// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +namespace dragonbox { +// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_upper64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return umul128_upper64(static_cast(x) << 32, y); +} -// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. -// These are generated by support/compute-powers.py. -template -const uint64_t basic_data::pow10_significands[] = { - 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, - 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, - 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, - 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, - 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, - 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, - 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, - 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, - 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, - 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, - 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, - 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, - 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, - 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, - 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, - 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, - 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, - 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, - 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, - 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, - 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, - 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, - 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, - 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, - 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, - 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, - 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, - 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, - 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, -}; +// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_lower128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint64_t high = x * y.high(); + uint128_fallback high_low = umul128(x, y.low()); + return {high + high_low.high(), high_low.low()}; +} -// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding -// to significands above. -template -const int16_t basic_data::pow10_exponents[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, - -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, - -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, - -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, - -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, - 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, - 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, - 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; +// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_lower64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return x * y; +} -template -const char basic_data::foreground_color[] = "\x1b[38;2;"; -template -const char basic_data::background_color[] = "\x1b[48;2;"; -template const char basic_data::reset_color[] = "\x1b[0m"; -template const wchar_t basic_data::wreset_color[] = L"\x1b[0m"; -template const char basic_data::signs[] = {0, '-', '+', ' '}; -template -const char basic_data::left_padding_shifts[] = {31, 31, 0, 1, 0}; -template -const char basic_data::right_padding_shifts[] = {0, 31, 0, 1, 0}; +// Various fast log computations. +inline auto floor_log10_pow2_minus_log10_4_over_3(int e) noexcept -> int { + FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); + return (e * 631305 - 261663) >> 21; +} -template struct bits { - static FMT_CONSTEXPR_DECL const int value = - static_cast(sizeof(T) * std::numeric_limits::digits); -}; +FMT_INLINE_VARIABLE constexpr struct { + uint32_t divisor; + int shift_amount; +} div_small_pow10_infos[] = {{10, 16}, {100, 16}}; + +// Replaces n by floor(n / pow(10, N)) returning true if and only if n is +// divisible by pow(10, N). +// Precondition: n <= pow(10, N + 1). +template +auto check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept -> bool { + // The numbers below are chosen such that: + // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100, + // 2. nm mod 2^k < m if and only if n is divisible by d, + // where m is magic_number, k is shift_amount + // and d is divisor. + // + // Item 1 is a common technique of replacing division by a constant with + // multiplication, see e.g. "Division by Invariant Integers Using + // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set + // to ceil(2^k/d) for large enough k. + // The idea for item 2 originates from Schubfach. + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + n *= magic_number; + const uint32_t comparison_mask = (1u << info.shift_amount) - 1; + bool result = (n & comparison_mask) < magic_number; + n >>= info.shift_amount; + return result; +} -class fp; -template fp normalize(fp value); +// Computes floor(n / pow(10, N)) for small n and N. +// Precondition: n <= pow(10, N + 1). +template auto small_division_by_pow10(uint32_t n) noexcept -> uint32_t { + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + return (n * magic_number) >> info.shift_amount; +} -// Lower (upper) boundary is a value half way between a floating-point value -// and its predecessor (successor). Boundaries have the same exponent as the -// value so only significands are stored. -struct boundaries { - uint64_t lower; - uint64_t upper; -}; +// Computes floor(n / 10^(kappa + 1)) (float) +inline auto divide_by_10_to_kappa_plus_1(uint32_t n) noexcept -> uint32_t { + // 1374389535 = ceil(2^37/100) + return static_cast((static_cast(n) * 1374389535) >> 37); +} +// Computes floor(n / 10^(kappa + 1)) (double) +inline auto divide_by_10_to_kappa_plus_1(uint64_t n) noexcept -> uint64_t { + // 2361183241434822607 = ceil(2^(64+7)/1000) + return umul128_upper64(n, 2361183241434822607ull) >> 7; +} -// A handmade floating-point number f * pow(2, e). -class fp { - private: - using significand_type = uint64_t; +// Various subroutines using pow10 cache +template struct cache_accessor; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint64_t; + + static auto get_cached_power(int k) noexcept -> uint64_t { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + static constexpr const uint64_t pow10_significands[] = { + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, + 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, + 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, + 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, + 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, + 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, + 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, + 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, + 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, + 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, + 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, + 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, + 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985, + 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, + 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7, + 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21, + 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, + 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; + return pow10_significands[k - float_info::min_k]; + } - public: - significand_type f; - int e; - - // All sizes are in bits. - // Subtract 1 to account for an implicit most significant bit in the - // normalized form. - static FMT_CONSTEXPR_DECL const int double_significand_size = - std::numeric_limits::digits - 1; - static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = - 1ULL << double_significand_size; - static FMT_CONSTEXPR_DECL const int significand_size = - bits::value; - - fp() : f(0), e(0) {} - fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} - - // Constructs fp from an IEEE754 double. It is a template to prevent compile - // errors on platforms where double is not IEEE754. - template explicit fp(Double d) { assign(d); } - - // Assigns d to this and return true iff predecessor is closer than successor. - template - bool assign(Double d) { - // Assume double is in the format [sign][exponent][significand]. - using limits = std::numeric_limits; - const int exponent_size = - bits::value - double_significand_size - 1; // -1 for sign - const uint64_t significand_mask = implicit_bit - 1; - const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask; - const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; - auto u = bit_cast(d); - f = u & significand_mask; - int biased_e = - static_cast((u & exponent_mask) >> double_significand_size); - // Predecessor is closer if d is a normalized power of 2 (f == 0) other than - // the smallest normalized number (biased_e > 1). - bool is_predecessor_closer = f == 0 && biased_e > 1; - if (biased_e != 0) - f += implicit_bit; - else - biased_e = 1; // Subnormals use biased exponent 1 (min exponent). - e = biased_e - exponent_bias - double_significand_size; - return is_predecessor_closer; + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul96_upper64(u, cache); + return {static_cast(r >> 32), + static_cast(r) == 0}; } - template - bool assign(Double) { - *this = fp(); - return false; + static auto compute_delta(const cache_entry_type& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache >> (64 - 1 - beta)); } - // Assigns d to this together with computing lower and upper boundaries, - // where a boundary is a value half way between the number and its predecessor - // (lower) or successor (upper). The upper boundary is normalized and lower - // has the same exponent but may be not normalized. - template boundaries assign_with_boundaries(Double d) { - bool is_lower_closer = assign(d); - fp lower = - is_lower_closer ? fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1); - // 1 in normalize accounts for the exponent shift above. - fp upper = normalize<1>(fp((f << 1) + 1, e - 1)); - lower.f <<= lower.e - upper.e; - return boundaries{lower.f, upper.f}; + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul96_lower64(two_f, cache); + return {((r >> (64 - beta)) & 1) != 0, + static_cast(r >> (32 - beta)) == 0}; } - template boundaries assign_float_with_boundaries(Double d) { - assign(d); - constexpr int min_normal_e = std::numeric_limits::min_exponent - - std::numeric_limits::digits; - significand_type half_ulp = 1 << (std::numeric_limits::digits - - std::numeric_limits::digits - 1); - if (min_normal_e > e) half_ulp <<= min_normal_e - e; - fp upper = normalize<0>(fp(f + half_ulp, e)); - fp lower = fp( - f - (half_ulp >> ((f == implicit_bit && e > min_normal_e) ? 1 : 0)), e); - lower.f <<= lower.e - upper.e; - return boundaries{lower.f, upper.f}; + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache - (cache >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta)); } -}; -// Normalizes the value converted from double and multiplied by (1 << SHIFT). -template fp normalize(fp value) { - // Handle subnormals. - const auto shifted_implicit_bit = fp::implicit_bit << SHIFT; - while ((value.f & shifted_implicit_bit) == 0) { - value.f <<= 1; - --value.e; + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache + (cache >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta)); } - // Subtract 1 to account for hidden bit. - const auto offset = - fp::significand_size - fp::double_significand_size - SHIFT - 1; - value.f <<= offset; - value.e -= offset; - return value; -} -inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; } + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (static_cast( + cache >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; -// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. -inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { -#if FMT_USE_INT128 - auto product = static_cast<__uint128_t>(lhs) * rhs; - auto f = static_cast(product >> 64); - return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint128_fallback; + + static auto get_cached_power(int k) noexcept -> uint128_fallback { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + + static constexpr const uint128_fallback pow10_significands[] = { +#if FMT_USE_FULL_CACHE_DRAGONBOX + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0x9faacf3df73609b1, 0x77b191618c54e9ad}, + {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, + {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, + {0x9becce62836ac577, 0x4ee367f9430aec33}, + {0xc2e801fb244576d5, 0x229c41f793cda740}, + {0xf3a20279ed56d48a, 0x6b43527578c11110}, + {0x9845418c345644d6, 0x830a13896b78aaaa}, + {0xbe5691ef416bd60c, 0x23cc986bc656d554}, + {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, + {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, + {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, + {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, + {0x91376c36d99995be, 0x23100809b9c21fa2}, + {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, + {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, + {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, + {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, + {0xdd95317f31c7fa1d, 0x40405643d711d584}, + {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, + {0xad1c8eab5ee43b66, 0xda3243650005eed0}, + {0xd863b256369d4a40, 0x90bed43e40076a83}, + {0x873e4f75e2224e68, 0x5a7744a6e804a292}, + {0xa90de3535aaae202, 0x711515d0a205cb37}, + {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, + {0x8412d9991ed58091, 0xe858790afe9486c3}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, + {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, + {0xc987434744ac874e, 0xa327ffb266b56221}, + {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, + {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, + {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, + {0xf6019da07f549b2b, 0x7e2a53a146606a49}, + {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, + {0xc0314325637a1939, 0xfa911155fefb5309}, + {0xf03d93eebc589f88, 0x793555ab7eba27cb}, + {0x96267c7535b763b5, 0x4bc1558b2f3458df}, + {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, + {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, + {0x92a1958a7675175f, 0x0bfacd89ec191eca}, + {0xb749faed14125d36, 0xcef980ec671f667c}, + {0xe51c79a85916f484, 0x82b7e12780e7401b}, + {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, + {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, + {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, + {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, + {0xaecc49914078536d, 0x58fae9f773886e19}, + {0xda7f5bf590966848, 0xaf39a475506a899f}, + {0x888f99797a5e012d, 0x6d8406c952429604}, + {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, + {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, + {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0xd0601d8efc57b08b, 0xf13b94daf124da27}, + {0x823c12795db6ce57, 0x76c53d08d6b70859}, + {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, + {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, + {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, + {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, + {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, + {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, + {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, + {0xc21094364dfb5636, 0x985915fc12f542e5}, + {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, + {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, + {0xbd8430bd08277231, 0x50c6ff782a838354}, + {0xece53cec4a314ebd, 0xa4f8bf5635246429}, + {0x940f4613ae5ed136, 0x871b7795e136be9a}, + {0xb913179899f68584, 0x28e2557b59846e40}, + {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, + {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, + {0xb4bca50b065abe63, 0x0fed077a756b53aa}, + {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, + {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, + {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, + {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, + {0x89e42caaf9491b60, 0xf41686c49db57245}, + {0xac5d37d5b79b6239, 0x311c2875c522ced6}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, + {0xd267caa862a12d66, 0xd072df63c324fd7c}, + {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, + {0xa46116538d0deb78, 0x52d9be85f074e609}, + {0xcd795be870516656, 0x67902e276c921f8c}, + {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, + {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, + {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, + {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, + {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, + {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, + {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, + {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, + {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, + {0xef340a98172aace4, 0x86fb897116c87c35}, + {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, + {0xbae0a846d2195712, 0x8974836059cca10a}, + {0xe998d258869facd7, 0x2bd1a438703fc94c}, + {0x91ff83775423cc06, 0x7b6306a34627ddd0}, + {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, + {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, + {0x8e938662882af53e, 0x547eb47b7282ee9d}, + {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, + {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, + {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, + {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, + {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, + {0xd47487cc8470652b, 0x7647c32000696720}, + {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, + {0xa5fb0a17c777cf09, 0xf468107100525891}, + {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, + {0x81ac1fe293d599bf, 0xc6f14cd848405531}, + {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, + {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, + {0xfd442e4688bd304a, 0x908f4a166d1da664}, + {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, + {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, + {0xf7549530e188c128, 0xd12bee59e68ef47d}, + {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, + {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, + {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, + {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, + {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, + {0xebdf661791d60f56, 0x111b495b3464ad22}, + {0x936b9fcebb25c995, 0xcab10dd900beec35}, + {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, + {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, + {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, + {0xb3f4e093db73a093, 0x59ed216765690f57}, + {0xe0f218b8d25088b8, 0x306869c13ec3532d}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, + {0x894bc396ce5da772, 0x6b8bba8c328eb784}, + {0xab9eb47c81f5114f, 0x066ea92f3f326565}, + {0xd686619ba27255a2, 0xc80a537b0efefebe}, + {0x8613fd0145877585, 0xbd06742ce95f5f37}, + {0xa798fc4196e952e7, 0x2c48113823b73705}, + {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, + {0x82ef85133de648c4, 0x9a984d73dbe722fc}, + {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, + {0xcc963fee10b7d1b3, 0x318df905079926a9}, + {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, + {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, + {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, + {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, + {0x9c1661a651213e2d, 0x06bea10ca65c084f}, + {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, + {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, + {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, + {0xbe89523386091465, 0xf6bbb397f1135824}, + {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, + {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, + {0xba121a4650e4ddeb, 0x92f34d62616ce414}, + {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, + {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, + {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, + {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, + {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, + {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, + {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, + {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, + {0x87625f056c7c4a8b, 0x11471cd764ad4973}, + {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, + {0xd389b47879823479, 0x4aff1d108d4ec2c4}, + {0x843610cb4bf160cb, 0xcedf722a585139bb}, + {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, + {0xce947a3da6a9273e, 0x733d226229feea33}, + {0x811ccc668829b887, 0x0806357d5a3f5260}, + {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, + {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, + {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, + {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, + {0xc5029163f384a931, 0x0a9e795e65d4df12}, + {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, + {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, + {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, + {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, + {0x964e858c91ba2655, 0x3a6a07f8d510f870}, + {0xbbe226efb628afea, 0x890489f70a55368c}, + {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, + {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, + {0xb32df8e9f3546564, 0x47939822dc96abfa}, + {0xdff9772470297ebd, 0x59787e2b93bc56f8}, + {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, + {0xaefae51477a06b03, 0xede622920b6b23f2}, + {0xdab99e59958885c4, 0xe95fab368e45ecee}, + {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, + {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, + {0xd59944a37c0752a2, 0x4be76d3346f04960}, + {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, + {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, + {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, + {0x825ecc24c873782f, 0x8ed400668c0c28c9}, + {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, + {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, + {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, + {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, + {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, + {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, + {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, + {0xc24452da229b021b, 0xfbe85badce996169}, + {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, + {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, + {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, + {0xed246723473e3813, 0x290123e9aab23b69}, + {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, + {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, + {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, + {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, + {0x8d590723948a535f, 0x579c487e5a38ad0f}, + {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, + {0xdcdb1b2798182244, 0xf8e431456cf88e66}, + {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, + {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, + {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, + {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, + {0xa87fea27a539e9a5, 0x3f2398d747b36225}, + {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, + {0x83a3eeeef9153e89, 0x1953cf68300424ad}, + {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, + {0xcdb02555653131b6, 0x3792f412cb06794e}, + {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, + {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, + {0xc8de047564d20a8b, 0xf245825a5a445276}, + {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, + {0x9ced737bb6c4183d, 0x55464dd69685606c}, + {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, + {0xf53304714d9265df, 0xd53dd99f4b3066a9}, + {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, + {0xbf8fdb78849a5f96, 0xde98520472bdd034}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xbb127c53b17ec159, 0x5560c018580d5d53}, + {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, + {0x9226712162ab070d, 0xcab3961304ca70e9}, + {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, + {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, + {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, + {0xb267ed1940f1c61c, 0x55f038b237591ed4}, + {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, + {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, + {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, + {0xd9c7dced53c72255, 0x96e7bd358c904a22}, + {0x881cea14545c7575, 0x7e50d64177da2e55}, + {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, + {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, + {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, + {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, + {0xcfb11ead453994ba, 0x67de18eda5814af3}, + {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, + {0xa2425ff75e14fc31, 0xa1258379a94d028e}, + {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, + {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, + {0x9e74d1b791e07e48, 0x775ea264cf55347e}, + {0xc612062576589dda, 0x95364afe032a819e}, + {0xf79687aed3eec551, 0x3a83ddbd83f52205}, + {0x9abe14cd44753b52, 0xc4926a9672793543}, + {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, + {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, + {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, + {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, + {0xb877aa3236a4b449, 0x09befeb9fad487c3}, + {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, + {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, + {0xb424dc35095cd80f, 0x538484c19ef38c95}, + {0xe12e13424bb40e13, 0x2865a5f206b06fba}, + {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, + {0xafebff0bcb24aafe, 0xf78f69a51539d749}, + {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, + {0x89705f4136b4a597, 0x31680a88f8953031}, + {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, + {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, + {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, + {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, + {0xd1b71758e219652b, 0xd3c36113404ea4a9}, + {0x83126e978d4fdf3b, 0x645a1cac083126ea}, + {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, + {0xcccccccccccccccc, 0xcccccccccccccccd}, + {0x8000000000000000, 0x0000000000000000}, + {0xa000000000000000, 0x0000000000000000}, + {0xc800000000000000, 0x0000000000000000}, + {0xfa00000000000000, 0x0000000000000000}, + {0x9c40000000000000, 0x0000000000000000}, + {0xc350000000000000, 0x0000000000000000}, + {0xf424000000000000, 0x0000000000000000}, + {0x9896800000000000, 0x0000000000000000}, + {0xbebc200000000000, 0x0000000000000000}, + {0xee6b280000000000, 0x0000000000000000}, + {0x9502f90000000000, 0x0000000000000000}, + {0xba43b74000000000, 0x0000000000000000}, + {0xe8d4a51000000000, 0x0000000000000000}, + {0x9184e72a00000000, 0x0000000000000000}, + {0xb5e620f480000000, 0x0000000000000000}, + {0xe35fa931a0000000, 0x0000000000000000}, + {0x8e1bc9bf04000000, 0x0000000000000000}, + {0xb1a2bc2ec5000000, 0x0000000000000000}, + {0xde0b6b3a76400000, 0x0000000000000000}, + {0x8ac7230489e80000, 0x0000000000000000}, + {0xad78ebc5ac620000, 0x0000000000000000}, + {0xd8d726b7177a8000, 0x0000000000000000}, + {0x878678326eac9000, 0x0000000000000000}, + {0xa968163f0a57b400, 0x0000000000000000}, + {0xd3c21bcecceda100, 0x0000000000000000}, + {0x84595161401484a0, 0x0000000000000000}, + {0xa56fa5b99019a5c8, 0x0000000000000000}, + {0xcecb8f27f4200f3a, 0x0000000000000000}, + {0x813f3978f8940984, 0x4000000000000000}, + {0xa18f07d736b90be5, 0x5000000000000000}, + {0xc9f2c9cd04674ede, 0xa400000000000000}, + {0xfc6f7c4045812296, 0x4d00000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xc5371912364ce305, 0x6c28000000000000}, + {0xf684df56c3e01bc6, 0xc732000000000000}, + {0x9a130b963a6c115c, 0x3c7f400000000000}, + {0xc097ce7bc90715b3, 0x4b9f100000000000}, + {0xf0bdc21abb48db20, 0x1e86d40000000000}, + {0x96769950b50d88f4, 0x1314448000000000}, + {0xbc143fa4e250eb31, 0x17d955a000000000}, + {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, + {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, + {0xb7abc627050305ad, 0xf14a3d9e40000000}, + {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, + {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, + {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, + {0xe0352f62a19e306e, 0xd50b2037ad200000}, + {0x8c213d9da502de45, 0x4526f422cc340000}, + {0xaf298d050e4395d6, 0x9670b12b7f410000}, + {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, + {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, + {0xab0e93b6efee0053, 0x8eea0d047a457a00}, + {0xd5d238a4abe98068, 0x72a4904598d6d880}, + {0x85a36366eb71f041, 0x47a6da2b7f864750}, + {0xa70c3c40a64e6c51, 0x999090b65f67d924}, + {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, + {0x82818f1281ed449f, 0xbff8f10e7a8921a5}, + {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, + {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, + {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, + {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, + {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, + {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, + {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, + {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, + {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, + {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, + {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, + {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, + {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, + {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, + {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, + {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, + {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, + {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, + {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, + {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, + {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, + {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, + {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, + {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, + {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, + {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, + {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, + {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, + {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, + {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, + {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, + {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, + {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, + {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, + {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, + {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, + {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, + {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, + {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, + {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, + {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, + {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, + {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, + {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, + {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, + {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, + {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, + {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, + {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, + {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, + {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, + {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, + {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, + {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, + {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, + {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, + {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, + {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, + {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, + {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, + {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, + {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, + {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, + {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, + {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, + {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, + {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, + {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, + {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, + {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, + {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, + {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, + {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, + {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, + {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, + {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, + {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, + {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, + {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, + {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, + {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, + {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, + {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, + {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, + {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, + {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, + {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, + {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, + {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, + {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, + {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, + {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, + {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, + {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, + {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, + {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, + {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, + {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, + {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, + {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, + {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, + {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, + {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, + {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, + {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, + {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, + {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, + {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, + {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, + {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, + {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, + {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, + {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, + {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, + {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, + {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, + {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, + {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, + {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, + {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, + {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, + {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, + {0xc5a05277621be293, 0xc7098b7305241886}, + {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}, + {0x9a65406d44a5c903, 0x737f74f1dc043329}, + {0xc0fe908895cf3b44, 0x505f522e53053ff3}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0}, + {0x96c6e0eab509e64d, 0x5eca783430dc19f6}, + {0xbc789925624c5fe0, 0xb67d16413d132073}, + {0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890}, + {0x933e37a534cbaae7, 0x8e91b962f7b6f15a}, + {0xb80dc58e81fe95a1, 0x723627bbb5a4adb1}, + {0xe61136f2227e3b09, 0xcec3b1aaa30dd91d}, + {0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2}, + {0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e}, + {0xe0accfa875af45a7, 0x93eb1b80a33b8606}, + {0x8c6c01c9498d8b88, 0xbc72f130660533c4}, + {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5}, + {0xdb68c2ca82ed2a05, 0xa67398db9f6820e2}, #else - // Multiply 32-bit parts of significands. - uint64_t mask = (1ULL << 32) - 1; - uint64_t a = lhs >> 32, b = lhs & mask; - uint64_t c = rhs >> 32, d = rhs & mask; - uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; - // Compute mid 64-bit of result and round. - uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); - return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0xc350000000000000, 0x0000000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0} #endif -} - -inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; } - -// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its -// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. -inline fp get_cached_power(int min_exponent, int& pow10_exponent) { - const int64_t one_over_log2_10 = 0x4d104d42; // round(pow(2, 32) / log2(10)) - int index = static_cast( - ((min_exponent + fp::significand_size - 1) * one_over_log2_10 + - ((int64_t(1) << 32) - 1)) // ceil - >> 32 // arithmetic shift - ); - // Decimal exponent of the first (smallest) cached power of 10. - const int first_dec_exp = -348; - // Difference between 2 consecutive decimal exponents in cached powers of 10. - const int dec_exp_step = 8; - index = (index - first_dec_exp - 1) / dec_exp_step + 1; - pow10_exponent = first_dec_exp + index * dec_exp_step; - return {data::pow10_significands[index], data::pow10_exponents[index]}; -} - -// A simple accumulator to hold the sums of terms in bigint::square if uint128_t -// is not available. -struct accumulator { - uint64_t lower; - uint64_t upper; - - accumulator() : lower(0), upper(0) {} - explicit operator uint32_t() const { return static_cast(lower); } + }; - void operator+=(uint64_t n) { - lower += n; - if (lower < n) ++upper; - } - void operator>>=(int shift) { - assert(shift == 32); - (void)shift; - lower = (upper << 32) | (lower >> 32); - upper >>= 32; +#if FMT_USE_FULL_CACHE_DRAGONBOX + return pow10_significands[k - float_info::min_k]; +#else + static constexpr const uint64_t powers_of_5_64[] = { + 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, + 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, + 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, + 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, + 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, + 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, + 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, + 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, + 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; + + static const int compression_ratio = 27; + + // Compute base index. + int cache_index = (k - float_info::min_k) / compression_ratio; + int kb = cache_index * compression_ratio + float_info::min_k; + int offset = k - kb; + + // Get base cache. + uint128_fallback base_cache = pow10_significands[cache_index]; + if (offset == 0) return base_cache; + + // Compute the required amount of bit-shift. + int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset; + FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); + + // Try to recover the real cache. + uint64_t pow5 = powers_of_5_64[offset]; + uint128_fallback recovered_cache = umul128(base_cache.high(), pow5); + uint128_fallback middle_low = umul128(base_cache.low(), pow5); + + recovered_cache += middle_low.high(); + + uint64_t high_to_middle = recovered_cache.high() << (64 - alpha); + uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); + + recovered_cache = + uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle, + ((middle_low.low() >> alpha) | middle_to_low)}; + FMT_ASSERT(recovered_cache.low() + 1 != 0, ""); + return {recovered_cache.high(), recovered_cache.low() + 1}; +#endif } -}; - -class bigint { - private: - // A bigint is stored as an array of bigits (big digits), with bigit at index - // 0 being the least significant one. - using bigit = uint32_t; - using double_bigit = uint64_t; - enum { bigits_capacity = 32 }; - basic_memory_buffer bigits_; - int exp_; - - bigit operator[](int index) const { return bigits_[to_unsigned(index)]; } - bigit& operator[](int index) { return bigits_[to_unsigned(index)]; } - static FMT_CONSTEXPR_DECL const int bigit_bits = bits::value; - - friend struct formatter; + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; - void subtract_bigits(int index, bigit other, bigit& borrow) { - auto result = static_cast((*this)[index]) - other - borrow; - (*this)[index] = static_cast(result); - borrow = static_cast(result >> (bigit_bits * 2 - 1)); + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul192_upper128(u, cache); + return {r.high(), r.low() == 0}; } - void remove_leading_zeros() { - int num_bigits = static_cast(bigits_.size()) - 1; - while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; - bigits_.resize(to_unsigned(num_bigits + 1)); + static auto compute_delta(cache_entry_type const& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache.high() >> (64 - 1 - beta)); } - // Computes *this -= other assuming aligned bigints and *this >= other. - void subtract_aligned(const bigint& other) { - FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); - FMT_ASSERT(compare(*this, other) >= 0, ""); - bigit borrow = 0; - int i = other.exp_ - exp_; - for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) { - subtract_bigits(i, other.bigits_[j], borrow); - } - while (borrow > 0) subtract_bigits(i, 0, borrow); - remove_leading_zeros(); - } + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); - void multiply(uint32_t value) { - const double_bigit wide_value = value; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - double_bigit result = bigits_[i] * wide_value + carry; - bigits_[i] = static_cast(result); - carry = static_cast(result >> bigit_bits); - } - if (carry != 0) bigits_.push_back(carry); + auto r = umul192_lower128(two_f, cache); + return {((r.high() >> (64 - beta)) & 1) != 0, + ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; } - void multiply(uint64_t value) { - const bigit mask = ~bigit(0); - const double_bigit lower = value & mask; - const double_bigit upper = value >> bigit_bits; - double_bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - double_bigit result = bigits_[i] * lower + (carry & mask); - carry = - bigits_[i] * upper + (result >> bigit_bits) + (carry >> bigit_bits); - bigits_[i] = static_cast(result); - } - while (carry != 0) { - bigits_.push_back(carry & mask); - carry >>= bigit_bits; - } + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() - + (cache.high() >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta); } - public: - bigint() : exp_(0) {} - explicit bigint(uint64_t n) { assign(n); } - ~bigint() { assert(bigits_.capacity() <= bigits_capacity); } - - bigint(const bigint&) = delete; - void operator=(const bigint&) = delete; - - void assign(const bigint& other) { - auto size = other.bigits_.size(); - bigits_.resize(size); - auto data = other.bigits_.data(); - std::copy(data, data + size, make_checked(bigits_.data(), size)); - exp_ = other.exp_; + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() + + (cache.high() >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta); } - void assign(uint64_t n) { - size_t num_bigits = 0; - do { - bigits_[num_bigits++] = n & ~bigit(0); - n >>= bigit_bits; - } while (n != 0); - bigits_.resize(num_bigits); - exp_ = 0; + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; } +}; - int num_bigits() const { return static_cast(bigits_.size()) + exp_; } - - FMT_NOINLINE bigint& operator<<=(int shift) { - assert(shift >= 0); - exp_ += shift / bigit_bits; - shift %= bigit_bits; - if (shift == 0) return *this; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - bigit c = bigits_[i] >> (bigit_bits - shift); - bigits_[i] = (bigits_[i] << shift) + carry; - carry = c; - } - if (carry != 0) bigits_.push_back(carry); - return *this; - } +FMT_FUNC auto get_cached_power(int k) noexcept -> uint128_fallback { + return cache_accessor::get_cached_power(k); +} - template bigint& operator*=(Int value) { - FMT_ASSERT(value > 0, ""); - multiply(uint32_or_64_or_128_t(value)); - return *this; - } +// Various integer checks +template +auto is_left_endpoint_integer_shorter_interval(int exponent) noexcept -> bool { + const int case_shorter_interval_left_endpoint_lower_threshold = 2; + const int case_shorter_interval_left_endpoint_upper_threshold = 3; + return exponent >= case_shorter_interval_left_endpoint_lower_threshold && + exponent <= case_shorter_interval_left_endpoint_upper_threshold; +} - friend int compare(const bigint& lhs, const bigint& rhs) { - int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); - if (num_lhs_bigits != num_rhs_bigits) - return num_lhs_bigits > num_rhs_bigits ? 1 : -1; - int i = static_cast(lhs.bigits_.size()) - 1; - int j = static_cast(rhs.bigits_.size()) - 1; - int end = i - j; - if (end < 0) end = 0; - for (; i >= end; --i, --j) { - bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; - if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; - } - if (i != j) return i > j ? 1 : -1; - return 0; +// Remove trailing zeros from n and return the number of zeros removed (float) +FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept { + FMT_ASSERT(n != 0, ""); + // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1. + constexpr uint32_t mod_inv_5 = 0xcccccccd; + constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5 + + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; } - - // Returns compare(lhs1 + lhs2, rhs). - friend int add_compare(const bigint& lhs1, const bigint& lhs2, - const bigint& rhs) { - int max_lhs_bigits = (std::max)(lhs1.num_bigits(), lhs2.num_bigits()); - int num_rhs_bigits = rhs.num_bigits(); - if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; - if (max_lhs_bigits > num_rhs_bigits) return 1; - auto get_bigit = [](const bigint& n, int i) -> bigit { - return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; - }; - double_bigit borrow = 0; - int min_exp = (std::min)((std::min)(lhs1.exp_, lhs2.exp_), rhs.exp_); - for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { - double_bigit sum = - static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); - bigit rhs_bigit = get_bigit(rhs, i); - if (sum > rhs_bigit + borrow) return 1; - borrow = rhs_bigit + borrow - sum; - if (borrow > 1) return -1; - borrow <<= bigit_bits; - } - return borrow != 0 ? -1 : 0; + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; } + return s; +} - // Assigns pow(10, exp) to this bigint. - void assign_pow10(int exp) { - assert(exp >= 0); - if (exp == 0) return assign(1); - // Find the top bit. - int bitmask = 1; - while (exp >= bitmask) bitmask <<= 1; - bitmask >>= 1; - // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by - // repeated squaring and multiplication. - assign(5); - bitmask >>= 1; - while (bitmask != 0) { - square(); - if ((exp & bitmask) != 0) *this *= 5; - bitmask >>= 1; - } - *this <<= exp; // Multiply by pow(2, exp) by shifting. +// Removes trailing zeros and returns the number of zeros removed (double) +FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { + FMT_ASSERT(n != 0, ""); + + // This magic number is ceil(2^90 / 10^8). + constexpr uint64_t magic_number = 12379400392853802749ull; + auto nm = umul128(n, magic_number); + + // Is n is divisible by 10^8? + if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) { + // If yes, work with the quotient... + auto n32 = static_cast(nm.high() >> (90 - 64)); + // ... and use the 32 bit variant of the function + int s = remove_trailing_zeros(n32, 8); + n = n32; + return s; } - void square() { - basic_memory_buffer n(std::move(bigits_)); - int num_bigits = static_cast(bigits_.size()); - int num_result_bigits = 2 * num_bigits; - bigits_.resize(to_unsigned(num_result_bigits)); - using accumulator_t = conditional_t; - auto sum = accumulator_t(); - for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { - // Compute bigit at position bigit_index of the result by adding - // cross-product terms n[i] * n[j] such that i + j == bigit_index. - for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { - // Most terms are multiplied twice which can be optimized in the future. - sum += static_cast(n[i]) * n[j]; - } - (*this)[bigit_index] = static_cast(sum); - sum >>= bits::value; // Compute the carry. - } - // Do the same for the top half. - for (int bigit_index = num_bigits; bigit_index < num_result_bigits; - ++bigit_index) { - for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) - sum += static_cast(n[i++]) * n[j--]; - (*this)[bigit_index] = static_cast(sum); - sum >>= bits::value; - } - --num_result_bigits; - remove_leading_zeros(); - exp_ *= 2; - } + // If n is not divisible by 10^8, work with n itself. + constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd; + constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // mod_inv_5 * mod_inv_5 - // Divides this bignum by divisor, assigning the remainder to this and - // returning the quotient. - int divmod_assign(const bigint& divisor) { - FMT_ASSERT(this != &divisor, ""); - if (compare(*this, divisor) < 0) return 0; - int num_bigits = static_cast(bigits_.size()); - FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); - int exp_difference = exp_ - divisor.exp_; - if (exp_difference > 0) { - // Align bigints by adding trailing zeros to simplify subtraction. - bigits_.resize(to_unsigned(num_bigits + exp_difference)); - for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) - bigits_[j] = bigits_[i]; - std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); - exp_ -= exp_difference; - } - int quotient = 0; - do { - subtract_aligned(divisor); - ++quotient; - } while (compare(*this, divisor) >= 0); - return quotient; + int s = 0; + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; } -}; - -enum class round_direction { unknown, up, down }; - -// Given the divisor (normally a power of 10), the remainder = v % divisor for -// some number v and the error, returns whether v should be rounded up, down, or -// whether the rounding direction can't be determined due to error. -// error should be less than divisor / 2. -inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder, - uint64_t error) { - FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. - FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. - FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. - // Round down if (remainder + error) * 2 <= divisor. - if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) - return round_direction::down; - // Round up if (remainder - error) * 2 >= divisor. - if (remainder >= error && - remainder - error >= divisor - (remainder - error)) { - return round_direction::up; + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; } - return round_direction::unknown; -} - -namespace digits { -enum result { - more, // Generate more digits. - done, // Done generating digits. - error // Digit generation cancelled due to an error. -}; -} -// A version of count_digits optimized for grisu_gen_digits. -inline int grisu_count_digits(uint32_t n) { - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1000) return 3; - if (n < 10000) return 4; - if (n < 100000) return 5; - if (n < 1000000) return 6; - if (n < 10000000) return 7; - if (n < 100000000) return 8; - if (n < 1000000000) return 9; - return 10; + return s; } -// Generates output using the Grisu digit-gen algorithm. -// error: the size of the region (lower, upper) outside of which numbers -// definitely do not round to value (Delta in Grisu3). -template -FMT_ALWAYS_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, - int& exp, Handler& handler) { - const fp one(1ULL << -value.e, value.e); - // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be - // zero because it contains a product of two 64-bit numbers with MSB set (due - // to normalization) - 1, shifted right by at most 60 bits. - auto integral = static_cast(value.f >> -one.e); - FMT_ASSERT(integral != 0, ""); - FMT_ASSERT(integral == value.f >> -one.e, ""); - // The fractional part of scaled value (p2 in Grisu) c = value % one. - uint64_t fractional = value.f & (one.f - 1); - exp = grisu_count_digits(integral); // kappa in Grisu. - // Divide by 10 to prevent overflow. - auto result = handler.on_start(data::powers_of_10_64[exp - 1] << -one.e, - value.f / 10, error * 10, exp); - if (result != digits::more) return result; - // Generate digits for the integral part. This can produce up to 10 digits. - do { - uint32_t digit = 0; - auto divmod_integral = [&](uint32_t divisor) { - digit = integral / divisor; - integral %= divisor; - }; - // This optimization by Milo Yip reduces the number of integer divisions by - // one per iteration. - switch (exp) { - case 10: - divmod_integral(1000000000); - break; - case 9: - divmod_integral(100000000); - break; - case 8: - divmod_integral(10000000); - break; - case 7: - divmod_integral(1000000); - break; - case 6: - divmod_integral(100000); - break; - case 5: - divmod_integral(10000); - break; - case 4: - divmod_integral(1000); - break; - case 3: - divmod_integral(100); - break; - case 2: - divmod_integral(10); - break; - case 1: - digit = integral; - integral = 0; - break; - default: - FMT_ASSERT(false, "invalid number of digits"); - } - --exp; - uint64_t remainder = - (static_cast(integral) << -one.e) + fractional; - result = handler.on_digit(static_cast('0' + digit), - data::powers_of_10_64[exp] << -one.e, remainder, - error, exp, true); - if (result != digits::more) return result; - } while (exp > 0); - // Generate digits for the fractional part. - for (;;) { - fractional *= 10; - error *= 10; - char digit = - static_cast('0' + static_cast(fractional >> -one.e)); - fractional &= one.f - 1; - --exp; - result = handler.on_digit(digit, one.f, fractional, error, exp, false); - if (result != digits::more) return result; +// The main algorithm for shorter interval case +template +FMT_INLINE decimal_fp shorter_interval_case(int exponent) noexcept { + decimal_fp ret_value; + // Compute k and beta + const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); + const int beta = exponent + floor_log2_pow10(-minus_k); + + // Compute xi and zi + using cache_entry_type = typename cache_accessor::cache_entry_type; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + + auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( + cache, beta); + auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( + cache, beta); + + // If the left endpoint is not an integer, increase it + if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; + + // Try bigger divisor + ret_value.significand = zi / 10; + + // If succeed, remove trailing zeros if necessary and return + if (ret_value.significand * 10 >= xi) { + ret_value.exponent = minus_k + 1; + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; } -} -// The fixed precision digit handler. -struct fixed_handler { - char* buf; - int size; - int precision; - int exp10; - bool fixed; - - digits::result on_start(uint64_t divisor, uint64_t remainder, uint64_t error, - int& exp) { - // Non-fixed formats require at least one digit and no precision adjustment. - if (!fixed) return digits::more; - // Adjust fixed precision by exponent because it is relative to decimal - // point. - precision += exp + exp10; - // Check if precision is satisfied just by leading zeros, e.g. - // format("{:.2f}", 0.001) gives "0.00" without generating any digits. - if (precision > 0) return digits::more; - if (precision < 0) return digits::done; - auto dir = get_round_direction(divisor, remainder, error); - if (dir == round_direction::unknown) return digits::error; - buf[size++] = dir == round_direction::up ? '1' : '0'; - return digits::done; + // Otherwise, compute the round-up of y + ret_value.significand = + cache_accessor::compute_round_up_for_shorter_interval_case(cache, + beta); + ret_value.exponent = minus_k; + + // When tie occurs, choose one of them according to the rule + if (exponent >= float_info::shorter_interval_tie_lower_threshold && + exponent <= float_info::shorter_interval_tie_upper_threshold) { + ret_value.significand = ret_value.significand % 2 == 0 + ? ret_value.significand + : ret_value.significand - 1; + } else if (ret_value.significand < xi) { + ++ret_value.significand; } + return ret_value; +} - digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, - uint64_t error, int, bool integral) { - FMT_ASSERT(remainder < divisor, ""); - buf[size++] = digit; - if (size < precision) return digits::more; - if (!integral) { - // Check if error * 2 < divisor with overflow prevention. - // The check is not needed for the integral part because error = 1 - // and divisor > (1 << 32) there. - if (error >= divisor || error >= divisor - error) return digits::error; - } else { - FMT_ASSERT(error == 1 && divisor > 2, ""); - } - auto dir = get_round_direction(divisor, remainder, error); - if (dir != round_direction::up) - return dir == round_direction::down ? digits::done : digits::error; - ++buf[size - 1]; - for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] > '9') { - buf[0] = '1'; - buf[size++] = '0'; - } - return digits::done; - } -}; +template auto to_decimal(T x) noexcept -> decimal_fp { + // Step 1: integer promotion & Schubfach multiplier calculation. -// The shortest representation digit handler. -struct grisu_shortest_handler { - char* buf; - int size; - // Distance between scaled value and upper bound (wp_W in Grisu3). - uint64_t diff; + using carrier_uint = typename float_info::carrier_uint; + using cache_entry_type = typename cache_accessor::cache_entry_type; + auto br = bit_cast(x); - digits::result on_start(uint64_t, uint64_t, uint64_t, int&) { - return digits::more; - } + // Extract significand bits and exponent bits. + const carrier_uint significand_mask = + (static_cast(1) << num_significand_bits()) - 1; + carrier_uint significand = (br & significand_mask); + int exponent = + static_cast((br & exponent_mask()) >> num_significand_bits()); - // Decrement the generated number approaching value from above. - void round(uint64_t d, uint64_t divisor, uint64_t& remainder, - uint64_t error) { - while ( - remainder < d && error - remainder >= divisor && - (remainder + divisor < d || d - remainder >= remainder + divisor - d)) { - --buf[size - 1]; - remainder += divisor; - } - } + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); - // Implements Grisu's round_weed. - digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, - uint64_t error, int exp, bool integral) { - buf[size++] = digit; - if (remainder >= error) return digits::more; - uint64_t unit = integral ? 1 : data::powers_of_10_64[-exp]; - uint64_t up = (diff - 1) * unit; // wp_Wup - round(up, divisor, remainder, error); - uint64_t down = (diff + 1) * unit; // wp_Wdown - if (remainder < down && error - remainder >= divisor && - (remainder + divisor < down || - down - remainder > remainder + divisor - down)) { - return digits::error; - } - return 2 * unit <= remainder && remainder <= error - 4 * unit - ? digits::done - : digits::error; - } -}; + // Shorter interval case; proceed like Schubfach. + // In fact, when exponent == 1 and significand == 0, the interval is + // regular. However, it can be shown that the end-results are anyway same. + if (significand == 0) return shorter_interval_case(exponent); -// Formats value using a variation of the Fixed-Precision Positive -// Floating-Point Printout ((FPP)^2) algorithm by Steele & White: -// https://fmt.dev/p372-steele.pdf. -template -void fallback_format(Double d, buffer& buf, int& exp10) { - bigint numerator; // 2 * R in (FPP)^2. - bigint denominator; // 2 * S in (FPP)^2. - // lower and upper are differences between value and corresponding boundaries. - bigint lower; // (M^- in (FPP)^2). - bigint upper_store; // upper's value if different from lower. - bigint* upper = nullptr; // (M^+ in (FPP)^2). - fp value; - // Shift numerator and denominator by an extra bit or two (if lower boundary - // is closer) to make lower and upper integers. This eliminates multiplication - // by 2 during later computations. - // TODO: handle float - int shift = value.assign(d) ? 2 : 1; - uint64_t significand = value.f << shift; - if (value.e >= 0) { - numerator.assign(significand); - numerator <<= value.e; - lower.assign(1); - lower <<= value.e; - if (shift != 1) { - upper_store.assign(1); - upper_store <<= value.e + 1; - upper = &upper_store; - } - denominator.assign_pow10(exp10); - denominator <<= 1; - } else if (exp10 < 0) { - numerator.assign_pow10(-exp10); - lower.assign(numerator); - if (shift != 1) { - upper_store.assign(numerator); - upper_store <<= 1; - upper = &upper_store; - } - numerator *= significand; - denominator.assign(1); - denominator <<= shift - value.e; + significand |= (static_cast(1) << num_significand_bits()); } else { - numerator.assign(significand); - denominator.assign_pow10(exp10); - denominator <<= shift - value.e; - lower.assign(1); - if (shift != 1) { - upper_store.assign(1ULL << 1); - upper = &upper_store; - } - } - if (!upper) upper = &lower; - // Invariant: value == (numerator / denominator) * pow(10, exp10). - bool even = (value.f & 1) == 0; - int num_digits = 0; - char* data = buf.data(); - for (;;) { - int digit = numerator.divmod_assign(denominator); - bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. - // numerator + upper >[=] pow10: - bool high = add_compare(numerator, *upper, denominator) + even > 0; - data[num_digits++] = static_cast('0' + digit); - if (low || high) { - if (!low) { - ++data[num_digits - 1]; - } else if (high) { - int result = add_compare(numerator, numerator, denominator); - // Round half to even. - if (result > 0 || (result == 0 && (digit % 2) != 0)) - ++data[num_digits - 1]; - } - buf.resize(to_unsigned(num_digits)); - exp10 -= num_digits - 1; - return; - } - numerator *= 10; - lower *= 10; - if (upper != &lower) *upper *= 10; - } -} - -// Formats value using the Grisu algorithm -// (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf) -// if T is a IEEE754 binary32 or binary64 and snprintf otherwise. -template -int format_float(T value, int precision, float_specs specs, buffer& buf) { - static_assert(!std::is_same::value, ""); - FMT_ASSERT(value >= 0, "value is negative"); - - const bool fixed = specs.format == float_format::fixed; - if (value <= 0) { // <= instead of == to silence a warning. - if (precision <= 0 || !fixed) { - buf.push_back('0'); - return 0; - } - buf.resize(to_unsigned(precision)); - std::uninitialized_fill_n(buf.data(), precision, '0'); - return -precision; + // Subnormal case; the interval is always regular. + if (significand == 0) return {0, 0}; + exponent = + std::numeric_limits::min_exponent - num_significand_bits() - 1; } - if (!specs.use_grisu) return snprintf_float(value, precision, specs, buf); - - int exp = 0; - const int min_exp = -60; // alpha in Grisu. - int cached_exp10 = 0; // K in Grisu. - if (precision < 0) { - fp fp_value; - auto boundaries = specs.binary32 - ? fp_value.assign_float_with_boundaries(value) - : fp_value.assign_with_boundaries(value); - fp_value = normalize(fp_value); - // Find a cached power of 10 such that multiplying value by it will bring - // the exponent in the range [min_exp, -32]. - const fp cached_pow = get_cached_power( - min_exp - (fp_value.e + fp::significand_size), cached_exp10); - // Multiply value and boundaries by the cached power of 10. - fp_value = fp_value * cached_pow; - boundaries.lower = multiply(boundaries.lower, cached_pow.f); - boundaries.upper = multiply(boundaries.upper, cached_pow.f); - assert(min_exp <= fp_value.e && fp_value.e <= -32); - --boundaries.lower; // \tilde{M}^- - 1 ulp -> M^-_{\downarrow}. - ++boundaries.upper; // \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}. - // Numbers outside of (lower, upper) definitely do not round to value. - grisu_shortest_handler handler{buf.data(), 0, - boundaries.upper - fp_value.f}; - auto result = - grisu_gen_digits(fp(boundaries.upper, fp_value.e), - boundaries.upper - boundaries.lower, exp, handler); - if (result == digits::error) { - exp += handler.size - cached_exp10 - 1; - fallback_format(value, buf, exp); - return exp; + const bool include_left_endpoint = (significand % 2 == 0); + const bool include_right_endpoint = include_left_endpoint; + + // Compute k and beta. + const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + const int beta = exponent + floor_log2_pow10(-minus_k); + + // Compute zi and deltai. + // 10^kappa <= deltai < 10^(kappa + 1) + const uint32_t deltai = cache_accessor::compute_delta(cache, beta); + const carrier_uint two_fc = significand << 1; + + // For the case of binary32, the result of integer check is not correct for + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, + // and they are the unique counterexamples. However, since 29711844 is even, + // this does not cause any problem for the endpoints calculations; it can only + // cause a problem when we need to perform integer check for the center. + // Fortunately, with these inputs, that branch is never executed, so we are + // fine. + const typename cache_accessor::compute_mul_result z_mul = + cache_accessor::compute_mul((two_fc | 1) << beta, cache); + + // Step 2: Try larger divisor; remove trailing zeros if necessary. + + // Using an upper bound on zi, we might be able to optimize the division + // better than the compiler; we are computing zi / big_divisor here. + decimal_fp ret_value; + ret_value.significand = divide_by_10_to_kappa_plus_1(z_mul.result); + uint32_t r = static_cast(z_mul.result - float_info::big_divisor * + ret_value.significand); + + if (r < deltai) { + // Exclude the right endpoint if necessary. + if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) { + --ret_value.significand; + r = float_info::big_divisor; + goto small_divisor_case_label; } - buf.resize(to_unsigned(handler.size)); + } else if (r > deltai) { + goto small_divisor_case_label; } else { - if (precision > 17) return snprintf_float(value, precision, specs, buf); - fp normalized = normalize(fp(value)); - const auto cached_pow = get_cached_power( - min_exp - (normalized.e + fp::significand_size), cached_exp10); - normalized = normalized * cached_pow; - fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; - if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error) - return snprintf_float(value, precision, specs, buf); - int num_digits = handler.size; - if (!fixed) { - // Remove trailing zeros. - while (num_digits > 0 && buf[num_digits - 1] == '0') { - --num_digits; - ++exp; - } - } - buf.resize(to_unsigned(num_digits)); - } - return exp - cached_exp10; -} + // r == deltai; compare fractional parts. + const typename cache_accessor::compute_mul_parity_result x_mul = + cache_accessor::compute_mul_parity(two_fc - 1, cache, beta); -template -int snprintf_float(T value, int precision, float_specs specs, - buffer& buf) { - // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. - FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); - static_assert(!std::is_same::value, ""); - - // Subtract 1 to account for the difference in precision since we use %e for - // both general and exponent format. - if (specs.format == float_format::general || - specs.format == float_format::exp) - precision = (precision >= 0 ? precision : 6) - 1; - - // Build the format string. - enum { max_format_size = 7 }; // The longest format is "%#.*Le". - char format[max_format_size]; - char* format_ptr = format; - *format_ptr++ = '%'; - if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#'; - if (precision >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - if (std::is_same()) *format_ptr++ = 'L'; - *format_ptr++ = specs.format != float_format::hex - ? (specs.format == float_format::fixed ? 'f' : 'e') - : (specs.upper ? 'A' : 'a'); - *format_ptr = '\0'; - - // Format using snprintf. - auto offset = buf.size(); - for (;;) { - auto begin = buf.data() + offset; - auto capacity = buf.capacity() - offset; -#ifdef FMT_FUZZ - if (precision > 100000) - throw std::runtime_error( - "fuzz mode - avoid large allocation inside snprintf"); -#endif - // Suppress the warning about a nonliteral format string. - // Cannot use auto because of a bug in MinGW (#1532). - int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; - int result = precision >= 0 - ? snprintf_ptr(begin, capacity, format, precision, value) - : snprintf_ptr(begin, capacity, format, value); - if (result < 0) { - buf.reserve(buf.capacity() + 1); // The buffer will grow exponentially. - continue; - } - auto size = to_unsigned(result); - // Size equal to capacity means that the last character was truncated. - if (size >= capacity) { - buf.reserve(size + offset + 1); // Add 1 for the terminating '\0'. - continue; - } - auto is_digit = [](char c) { return c >= '0' && c <= '9'; }; - if (specs.format == float_format::fixed) { - if (precision == 0) { - buf.resize(size); - return 0; - } - // Find and remove the decimal point. - auto end = begin + size, p = end; - do { - --p; - } while (is_digit(*p)); - int fraction_size = static_cast(end - p - 1); - std::memmove(p, p + 1, to_unsigned(fraction_size)); - buf.resize(size - 1); - return -fraction_size; - } - if (specs.format == float_format::hex) { - buf.resize(size + offset); - return 0; - } - // Find and parse the exponent. - auto end = begin + size, exp_pos = end; - do { - --exp_pos; - } while (*exp_pos != 'e'); - char sign = exp_pos[1]; - assert(sign == '+' || sign == '-'); - int exp = 0; - auto p = exp_pos + 2; // Skip 'e' and sign. - do { - assert(is_digit(*p)); - exp = exp * 10 + (*p++ - '0'); - } while (p != end); - if (sign == '-') exp = -exp; - int fraction_size = 0; - if (exp_pos != begin + 1) { - // Remove trailing zeros. - auto fraction_end = exp_pos - 1; - while (*fraction_end == '0') --fraction_end; - // Move the fractional part left to get rid of the decimal point. - fraction_size = static_cast(fraction_end - begin - 1); - std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size)); - } - buf.resize(to_unsigned(fraction_size) + offset + 1); - return exp - fraction_size; + if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint))) + goto small_divisor_case_label; } + ret_value.exponent = minus_k + float_info::kappa + 1; + + // We may need to remove trailing zeros. + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + + // Step 3: Find the significand with the smaller divisor. + +small_divisor_case_label: + ret_value.significand *= 10; + ret_value.exponent = minus_k + float_info::kappa; + + uint32_t dist = r - (deltai / 2) + (float_info::small_divisor / 2); + const bool approx_y_parity = + ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; + + // Is dist divisible by 10^kappa? + const bool divisible_by_small_divisor = + check_divisibility_and_divide_by_pow10::kappa>(dist); + + // Add dist / 10^kappa to the significand. + ret_value.significand += dist; + + if (!divisible_by_small_divisor) return ret_value; + + // Check z^(f) >= epsilon^(f). + // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). + // Since there are only 2 possibilities, we only need to care about the + // parity. Also, zi and r should have the same parity since the divisor + // is an even number. + const auto y_mul = cache_accessor::compute_mul_parity(two_fc, cache, beta); + + // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f), + // or equivalently, when y is an integer. + if (y_mul.parity != approx_y_parity) + --ret_value.significand; + else if (y_mul.is_integer & (ret_value.significand % 2 != 0)) + --ret_value.significand; + return ret_value; } - -// A public domain branchless UTF-8 decoder by Christopher Wellons: -// https://github.com/skeeto/branchless-utf8 -/* Decode the next character, c, from buf, reporting errors in e. - * - * Since this is a branchless decoder, four bytes will be read from the - * buffer regardless of the actual length of the next character. This - * means the buffer _must_ have at least three bytes of zero padding - * following the end of the data stream. - * - * Errors are reported in e, which will be non-zero if the parsed - * character was somehow invalid: invalid byte sequence, non-canonical - * encoding, or a surrogate half. - * - * The function returns a pointer to the next character. When an error - * occurs, this pointer will be a guess that depends on the particular - * error, but it will always advance at least one byte. - */ -FMT_FUNC const char* utf8_decode(const char* buf, uint32_t* c, int* e) { - static const char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; - static const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; - static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; - static const int shiftc[] = {0, 18, 12, 6, 0}; - static const int shifte[] = {0, 6, 4, 2, 0}; - - auto s = reinterpret_cast(buf); - int len = lengths[s[0] >> 3]; - - // Compute the pointer to the next character early so that the next - // iteration can start working on the next character. Neither Clang - // nor GCC figure out this reordering on their own. - const char* next = buf + len + !len; - - // Assume a four-byte character and load four bytes. Unused bits are - // shifted out. - *c = uint32_t(s[0] & masks[len]) << 18; - *c |= uint32_t(s[1] & 0x3f) << 12; - *c |= uint32_t(s[2] & 0x3f) << 6; - *c |= uint32_t(s[3] & 0x3f) << 0; - *c >>= shiftc[len]; - - // Accumulate the various error conditions. - *e = (*c < mins[len]) << 6; // non-canonical encoding - *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? - *e |= (*c > 0x10FFFF) << 8; // out of range? - *e |= (s[1] & 0xc0) >> 2; - *e |= (s[2] & 0xc0) >> 4; - *e |= (s[3]) >> 6; - *e ^= 0x2a; // top two bits of each tail byte correct? - *e >>= shifte[len]; - - return next; -} +} // namespace dragonbox } // namespace detail template <> struct formatter { - format_parse_context::iterator parse(format_parse_context& ctx) { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { return ctx.begin(); } - format_context::iterator format(const detail::bigint& n, - format_context& ctx) { + auto format(const detail::bigint& n, format_context& ctx) const + -> format_context::iterator { auto out = ctx.out(); bool first = true; for (auto i = n.bigits_.size(); i > 0; --i) { auto value = n.bigits_[i - 1u]; if (first) { - out = format_to(out, "{:x}", value); + out = fmt::format_to(out, FMT_STRING("{:x}"), value); first = false; continue; } - out = format_to(out, "{:08x}", value); + out = fmt::format_to(out, FMT_STRING("{:08x}"), value); } if (n.exp_ > 0) - out = format_to(out, "p{}", n.exp_ * detail::bigint::bigit_bits); + out = fmt::format_to(out, FMT_STRING("p{}"), + n.exp_ * detail::bigint::bigit_bits); return out; } }; FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { - auto transcode = [this](const char* p) { - auto cp = uint32_t(); - auto error = 0; - p = utf8_decode(p, &cp, &error); - if (error != 0) FMT_THROW(std::runtime_error("invalid utf8")); + for_each_codepoint(s, [this](uint32_t cp, string_view) { + if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); if (cp <= 0xFFFF) { buffer_.push_back(static_cast(cp)); } else { @@ -1335,119 +1407,522 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { buffer_.push_back(static_cast(0xD800 + (cp >> 10))); buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); } - return p; - }; - auto p = s.data(); - const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. - if (s.size() >= block_size) { - for (auto end = p + s.size() - block_size + 1; p < end;) p = transcode(p); - } - if (auto num_chars_left = s.data() + s.size() - p) { - char buf[2 * block_size - 1] = {}; - memcpy(buf, p, to_unsigned(num_chars_left)); - p = buf; - do { - p = transcode(p); - } while (p - buf < num_chars_left); - } + return true; + }); buffer_.push_back(0); } FMT_FUNC void format_system_error(detail::buffer& out, int error_code, - string_view message) FMT_NOEXCEPT { + const char* message) noexcept { FMT_TRY { - memory_buffer buf; - buf.resize(inline_buffer_size); - for (;;) { - char* system_message = &buf[0]; - int result = - detail::safe_strerror(error_code, system_message, buf.size()); - if (result == 0) { - format_to(std::back_inserter(out), "{}: {}", message, system_message); - return; - } - if (result != ERANGE) - break; // Can't get error message, report error code instead. - buf.resize(buf.size() * 2); - } + auto ec = std::error_code(error_code, std::generic_category()); + detail::write(appender(out), std::system_error(ec, message).what()); + return; } FMT_CATCH(...) {} format_error_code(out, error_code, message); } -FMT_FUNC void detail::error_handler::on_error(const char* message) { - FMT_THROW(format_error(message)); -} - FMT_FUNC void report_system_error(int error_code, - fmt::string_view message) FMT_NOEXCEPT { + const char* message) noexcept { report_error(format_system_error, error_code, message); } -struct stringifier { - template FMT_INLINE std::string operator()(T value) const { - return to_string(value); +FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string { + // Don't optimize the "{}" case to keep the binary size small and because it + // can be better optimized in fmt::format anyway. + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + return to_string(buffer); +} + +namespace detail { + +template struct span { + T* data; + size_t size; +}; + +template auto flockfile(F* f) -> decltype(_lock_file(f)) { + _lock_file(f); +} +template auto funlockfile(F* f) -> decltype(_unlock_file(f)) { + _unlock_file(f); +} + +#ifndef getc_unlocked +template auto getc_unlocked(F* f) -> decltype(_fgetc_nolock(f)) { + return _fgetc_nolock(f); +} +#endif + +template +struct has_flockfile : std::false_type {}; + +template +struct has_flockfile()))>> + : std::true_type {}; + +// A FILE wrapper. F is FILE defined as a template parameter to make system API +// detection work. +template class file_base { + public: + F* file_; + + public: + file_base(F* file) : file_(file) {} + operator F*() const { return file_; } + + // Reads a code unit from the stream. + auto get() -> int { + int result = getc_unlocked(file_); + if (result == EOF && ferror(file_) != 0) + FMT_THROW(system_error(errno, FMT_STRING("getc failed"))); + return result; } - std::string operator()(basic_format_arg::handle h) const { - memory_buffer buf; - detail::buffer& base = buf; - format_parse_context parse_ctx({}); - format_context format_ctx(std::back_inserter(base), {}, {}); - h.format(parse_ctx, format_ctx); - return to_string(buf); + + // Puts the code unit back into the stream buffer. + void unget(char c) { + if (ungetc(c, file_) == EOF) + FMT_THROW(system_error(errno, FMT_STRING("ungetc failed"))); } + + void flush() { fflush(this->file_); } }; -FMT_FUNC std::string detail::vformat(string_view format_str, format_args args) { - if (format_str.size() == 2 && equal2(format_str.data(), "{}")) { - auto arg = args.get(0); - if (!arg) error_handler().on_error("argument not found"); - return visit_format_arg(stringifier(), arg); +// A FILE wrapper for glibc. +template class glibc_file : public file_base { + private: + enum { + line_buffered = 0x200, // _IO_LINE_BUF + unbuffered = 2 // _IO_UNBUFFERED + }; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { + return (this->file_->_flags & unbuffered) == 0; } - memory_buffer buffer; - detail::vformat_to(buffer, format_str, args); - return to_string(buffer); -} -FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { - memory_buffer buffer; - detail::vformat_to(buffer, format_str, - basic_format_args>(args)); -#ifdef _WIN32 - auto fd = _fileno(f); - if (_isatty(fd)) { - detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size())); - auto written = DWORD(); - if (!WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), - u16.c_str(), static_cast(u16.size()), &written, - nullptr)) { - FMT_THROW(format_error("failed to write to console")); - } - return; + void init_buffer() { + if (this->file_->_IO_write_ptr) return; + // Force buffer initialization by placing and removing a char in a buffer. + putc_unlocked(0, this->file_); + --this->file_->_IO_write_ptr; + } + + // Returns the file's read buffer. + auto get_read_buffer() const -> span { + auto ptr = this->file_->_IO_read_ptr; + return {ptr, to_unsigned(this->file_->_IO_read_end - ptr)}; + } + + // Returns the file's write buffer. + auto get_write_buffer() const -> span { + auto ptr = this->file_->_IO_write_ptr; + return {ptr, to_unsigned(this->file_->_IO_buf_end - ptr)}; + } + + void advance_write_buffer(size_t size) { this->file_->_IO_write_ptr += size; } + + bool needs_flush() const { + if ((this->file_->_flags & line_buffered) == 0) return false; + char* end = this->file_->_IO_write_end; + return memchr(end, '\n', to_unsigned(this->file_->_IO_write_ptr - end)); + } + + void flush() { fflush_unlocked(this->file_); } +}; + +// A FILE wrapper for Apple's libc. +template class apple_file : public file_base { + private: + enum { + line_buffered = 1, // __SNBF + unbuffered = 2 // __SLBF + }; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { + return (this->file_->_flags & unbuffered) == 0; + } + + void init_buffer() { + if (this->file_->_p) return; + // Force buffer initialization by placing and removing a char in a buffer. + putc_unlocked(0, this->file_); + --this->file_->_p; + ++this->file_->_w; + } + + auto get_read_buffer() const -> span { + return {reinterpret_cast(this->file_->_p), + to_unsigned(this->file_->_r)}; + } + + auto get_write_buffer() const -> span { + return {reinterpret_cast(this->file_->_p), + to_unsigned(this->file_->_bf._base + this->file_->_bf._size - + this->file_->_p)}; } + + void advance_write_buffer(size_t size) { + this->file_->_p += size; + this->file_->_w -= size; + } + + bool needs_flush() const { + if ((this->file_->_flags & line_buffered) == 0) return false; + return memchr(this->file_->_p + this->file_->_w, '\n', + to_unsigned(-this->file_->_w)); + } +}; + +// A fallback FILE wrapper. +template class fallback_file : public file_base { + private: + char next_; // The next unconsumed character in the buffer. + bool has_next_ = false; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { return false; } + auto needs_flush() const -> bool { return false; } + void init_buffer() {} + + auto get_read_buffer() const -> span { + return {&next_, has_next_ ? 1u : 0u}; + } + + auto get_write_buffer() const -> span { return {nullptr, 0}; } + + void advance_write_buffer(size_t) {} + + auto get() -> int { + has_next_ = false; + return file_base::get(); + } + + void unget(char c) { + file_base::unget(c); + next_ = c; + has_next_ = true; + } +}; + +#ifndef FMT_USE_FALLBACK_FILE +# define FMT_USE_FALLBACK_FILE 1 #endif - detail::fwrite_fully(buffer.data(), 1, buffer.size(), f); + +template +auto get_file(F* f, int) -> apple_file { + return f; +} +template +inline auto get_file(F* f, int) -> glibc_file { + return f; +} + +inline auto get_file(FILE* f, ...) -> fallback_file { return f; } + +using file_ref = decltype(get_file(static_cast(nullptr), 0)); + +template +class file_print_buffer : public buffer { + public: + explicit file_print_buffer(F*) : buffer(nullptr, size_t()) {} +}; + +template +class file_print_buffer::value>> + : public buffer { + private: + file_ref file_; + + static void grow(buffer& base, size_t) { + auto& self = static_cast(base); + self.file_.advance_write_buffer(self.size()); + if (self.file_.get_write_buffer().size == 0) self.file_.flush(); + auto buf = self.file_.get_write_buffer(); + FMT_ASSERT(buf.size > 0, ""); + self.set(buf.data, buf.size); + self.clear(); + } + + public: + explicit file_print_buffer(F* f) : buffer(grow, size_t()), file_(f) { + flockfile(f); + file_.init_buffer(); + auto buf = file_.get_write_buffer(); + set(buf.data, buf.size); + } + ~file_print_buffer() { + file_.advance_write_buffer(size()); + bool flush = file_.needs_flush(); + F* f = file_; // Make funlockfile depend on the template parameter F + funlockfile(f); // for the system API detection to work. + if (flush) fflush(file_); + } +}; + +#if !defined(_WIN32) || defined(FMT_USE_WRITE_CONSOLE) +FMT_FUNC auto write_console(int, string_view) -> bool { return false; } +#else +using dword = conditional_t; +extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // + void*, const void*, dword, dword*, void*); + +FMT_FUNC bool write_console(int fd, string_view text) { + auto u16 = utf8_to_utf16(text); + return WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), + static_cast(u16.size()), nullptr, nullptr) != 0; } +#endif #ifdef _WIN32 // Print assuming legacy (non-Unicode) encoding. -FMT_FUNC void detail::vprint_mojibake(std::FILE* f, string_view format_str, - format_args args) { - memory_buffer buffer; - detail::vformat_to(buffer, format_str, - basic_format_args>(args)); - fwrite_fully(buffer.data(), 1, buffer.size(), f); +FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args, + bool newline) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + if (newline) buffer.push_back('\n'); + fwrite_fully(buffer.data(), buffer.size(), f); } #endif -FMT_FUNC void vprint(string_view format_str, format_args args) { - vprint(stdout, format_str, args); +FMT_FUNC void print(std::FILE* f, string_view text) { +#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) + int fd = _fileno(f); + if (_isatty(fd)) { + std::fflush(f); + if (write_console(fd, text)) return; + } +#endif + fwrite_fully(text.data(), text.size(), f); +} +} // namespace detail + +FMT_FUNC void vprint_buffered(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + detail::print(f, {buffer.data(), buffer.size()}); } -FMT_END_NAMESPACE +FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { + if (!detail::file_ref(f).is_buffered() || !detail::has_flockfile<>()) + return vprint_buffered(f, fmt, args); + auto&& buffer = detail::file_print_buffer<>(f); + return detail::vformat_to(buffer, fmt, args); +} -#ifdef _MSC_VER -# pragma warning(pop) -#endif +FMT_FUNC void vprintln(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + buffer.push_back('\n'); + detail::print(f, {buffer.data(), buffer.size()}); +} + +FMT_FUNC void vprint(string_view fmt, format_args args) { + vprint(stdout, fmt, args); +} + +namespace detail { + +struct singleton { + unsigned char upper; + unsigned char lower_count; +}; + +inline auto is_printable(uint16_t x, const singleton* singletons, + size_t singletons_size, + const unsigned char* singleton_lowers, + const unsigned char* normal, size_t normal_size) + -> bool { + auto upper = x >> 8; + auto lower_start = 0; + for (size_t i = 0; i < singletons_size; ++i) { + auto s = singletons[i]; + auto lower_end = lower_start + s.lower_count; + if (upper < s.upper) break; + if (upper == s.upper) { + for (auto j = lower_start; j < lower_end; ++j) { + if (singleton_lowers[j] == (x & 0xff)) return false; + } + } + lower_start = lower_end; + } + + auto xsigned = static_cast(x); + auto current = true; + for (size_t i = 0; i < normal_size; ++i) { + auto v = static_cast(normal[i]); + auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; + xsigned -= len; + if (xsigned < 0) break; + current = !current; + } + return current; +} + +// This code is generated by support/printable.py. +FMT_FUNC auto is_printable(uint32_t cp) -> bool { + static constexpr singleton singletons0[] = { + {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, + {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, + {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, + {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, + {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, + {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, + {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, + }; + static constexpr unsigned char singletons0_lower[] = { + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, + 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, + 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, + 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, + 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, + 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, + 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, + 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, + 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, + 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, + 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, + 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, + 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, + }; + static constexpr singleton singletons1[] = { + {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, + {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, + {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, + {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, + {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, + {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, + {0xfa, 2}, {0xfb, 1}, + }; + static constexpr unsigned char singletons1_lower[] = { + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, + 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, + 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, + 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, + 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, + 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, + 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + }; + static constexpr unsigned char normal0[] = { + 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, + 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, + 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, + 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, + 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, + 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, + 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, + 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, + 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, + 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, + 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, + 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, + 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, + 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, + 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, + 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, + 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, + 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, + 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, + 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, + 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, + 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, + 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, + 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, + 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, + }; + static constexpr unsigned char normal1[] = { + 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, + 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, + 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, + 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, + 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, + 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, + 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, + 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, + 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, + 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, + 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, + 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, + 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, + 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, + 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, + 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, + 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, + 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, + 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, + 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, + 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, + 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, + 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, + 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, + 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, + 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, + 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, + 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, + 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, + 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, + 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, + 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, + 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, + 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, + }; + auto lower = static_cast(cp); + if (cp < 0x10000) { + return is_printable(lower, singletons0, + sizeof(singletons0) / sizeof(*singletons0), + singletons0_lower, normal0, sizeof(normal0)); + } + if (cp < 0x20000) { + return is_printable(lower, singletons1, + sizeof(singletons1) / sizeof(*singletons1), + singletons1_lower, normal1, sizeof(normal1)); + } + if (0x2a6de <= cp && cp < 0x2a700) return false; + if (0x2b735 <= cp && cp < 0x2b740) return false; + if (0x2b81e <= cp && cp < 0x2b820) return false; + if (0x2cea2 <= cp && cp < 0x2ceb0) return false; + if (0x2ebe1 <= cp && cp < 0x2f800) return false; + if (0x2fa1e <= cp && cp < 0x30000) return false; + if (0x3134b <= cp && cp < 0xe0100) return false; + if (0xe01f0 <= cp && cp < 0x110000) return false; + return cp < 0x110000; +} + +} // namespace detail + +FMT_END_NAMESPACE #endif // FMT_FORMAT_INL_H_ diff --git a/external/fmt/include/fmt/format.h b/external/fmt/include/fmt/format.h index 721ea9bf8d..67f0ab739b 100644 --- a/external/fmt/include/fmt/format.h +++ b/external/fmt/include/fmt/format.h @@ -1,60 +1,97 @@ /* - Formatting library for C++ - - Copyright (c) 2012 - present, Victor Zverovich - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --- Optional exception to the license --- - - As an exception, if, as a result of your compiling your source code, portions - of this Software are embedded into a machine-executable object form of such - source code, you may redistribute such embedded portions in such object form - without including the above copyright and permission notices. + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + --- Optional exception to the license --- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into a machine-executable object form of such + source code, you may redistribute such embedded portions in such object form + without including the above copyright and permission notices. */ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ -#include -#include -#include -#include -#include -#include -#include +#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +# define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +# define FMT_REMOVE_TRANSITIVE_INCLUDES +#endif + +#include "base.h" + +#ifndef FMT_MODULE +# include // std::signbit +# include // uint32_t +# include // std::memcpy +# include // std::initializer_list +# include // std::numeric_limits +# if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI) +// Workaround for pre gcc 5 libstdc++. +# include // std::allocator_traits +# endif +# include // std::runtime_error +# include // std::string +# include // std::system_error + +// Checking FMT_CPLUSPLUS for warning suppression in MSVC. +# if FMT_HAS_INCLUDE() && FMT_CPLUSPLUS > 201703L +# include // std::bit_cast +# endif -#include "core.h" +// libc++ supports string_view in pre-c++17. +# if FMT_HAS_INCLUDE() && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# include +# define FMT_USE_STRING_VIEW +# endif +#endif // FMT_MODULE -#ifdef __INTEL_COMPILER -# define FMT_ICC_VERSION __INTEL_COMPILER -#elif defined(__ICL) -# define FMT_ICC_VERSION __ICL +#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L +# define FMT_INLINE_VARIABLE inline #else -# define FMT_ICC_VERSION 0 +# define FMT_INLINE_VARIABLE +#endif + +#ifndef FMT_NO_UNIQUE_ADDRESS +# if FMT_CPLUSPLUS >= 202002L +# if FMT_HAS_CPP_ATTRIBUTE(no_unique_address) +# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] +// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485). +# elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION +# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +# endif +# endif +#endif +#ifndef FMT_NO_UNIQUE_ADDRESS +# define FMT_NO_UNIQUE_ADDRESS #endif -#ifdef __NVCC__ -# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +// Visibility when compiled as a shared library/object. +#if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value) #else -# define FMT_CUDA_VERSION 0 +# define FMT_SO_VISIBILITY(value) #endif #ifdef __has_builtin @@ -69,33 +106,16 @@ # define FMT_NOINLINE #endif -#if __cplusplus == 201103L || __cplusplus == 201402L -# if defined(__clang__) -# define FMT_FALLTHROUGH [[clang::fallthrough]] -# elif FMT_GCC_VERSION >= 700 && !defined(__PGI) && \ - (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) -# define FMT_FALLTHROUGH [[gnu::fallthrough]] -# else -# define FMT_FALLTHROUGH -# endif -#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \ - (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define FMT_FALLTHROUGH [[fallthrough]] -#else -# define FMT_FALLTHROUGH -#endif - -#ifndef FMT_MAYBE_UNUSED -# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) -# define FMT_MAYBE_UNUSED [[maybe_unused]] -# else -# define FMT_MAYBE_UNUSED -# endif -#endif +namespace std { +template <> struct iterator_traits { + using iterator_category = output_iterator_tag; + using value_type = char; +}; +} // namespace std #ifndef FMT_THROW # if FMT_EXCEPTIONS -# if FMT_MSC_VER || FMT_NVCC +# if FMT_MSC_VERSION || defined(__NVCC__) FMT_BEGIN_NAMESPACE namespace detail { template inline void do_throw(const Exception& x) { @@ -111,26 +131,26 @@ FMT_END_NAMESPACE # define FMT_THROW(x) throw x # endif # else -# define FMT_THROW(x) \ - do { \ - static_cast(sizeof(x)); \ - FMT_ASSERT(false, ""); \ - } while (false) +# define FMT_THROW(x) \ + ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what()) # endif #endif -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif #endif #ifndef FMT_USE_USER_DEFINED_LITERALS // EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. -# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ - FMT_MSC_VER >= 1900) && \ +// +// GCC before 4.9 requires a space in `operator"" _a` which is invalid in later +// compiler versions. +# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 409 || \ + FMT_MSC_VERSION >= 1900) && \ (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) # define FMT_USE_USER_DEFINED_LITERALS 1 # else @@ -138,475 +158,677 @@ FMT_END_NAMESPACE # endif #endif -#ifndef FMT_USE_UDL_TEMPLATE -// EDG frontend based compilers (icc, nvcc, etc) and GCC < 6.4 do not properly -// support UDL templates and GCC >= 9 warns about them. -# if FMT_USE_USER_DEFINED_LITERALS && \ - (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 501) && \ - ((FMT_GCC_VERSION >= 604 && __cplusplus >= 201402L) || \ - FMT_CLANG_VERSION >= 304) -# define FMT_USE_UDL_TEMPLATE 1 -# else -# define FMT_USE_UDL_TEMPLATE 0 -# endif -#endif - -#ifndef FMT_USE_FLOAT -# define FMT_USE_FLOAT 1 +// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of +// integer formatter template instantiations to just one by only using the +// largest integer type. This results in a reduction in binary size but will +// cause a decrease in integer formatting performance. +#if !defined(FMT_REDUCE_INT_INSTANTIATIONS) +# define FMT_REDUCE_INT_INSTANTIATIONS 0 #endif -#ifndef FMT_USE_DOUBLE -# define FMT_USE_DOUBLE 1 +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VERSION +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif #endif -#ifndef FMT_USE_LONG_DOUBLE -# define FMT_USE_LONG_DOUBLE 1 +// __builtin_ctz is broken in Intel Compiler Classic on Windows: +// https://github.com/fmtlib/fmt/issues/2510. +#ifndef __ICL +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ + defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \ + FMT_ICC_VERSION || defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif #endif -// __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519 -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +#if FMT_MSC_VERSION +# include // _BitScanReverse[64], _BitScanForward[64], _umul128 #endif // Some compilers masquerade as both MSVC and GCC-likes or otherwise support // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the // MSVC intrinsics if the clz and clzll builtins are not available. -#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) -# include // _BitScanReverse, _BitScanReverse64 - +#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \ + !defined(FMT_BUILTIN_CTZLL) FMT_BEGIN_NAMESPACE namespace detail { // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. -# ifndef __clang__ +# if !defined(__clang__) +# pragma intrinsic(_BitScanForward) # pragma intrinsic(_BitScanReverse) +# if defined(_WIN64) +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif # endif -inline uint32_t clz(uint32_t x) { + +inline auto clz(uint32_t x) -> int { unsigned long r = 0; _BitScanReverse(&r, x); - FMT_ASSERT(x != 0, ""); // Static analysis complains about using uninitialized data // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. - FMT_SUPPRESS_MSC_WARNING(6102) - return 31 - r; + FMT_MSC_WARNING(suppress : 6102) + return 31 ^ static_cast(r); } # define FMT_BUILTIN_CLZ(n) detail::clz(n) -# if defined(_WIN64) && !defined(__clang__) -# pragma intrinsic(_BitScanReverse64) -# endif - -inline uint32_t clzll(uint64_t x) { +inline auto clzll(uint64_t x) -> int { unsigned long r = 0; # ifdef _WIN64 _BitScanReverse64(&r, x); # else // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 - (r + 32); - + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 ^ static_cast(r + 32); // Scan the low 32 bits. _BitScanReverse(&r, static_cast(x)); # endif - FMT_ASSERT(x != 0, ""); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. - FMT_SUPPRESS_MSC_WARNING(6102) - return 63 - r; + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return 63 ^ static_cast(r); } # define FMT_BUILTIN_CLZLL(n) detail::clzll(n) + +inline auto ctz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanForward(&r, x); + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return static_cast(r); +} +# define FMT_BUILTIN_CTZ(n) detail::ctz(n) + +inline auto ctzll(uint64_t x) -> int { + unsigned long r = 0; + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +# ifdef _WIN64 + _BitScanForward64(&r, x); +# else + // Scan the low 32 bits. + if (_BitScanForward(&r, static_cast(x))) return static_cast(r); + // Scan the high 32 bits. + _BitScanForward(&r, static_cast(x >> 32)); + r += 32; +# endif + return static_cast(r); +} +# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) } // namespace detail FMT_END_NAMESPACE #endif -// Enable the deprecated numeric alignment. -#ifndef FMT_DEPRECATED_NUMERIC_ALIGN -# define FMT_DEPRECATED_NUMERIC_ALIGN 0 -#endif - FMT_BEGIN_NAMESPACE + +template +struct is_contiguous> + : std::true_type {}; + namespace detail { -// An equivalent of `*reinterpret_cast(&source)` that doesn't have -// undefined behavior (e.g. due to type aliasing). -// Example: uint64_t d = bit_cast(2.718); -template -inline Dest bit_cast(const Source& source) { - static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); - Dest dest; - std::memcpy(&dest, &source, sizeof(dest)); - return dest; +FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { + ignore_unused(condition); +#ifdef FMT_FUZZ + if (condition) throw std::runtime_error("fuzzing limit reached"); +#endif +} + +#if defined(FMT_USE_STRING_VIEW) +template using std_string_view = std::basic_string_view; +#else +template struct std_string_view {}; +#endif + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; } -inline bool is_big_endian() { - const auto u = 1u; +inline auto is_big_endian() -> bool { +#ifdef _WIN32 + return false; +#elif defined(__BIG_ENDIAN__) + return true; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +#else struct bytes { - char data[sizeof(u)]; + char data[sizeof(int)]; }; - return bit_cast(u).data[0] == 0; + return bit_cast(1).data[0] == 0; +#endif } -// A fallback implementation of uintptr_t for systems that lack it. -struct fallback_uintptr { - unsigned char value[sizeof(void*)]; +class uint128_fallback { + private: + uint64_t lo_, hi_; - fallback_uintptr() = default; - explicit fallback_uintptr(const void* p) { - *this = bit_cast(p); - if (is_big_endian()) { - for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) - std::swap(value[i], value[j]); + public: + constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} + constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} + + constexpr auto high() const noexcept -> uint64_t { return hi_; } + constexpr auto low() const noexcept -> uint64_t { return lo_; } + + template ::value)> + constexpr explicit operator T() const { + return static_cast(lo_); + } + + friend constexpr auto operator==(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; + } + friend constexpr auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return !(lhs == rhs); + } + friend constexpr auto operator>(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; + } + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; + } + friend constexpr auto operator&(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; + } + friend constexpr auto operator~(const uint128_fallback& n) + -> uint128_fallback { + return {~n.hi_, ~n.lo_}; + } + friend auto operator+(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> uint128_fallback { + auto result = uint128_fallback(lhs); + result += rhs; + return result; + } + friend auto operator*(const uint128_fallback& lhs, uint32_t rhs) + -> uint128_fallback { + FMT_ASSERT(lhs.hi_ == 0, ""); + uint64_t hi = (lhs.lo_ >> 32) * rhs; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; + } + friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) + -> uint128_fallback { + return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; + } + FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { + if (shift == 64) return {0, hi_}; + if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { + if (shift == 64) return {lo_, 0}; + if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; + } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { + return *this = *this >> shift; + } + FMT_CONSTEXPR void operator+=(uint128_fallback n) { + uint64_t new_lo = lo_ + n.lo_; + uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); + FMT_ASSERT(new_hi >= hi_, ""); + lo_ = new_lo; + hi_ = new_hi; + } + FMT_CONSTEXPR void operator&=(uint128_fallback n) { + lo_ &= n.lo_; + hi_ &= n.hi_; + } + + FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128_fallback& { + if (is_constant_evaluated()) { + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); + return *this; } +#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + unsigned long long carry; + lo_ = __builtin_addcll(lo_, n, 0, &carry); + hi_ += carry; +#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) + unsigned long long result; + auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); + lo_ = result; + hi_ += carry; +#elif defined(_MSC_VER) && defined(_M_X64) + auto carry = _addcarry_u64(0, lo_, n, &lo_); + _addcarry_u64(carry, hi_, 0, &hi_); +#else + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); +#endif + return *this; } }; + +using uint128_t = conditional_t; + #ifdef UINTPTR_MAX using uintptr_t = ::uintptr_t; -inline uintptr_t to_uintptr(const void* p) { return bit_cast(p); } #else -using uintptr_t = fallback_uintptr; -inline fallback_uintptr to_uintptr(const void* p) { - return fallback_uintptr(p); -} +using uintptr_t = uint128_t; #endif // Returns the largest possible value for type T. Same as // std::numeric_limits::max() but shorter and not affected by the max macro. -template constexpr T max_value() { +template constexpr auto max_value() -> T { return (std::numeric_limits::max)(); } -template constexpr int num_bits() { +template constexpr auto num_bits() -> int { return std::numeric_limits::digits; } // std::numeric_limits::digits may return 0 for 128-bit ints. -template <> constexpr int num_bits() { return 128; } -template <> constexpr int num_bits() { return 128; } -template <> constexpr int num_bits() { - return static_cast(sizeof(void*) * - std::numeric_limits::digits); +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } + +// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t +// and 128-bit pointers to uint128_fallback. +template sizeof(From))> +inline auto bit_cast(const From& from) -> To { + constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); + struct data_t { + unsigned value[static_cast(size)]; + } data = bit_cast(from); + auto result = To(); + if (const_check(is_big_endian())) { + for (int i = 0; i < size; ++i) + result = (result << num_bits()) | data.value[i]; + } else { + for (int i = size - 1; i >= 0; --i) + result = (result << num_bits()) | data.value[i]; + } + return result; +} + +template +FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int { + int lz = 0; + constexpr UInt msb_mask = static_cast(1) << (num_bits() - 1); + for (; (n & msb_mask) == 0; n <<= 1) lz++; + return lz; +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); +#endif + return countl_zero_fallback(n); +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n); +#endif + return countl_zero_fallback(n); } FMT_INLINE void assume(bool condition) { (void)condition; -#if FMT_HAS_BUILTIN(__builtin_assume) +#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION __builtin_assume(condition); +#elif FMT_GCC_VERSION + if (!condition) __builtin_unreachable(); #endif } -// A workaround for gcc 4.8 to make void_t work in a SFINAE context. -template struct void_t_impl { using type = void; }; - -template -using void_t = typename detail::void_t_impl::type; - // An approximation of iterator_t for pre-C++20 systems. template using iterator_t = decltype(std::begin(std::declval())); template using sentinel_t = decltype(std::end(std::declval())); -// Detect the iterator category of *any* given type in a SFINAE-friendly way. -// Unfortunately, older implementations of std::iterator_traits are not safe -// for use in a SFINAE-context. -template -struct iterator_category : std::false_type {}; - -template struct iterator_category { - using type = std::random_access_iterator_tag; -}; - -template -struct iterator_category> { - using type = typename It::iterator_category; -}; - -// Detect if *any* given type models the OutputIterator concept. -template class is_output_iterator { - // Check for mutability because all iterator categories derived from - // std::input_iterator_tag *may* also meet the requirements of an - // OutputIterator, thereby falling into the category of 'mutable iterators' - // [iterator.requirements.general] clause 4. The compiler reveals this - // property only at the point of *actually dereferencing* the iterator! - template - static decltype(*(std::declval())) test(std::input_iterator_tag); - template static char& test(std::output_iterator_tag); - template static const char& test(...); - - using type = decltype(test(typename iterator_category::type{})); - - public: - enum { value = !std::is_const>::value }; -}; - // A workaround for std::string not having mutable data() until C++17. -template inline Char* get_data(std::basic_string& s) { +template +inline auto get_data(std::basic_string& s) -> Char* { return &s[0]; } template -inline typename Container::value_type* get_data(Container& c) { +inline auto get_data(Container& c) -> typename Container::value_type* { return c.data(); } -#if defined(_SECURE_SCL) && _SECURE_SCL -// Make a checked iterator to avoid MSVC warnings. -template using checked_ptr = stdext::checked_array_iterator; -template checked_ptr make_checked(T* p, size_t size) { - return {p, size}; -} -#else -template using checked_ptr = T*; -template inline T* make_checked(T* p, size_t) { return p; } -#endif - -template ::value)> -#if FMT_CLANG_VERSION +// Attempts to reserve space for n extra characters in the output range. +// Returns a pointer to the reserved range or a reference to it. +template ::value&& + is_contiguous::value)> +#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION __attribute__((no_sanitize("undefined"))) #endif -inline checked_ptr -reserve(std::back_insert_iterator it, size_t n) { - Container& c = get_container(it); +inline auto +reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { + auto& c = get_container(it); size_t size = c.size(); c.resize(size + n); - return make_checked(get_data(c) + size, n); + return get_data(c) + size; } -template inline Iterator& reserve(Iterator& it, size_t) { - return it; -} - -template ::value)> -inline std::back_insert_iterator base_iterator( - std::back_insert_iterator& it, - checked_ptr) { +template +inline auto reserve(basic_appender it, size_t n) -> basic_appender { + buffer& buf = get_container(it); + buf.try_reserve(buf.size() + n); return it; } template -inline Iterator base_iterator(Iterator, Iterator it) { +constexpr auto reserve(Iterator& it, size_t) -> Iterator& { return it; } -// An output iterator that counts the number of objects written to it and -// discards them. -class counting_iterator { - private: - size_t count_; - - public: - using iterator_category = std::output_iterator_tag; - using difference_type = std::ptrdiff_t; - using pointer = void; - using reference = void; - using _Unchecked_type = counting_iterator; // Mark iterator as checked. - - struct value_type { - template void operator=(const T&) {} - }; - - counting_iterator() : count_(0) {} - - size_t count() const { return count_; } - - counting_iterator& operator++() { - ++count_; - return *this; - } - - counting_iterator operator++(int) { - auto it = *this; - ++*this; - return it; - } - - value_type operator*() const { return {}; } -}; - -template class truncating_iterator_base { - protected: - OutputIt out_; - size_t limit_; - size_t count_; - - truncating_iterator_base(OutputIt out, size_t limit) - : out_(out), limit_(limit), count_(0) {} - - public: - using iterator_category = std::output_iterator_tag; - using value_type = typename std::iterator_traits::value_type; - using difference_type = void; - using pointer = void; - using reference = void; - using _Unchecked_type = - truncating_iterator_base; // Mark iterator as checked. - - OutputIt base() const { return out_; } - size_t count() const { return count_; } -}; - -// An output iterator that truncates the output and counts the number of objects -// written to it. -template ::value_type>::type> -class truncating_iterator; - template -class truncating_iterator - : public truncating_iterator_base { - mutable typename truncating_iterator_base::value_type blackhole_; +using reserve_iterator = + remove_reference_t(), 0))>; - public: - using value_type = typename truncating_iterator_base::value_type; +template +constexpr auto to_pointer(OutputIt, size_t) -> T* { + return nullptr; +} +template auto to_pointer(basic_appender it, size_t n) -> T* { + buffer& buf = get_container(it); + auto size = buf.size(); + buf.try_reserve(size + n); + if (buf.capacity() < size + n) return nullptr; + buf.try_resize(size + n); + return buf.data() + size; +} - truncating_iterator(OutputIt out, size_t limit) - : truncating_iterator_base(out, limit) {} +template ::value&& + is_contiguous::value)> +inline auto base_iterator(OutputIt it, + typename OutputIt::container_type::value_type*) + -> OutputIt { + return it; +} - truncating_iterator& operator++() { - if (this->count_++ < this->limit_) ++this->out_; - return *this; - } +template +constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { + return it; +} - truncating_iterator operator++(int) { - auto it = *this; - ++*this; - return it; +// is spectacularly slow to compile in C++20 so use a simple fill_n +// instead (#1998). +template +FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) + -> OutputIt { + for (Size i = 0; i < count; ++i) *out++ = value; + return out; +} +template +FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { + if (is_constant_evaluated()) { + return fill_n(out, count, value); } + std::memset(out, value, to_unsigned(count)); + return out + count; +} - value_type& operator*() const { - return this->count_ < this->limit_ ? *this->out_ : blackhole_; - } -}; +template +FMT_CONSTEXPR FMT_NOINLINE auto copy_noinline(InputIt begin, InputIt end, + OutputIt out) -> OutputIt { + return copy(begin, end, out); +} -template -class truncating_iterator - : public truncating_iterator_base { - public: - truncating_iterator(OutputIt out, size_t limit) - : truncating_iterator_base(out, limit) {} +// A public domain branchless UTF-8 decoder by Christopher Wellons: +// https://github.com/skeeto/branchless-utf8 +/* Decode the next character, c, from s, reporting errors in e. + * + * Since this is a branchless decoder, four bytes will be read from the + * buffer regardless of the actual length of the next character. This + * means the buffer _must_ have at least three bytes of zero padding + * following the end of the data stream. + * + * Errors are reported in e, which will be non-zero if the parsed + * character was somehow invalid: invalid byte sequence, non-canonical + * encoding, or a surrogate half. + * + * The function returns a pointer to the next character. When an error + * occurs, this pointer will be a guess that depends on the particular + * error, but it will always advance at least one byte. + */ +FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) + -> const char* { + constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; + constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; + constexpr const int shiftc[] = {0, 18, 12, 6, 0}; + constexpr const int shifte[] = {0, 6, 4, 2, 0}; + + int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" + [static_cast(*s) >> 3]; + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + const char* next = s + len + !len; + + using uchar = unsigned char; + + // Assume a four-byte character and load four bytes. Unused bits are + // shifted out. + *c = uint32_t(uchar(s[0]) & masks[len]) << 18; + *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; + *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; + *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; + *c >>= shiftc[len]; + + // Accumulate the various error conditions. + *e = (*c < mins[len]) << 6; // non-canonical encoding + *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? + *e |= (*c > 0x10FFFF) << 8; // out of range? + *e |= (uchar(s[1]) & 0xc0) >> 2; + *e |= (uchar(s[2]) & 0xc0) >> 4; + *e |= uchar(s[3]) >> 6; + *e ^= 0x2a; // top two bits of each tail byte correct? + *e >>= shifte[len]; + + return next; +} - template truncating_iterator& operator=(T val) { - if (this->count_++ < this->limit_) *this->out_++ = val; - return *this; +constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t(); + +// Invokes f(cp, sv) for every code point cp in s with sv being the string view +// corresponding to the code point. cp is invalid_code_point on error. +template +FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { + auto decode = [f](const char* buf_ptr, const char* ptr) { + auto cp = uint32_t(); + auto error = 0; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, + string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); + return result ? (error ? buf_ptr + 1 : end) : nullptr; + }; + auto p = s.data(); + const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. + if (s.size() >= block_size) { + for (auto end = p + s.size() - block_size + 1; p < end;) { + p = decode(p, p); + if (!p) return; + } } - - truncating_iterator& operator++() { return *this; } - truncating_iterator& operator++(int) { return *this; } - truncating_iterator& operator*() { return *this; } -}; + if (auto num_chars_left = s.data() + s.size() - p) { + char buf[2 * block_size - 1] = {}; + copy(p, p + num_chars_left, buf); + const char* buf_ptr = buf; + do { + auto end = decode(buf_ptr, p); + if (!end) return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); + } +} template -inline size_t count_code_points(basic_string_view s) { +inline auto compute_width(basic_string_view s) -> size_t { return s.size(); } -// Counts the number of code points in a UTF-8 string. -inline size_t count_code_points(basic_string_view s) { - const char* data = s.data(); +// Computes approximate display width of a UTF-8 string. +FMT_CONSTEXPR inline auto compute_width(string_view s) -> size_t { size_t num_code_points = 0; - for (size_t i = 0, size = s.size(); i != size; ++i) { - if ((data[i] & 0xc0) != 0x80) ++num_code_points; - } + // It is not a lambda for compatibility with C++14. + struct count_code_points { + size_t* count; + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { + *count += detail::to_unsigned( + 1 + + (cp >= 0x1100 && + (cp <= 0x115f || // Hangul Jamo init. consonants + cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET + cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: + (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || + (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables + (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs + (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms + (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms + (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms + (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms + (cp >= 0x20000 && cp <= 0x2fffd) || // CJK + (cp >= 0x30000 && cp <= 0x3fffd) || + // Miscellaneous Symbols and Pictographs + Emoticons: + (cp >= 0x1f300 && cp <= 0x1f64f) || + // Supplemental Symbols and Pictographs: + (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; + } + }; + // We could avoid branches by using utf8_decode directly. + for_each_codepoint(s, count_code_points{&num_code_points}); return num_code_points; } -inline size_t count_code_points(basic_string_view s) { - return count_code_points(basic_string_view( - reinterpret_cast(s.data()), s.size())); -} - template -inline size_t code_point_index(basic_string_view s, size_t n) { +inline auto code_point_index(basic_string_view s, size_t n) -> size_t { size_t size = s.size(); return n < size ? n : size; } // Calculates the index of the nth code point in a UTF-8 string. -inline size_t code_point_index(basic_string_view s, size_t n) { - const char8_type* data = s.data(); - size_t num_code_points = 0; - for (size_t i = 0, size = s.size(); i != size; ++i) { - if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) { - return i; +inline auto code_point_index(string_view s, size_t n) -> size_t { + size_t result = s.size(); + const char* begin = s.begin(); + for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) { + if (n != 0) { + --n; + return true; } - } - return s.size(); + result = to_unsigned(sv.begin() - begin); + return false; + }); + return result; } -template -using needs_conversion = bool_constant< - std::is_same::value_type, - char>::value && - std::is_same::value>; +template struct is_integral : std::is_integral {}; +template <> struct is_integral : std::true_type {}; +template <> struct is_integral : std::true_type {}; -template ::value)> -OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { - return std::copy(begin, end, it); -} +template +using is_signed = + std::integral_constant::is_signed || + std::is_same::value>; -template ::value)> -OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { - return std::transform(begin, end, it, - [](char c) { return static_cast(c); }); -} +template +using is_integer = + bool_constant::value && !std::is_same::value && + !std::is_same::value && + !std::is_same::value>; -#ifndef FMT_USE_GRISU -# define FMT_USE_GRISU 1 +#ifndef FMT_USE_FLOAT +# define FMT_USE_FLOAT 1 +#endif +#ifndef FMT_USE_DOUBLE +# define FMT_USE_DOUBLE 1 +#endif +#ifndef FMT_USE_LONG_DOUBLE +# define FMT_USE_LONG_DOUBLE 1 #endif -template constexpr bool use_grisu() { - return FMT_USE_GRISU && std::numeric_limits::is_iec559 && - sizeof(T) <= sizeof(double); -} +#if defined(FMT_USE_FLOAT128) +// Use the provided definition. +#elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE() +# define FMT_USE_FLOAT128 1 +#elif FMT_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \ + !defined(__STRICT_ANSI__) +# define FMT_USE_FLOAT128 1 +#else +# define FMT_USE_FLOAT128 0 +#endif +#if FMT_USE_FLOAT128 +using float128 = __float128; +#else +using float128 = void; +#endif -template -template -void buffer::append(const U* begin, const U* end) { - size_t new_size = size_ + to_unsigned(end - begin); - reserve(new_size); - std::uninitialized_copy(begin, end, - make_checked(ptr_ + size_, capacity_ - size_)); - size_ = new_size; -} -} // namespace detail +template using is_float128 = std::is_same; -// The number of characters to store in the basic_memory_buffer object itself -// to avoid dynamic memory allocation. -enum { inline_buffer_size = 500 }; +template +using is_floating_point = + bool_constant::value || is_float128::value>; -/** - \rst - A dynamically growing memory buffer for trivially copyable/constructible types - with the first ``SIZE`` elements stored in the object itself. +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; - You can use one of the following type aliases for common character types: +template +using is_double_double = bool_constant::digits == 106>; - +----------------+------------------------------+ - | Type | Definition | - +================+==============================+ - | memory_buffer | basic_memory_buffer | - +----------------+------------------------------+ - | wmemory_buffer | basic_memory_buffer | - +----------------+------------------------------+ +#ifndef FMT_USE_FULL_CACHE_DRAGONBOX +# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +#endif - **Example**:: +template +struct is_locale : std::false_type {}; +template +struct is_locale> : std::true_type {}; +} // namespace detail - fmt::memory_buffer out; - format_to(out, "The answer is {}.", 42); +FMT_BEGIN_EXPORT - This will append the following output to the ``out`` object: +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; - .. code-block:: none - - The answer is 42. - - The output can be converted to an ``std::string`` with ``to_string(out)``. - \endrst +/** + * A dynamically growing memory buffer for trivially copyable/constructible + * types with the first `SIZE` elements stored in the object itself. Most + * commonly used via the `memory_buffer` alias for `char`. + * + * **Example**: + * + * auto out = fmt::memory_buffer(); + * fmt::format_to(std::back_inserter(out), "The answer is {}.", 42); + * + * This will append "The answer is 42." to `out`. The buffer content can be + * converted to `std::string` with `to_string(out)`. */ template > @@ -614,62 +836,80 @@ class basic_memory_buffer : public detail::buffer { private: T store_[SIZE]; - // Don't inherit from Allocator avoid generating type_info for it. - Allocator alloc_; + // Don't inherit from Allocator to avoid generating type_info for it. + FMT_NO_UNIQUE_ADDRESS Allocator alloc_; // Deallocate memory allocated by the buffer. - void deallocate() { + FMT_CONSTEXPR20 void deallocate() { T* data = this->data(); if (data != store_) alloc_.deallocate(data, this->capacity()); } - protected: - void grow(size_t size) FMT_OVERRIDE; + static FMT_CONSTEXPR20 void grow(detail::buffer& buf, size_t size) { + detail::abort_fuzzing_if(size > 5000); + auto& self = static_cast(buf); + const size_t max_size = + std::allocator_traits::max_size(self.alloc_); + size_t old_capacity = buf.capacity(); + size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + else if (new_capacity > max_size) + new_capacity = size > max_size ? size : max_size; + T* old_data = buf.data(); + T* new_data = self.alloc_.allocate(new_capacity); + // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481). + detail::assume(buf.size() <= new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + memcpy(new_data, old_data, buf.size() * sizeof(T)); + self.set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity); + } public: using value_type = T; using const_reference = const T&; - explicit basic_memory_buffer(const Allocator& alloc = Allocator()) - : alloc_(alloc) { + FMT_CONSTEXPR20 explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) + : detail::buffer(grow), alloc_(alloc) { this->set(store_, SIZE); + if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T()); } - ~basic_memory_buffer() FMT_OVERRIDE { deallocate(); } + FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } private: // Move data from other to this buffer. - void move(basic_memory_buffer& other) { + FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { alloc_ = std::move(other.alloc_); T* data = other.data(); size_t size = other.size(), capacity = other.capacity(); if (data == other.store_) { this->set(store_, capacity); - std::uninitialized_copy(other.store_, other.store_ + size, - detail::make_checked(store_, capacity)); + detail::copy(other.store_, other.store_ + size, store_); } else { this->set(data, capacity); // Set pointer to the inline array so that delete is not called // when deallocating. other.set(other.store_, 0); + other.clear(); } this->resize(size); } public: - /** - \rst - Constructs a :class:`fmt::basic_memory_buffer` object moving the content - of the other object to it. - \endrst - */ - basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); } - - /** - \rst - Moves the content of the other ``basic_memory_buffer`` object to this one. - \endrst - */ - basic_memory_buffer& operator=(basic_memory_buffer&& other) FMT_NOEXCEPT { + /// Constructs a `basic_memory_buffer` object moving the content of the other + /// object to it. + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept + : detail::buffer(grow) { + move(other); + } + + /// Moves the content of the other `basic_memory_buffer` object to this one. + auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& { FMT_ASSERT(this != &other, ""); deallocate(); move(other); @@ -677,122 +917,220 @@ class basic_memory_buffer : public detail::buffer { } // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { return alloc_; } + auto get_allocator() const -> Allocator { return alloc_; } + + /// Resizes the buffer to contain `count` elements. If T is a POD type new + /// elements may not be initialized. + FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } + + /// Increases the buffer capacity to `new_capacity`. + void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } + + using detail::buffer::append; + template + void append(const ContiguousRange& range) { + append(range.data(), range.data() + range.size()); + } }; +using memory_buffer = basic_memory_buffer; + template -void basic_memory_buffer::grow(size_t size) { -#ifdef FMT_FUZZ - if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); +struct is_contiguous> : std::true_type { +}; + +FMT_END_EXPORT +namespace detail { +FMT_API auto write_console(int fd, string_view text) -> bool; +FMT_API void print(std::FILE*, string_view); +} // namespace detail + +FMT_BEGIN_EXPORT + +// Suppress a misleading warning in older versions of clang. +#if FMT_CLANG_VERSION +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +/// An error reported from a formatting function. +class FMT_SO_VISIBILITY("default") format_error : public std::runtime_error { + public: + using std::runtime_error::runtime_error; +}; + +namespace detail_exported { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template struct fixed_string { + constexpr fixed_string(const Char (&str)[N]) { + detail::copy(static_cast(str), + str + N, data); + } + Char data[N] = {}; +}; #endif - size_t old_capacity = this->capacity(); - size_t new_capacity = old_capacity + old_capacity / 2; - if (size > new_capacity) new_capacity = size; - T* old_data = this->data(); - T* new_data = - std::allocator_traits::allocate(alloc_, new_capacity); - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(old_data, old_data + this->size(), - detail::make_checked(new_data, new_capacity)); - this->set(new_data, new_capacity); - // deallocate must not throw according to the standard, but even if it does, - // the buffer already uses the new storage and will deallocate it in - // destructor. - if (old_data != store_) alloc_.deallocate(old_data, old_capacity); + +// Converts a compile-time string to basic_string_view. +template +constexpr auto compile_string_to_view(const Char (&s)[N]) + -> basic_string_view { + // Remove trailing NUL character if needed. Won't be present if this is used + // with a raw character array (i.e. not defined as a string). + return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; } +template +constexpr auto compile_string_to_view(basic_string_view s) + -> basic_string_view { + return s; +} +} // namespace detail_exported -using memory_buffer = basic_memory_buffer; -using wmemory_buffer = basic_memory_buffer; +// A generic formatting context with custom output iterator and character +// (code unit) support. Char is the format string code unit type which can be +// different from OutputIt::value_type. +template class generic_context { + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; -template -struct is_contiguous> : std::true_type { + public: + using char_type = Char; + using iterator = OutputIt; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + constexpr generic_context(OutputIt out, + basic_format_args ctx_args, + detail::locale_ref loc = {}) + : out_(out), args_(ctx_args), loc_(loc) {} + generic_context(generic_context&&) = default; + generic_context(const generic_context&) = delete; + void operator=(const generic_context&) = delete; + + constexpr auto arg(int id) const -> basic_format_arg { + return args_.get(id); + } + auto arg(basic_string_view name) -> basic_format_arg { + return args_.get(name); + } + FMT_CONSTEXPR auto arg_id(basic_string_view name) -> int { + return args_.get_id(name); + } + auto args() const -> const basic_format_args& { + return args_; + } + + FMT_CONSTEXPR auto out() -> iterator { return out_; } + + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } }; -/** A formatting error such as invalid format string. */ -FMT_CLASS_API -class FMT_API format_error : public std::runtime_error { +class loc_value { + private: + basic_format_arg value_; + public: - explicit format_error(const char* message) : std::runtime_error(message) {} - explicit format_error(const std::string& message) - : std::runtime_error(message) {} - format_error(const format_error&) = default; - format_error& operator=(const format_error&) = default; - format_error(format_error&&) = default; - format_error& operator=(format_error&&) = default; - ~format_error() FMT_NOEXCEPT FMT_OVERRIDE; + template ::value)> + loc_value(T value) : value_(detail::make_arg(value)) {} + + template ::value)> + loc_value(T) {} + + template auto visit(Visitor&& vis) -> decltype(vis(0)) { + return value_.visit(vis); + } }; -namespace detail { +// A locale facet that formats values in UTF-8. +// It is parameterized on the locale to avoid the heavy include. +template class format_facet : public Locale::facet { + private: + std::string separator_; + std::string grouping_; + std::string decimal_point_; -template -using is_signed = - std::integral_constant::is_signed || - std::is_same::value>; + protected: + virtual auto do_put(appender out, loc_value val, + const format_specs& specs) const -> bool; + + public: + static FMT_API typename Locale::id id; + + explicit format_facet(Locale& loc); + explicit format_facet(string_view sep = "", + std::initializer_list g = {3}, + std::string decimal_point = ".") + : separator_(sep.data(), sep.size()), + grouping_(g.begin(), g.end()), + decimal_point_(decimal_point) {} + + auto put(appender out, loc_value val, const format_specs& specs) const + -> bool { + return do_put(out, val, specs); + } +}; + +FMT_END_EXPORT + +namespace detail { // Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. template ::value)> -FMT_CONSTEXPR bool is_negative(T value) { +constexpr auto is_negative(T value) -> bool { return value < 0; } template ::value)> -FMT_CONSTEXPR bool is_negative(T) { +constexpr auto is_negative(T) -> bool { return false; } -template ::value)> -FMT_CONSTEXPR bool is_supported_floating_point(T) { - return (std::is_same::value && FMT_USE_FLOAT) || - (std::is_same::value && FMT_USE_DOUBLE) || - (std::is_same::value && FMT_USE_LONG_DOUBLE); +template +FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { + if (std::is_same()) return FMT_USE_FLOAT; + if (std::is_same()) return FMT_USE_DOUBLE; + if (std::is_same()) return FMT_USE_LONG_DOUBLE; + return true; } // Smallest of uint32_t, uint64_t, uint128_t that is large enough to -// represent all values of T. +// represent all values of an integral type T. template using uint32_or_64_or_128_t = - conditional_t() <= 32, uint32_t, + conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, + uint32_t, conditional_t() <= 64, uint64_t, uint128_t>>; +template +using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \ + (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ + (factor) * 100000000, (factor) * 1000000000 + +// Converts value in the range [0, 100) to a string. +constexpr auto digits2(size_t value) -> const char* { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} -// Static data is placed in this class template for the header-only config. -template struct FMT_EXTERN_TEMPLATE_API basic_data { - static const uint64_t powers_of_10_64[]; - static const uint32_t zero_or_powers_of_10_32[]; - static const uint64_t zero_or_powers_of_10_64[]; - static const uint64_t pow10_significands[]; - static const int16_t pow10_exponents[]; - // GCC generates slightly better code for pairs than chars. - using digit_pair = char[2]; - static const digit_pair digits[]; - static const char hex_digits[]; - static const char foreground_color[]; - static const char background_color[]; - static const char reset_color[5]; - static const wchar_t wreset_color[5]; - static const char signs[]; - static const char left_padding_shifts[5]; - static const char right_padding_shifts[5]; -}; - -#ifndef FMT_EXPORTED -FMT_EXTERN template struct basic_data; +// Sign is a template parameter to workaround a bug in gcc 4.8. +template constexpr auto sign(Sign s) -> Char { +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 + static_assert(std::is_same::value, ""); #endif - -// This is a struct rather than an alias to avoid shadowing warnings in gcc. -struct data : basic_data<> {}; - -#ifdef FMT_BUILTIN_CLZLL -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline int count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return t - (n < data::zero_or_powers_of_10_64[t]) + 1; + return static_cast(((' ' << 24) | ('+' << 16) | ('-' << 8)) >> (s * 8)); } -#else -// Fallback version of count_digits used when __builtin_clz is not available. -inline int count_digits(uint64_t n) { + +template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { int count = 1; for (;;) { // Integer division is slow so do it for a group of four digits instead @@ -806,94 +1144,144 @@ inline int count_digits(uint64_t n) { count += 4; } } -#endif - #if FMT_USE_INT128 -inline int count_digits(uint128_t n) { - int count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000U; - count += 4; - } +FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { + return count_digits_fallback(n); } #endif -// Counts the number of digits in n. BITS = log2(radix). -template inline int count_digits(UInt n) { - int num_digits = 0; - do { - ++num_digits; - } while ((n >>= BITS) != 0); - return num_digits; +#ifdef FMT_BUILTIN_CLZLL +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +inline auto do_count_digits(uint64_t n) -> int { + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); } +#endif -template <> int count_digits<4>(detail::fallback_uintptr n); +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) return do_count_digits(n); +#endif + return count_digits_fallback(n); +} -#if FMT_GCC_VERSION || FMT_CLANG_VERSION -# define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) -#else -# define FMT_ALWAYS_INLINE +// Counts the number of digits in n. BITS = log2(radix). +template +FMT_CONSTEXPR auto count_digits(UInt n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated() && num_bits() == 32) + return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; #endif + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); +} #ifdef FMT_BUILTIN_CLZ -// Optional version of count_digits for better performance on 32-bit platforms. -inline int count_digits(uint32_t n) { - int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return t - (n < data::zero_or_powers_of_10_32[t]) + 1; +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +FMT_INLINE auto do_count_digits(uint32_t n) -> int { +// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) + static constexpr uint64_t table[] = { + FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 + FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 + FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 + FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 + FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k + FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k + FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k + FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M + FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M + FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M + FMT_INC(1000000000), FMT_INC(1000000000) // 4B + }; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); } #endif -template constexpr int digits10() FMT_NOEXCEPT { - return std::numeric_limits::digits10; +// Optional version of count_digits for better performance on 32-bit platforms. +FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) { + return do_count_digits(n); + } +#endif + return count_digits_fallback(n); } -template <> constexpr int digits10() FMT_NOEXCEPT { return 38; } -template <> constexpr int digits10() FMT_NOEXCEPT { return 38; } -template FMT_API std::string grouping_impl(locale_ref loc); -template inline std::string grouping(locale_ref loc) { - return grouping_impl(loc); -} -template <> inline std::string grouping(locale_ref loc) { - return grouping_impl(loc); +template constexpr auto digits10() noexcept -> int { + return std::numeric_limits::digits10; } +template <> constexpr auto digits10() noexcept -> int { return 38; } +template <> constexpr auto digits10() noexcept -> int { return 38; } + +template struct thousands_sep_result { + std::string grouping; + Char thousands_sep; +}; -template FMT_API Char thousands_sep_impl(locale_ref loc); -template inline Char thousands_sep(locale_ref loc) { - return Char(thousands_sep_impl(loc)); +template +FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; +template +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + auto result = thousands_sep_impl(loc); + return {result.grouping, Char(result.thousands_sep)}; } -template <> inline wchar_t thousands_sep(locale_ref loc) { +template <> +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { return thousands_sep_impl(loc); } -template FMT_API Char decimal_point_impl(locale_ref loc); -template inline Char decimal_point(locale_ref loc) { +template +FMT_API auto decimal_point_impl(locale_ref loc) -> Char; +template inline auto decimal_point(locale_ref loc) -> Char { return Char(decimal_point_impl(loc)); } -template <> inline wchar_t decimal_point(locale_ref loc) { +template <> inline auto decimal_point(locale_ref loc) -> wchar_t { return decimal_point_impl(loc); } // Compares two characters for equality. -template bool equal2(const Char* lhs, const char* rhs) { - return lhs[0] == rhs[0] && lhs[1] == rhs[1]; +template auto equal2(const Char* lhs, const char* rhs) -> bool { + return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); } -inline bool equal2(const char* lhs, const char* rhs) { +inline auto equal2(const char* lhs, const char* rhs) -> bool { return memcmp(lhs, rhs, 2) == 0; } // Copies two characters from src to dst. -template void copy2(Char* dst, const char* src) { +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { + memcpy(dst, src, 2); + return; + } *dst++ = static_cast(*src++); *dst = static_cast(*src); } -inline void copy2(char* dst, const char* src) { memcpy(dst, src, 2); } template struct format_decimal_result { Iterator begin; @@ -904,8 +1292,8 @@ template struct format_decimal_result { // buffer of specified size. The caller must ensure that the buffer is large // enough. template -inline format_decimal_result format_decimal(Char* out, UInt value, - int size) { +FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) + -> format_decimal_result { FMT_ASSERT(size >= count_digits(value), "invalid digit count"); out += size; Char* end = out; @@ -914,7 +1302,7 @@ inline format_decimal_result format_decimal(Char* out, UInt value, // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. out -= 2; - copy2(out, data::digits[value % 100]); + copy2(out, digits2(static_cast(value % 100))); value /= 100; } if (value < 10) { @@ -922,172 +1310,277 @@ inline format_decimal_result format_decimal(Char* out, UInt value, return {out, end}; } out -= 2; - copy2(out, data::digits[value]); + copy2(out, digits2(static_cast(value))); return {out, end}; } template >::value)> -inline format_decimal_result format_decimal(Iterator out, UInt value, - int num_digits) { - // Buffer should be large enough to hold all digits (<= digits10 + 1). - enum { max_size = digits10() + 1 }; - Char buffer[2 * max_size]; - auto end = format_decimal(buffer, value, num_digits).end; - return {out, detail::copy_str(buffer, end, out)}; +FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) + -> format_decimal_result { + // Buffer is large enough to hold all digits (digits10 + 1). + Char buffer[digits10() + 1] = {}; + auto end = format_decimal(buffer, value, size).end; + return {out, detail::copy_noinline(buffer, end, out)}; } template -inline Char* format_uint(Char* buffer, UInt value, int num_digits, - bool upper = false) { +FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, + bool upper = false) -> Char* { buffer += num_digits; Char* end = buffer; do { - const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits; - unsigned digit = (value & ((1 << BASE_BITS) - 1)); + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); } while ((value >>= BASE_BITS) != 0); return end; } -template -Char* format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, - bool = false) { - auto char_digits = std::numeric_limits::digits / 4; - int start = (num_digits + char_digits - 1) / char_digits - 1; - if (int start_digits = num_digits % char_digits) { - unsigned value = n.value[start--]; - buffer = format_uint(buffer, value, start_digits); - } - for (; start >= 0; --start) { - unsigned value = n.value[start]; - buffer += char_digits; - auto p = buffer; - for (int i = 0; i < char_digits; ++i) { - unsigned digit = (value & ((1 << BASE_BITS) - 1)); - *--p = static_cast(data::hex_digits[digit]); - value >>= BASE_BITS; - } - } - return buffer; -} - template -inline It format_uint(It out, UInt value, int num_digits, bool upper = false) { +FMT_CONSTEXPR inline auto format_uint(It out, UInt value, int num_digits, + bool upper = false) -> It { + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { + format_uint(ptr, value, num_digits, upper); + return out; + } // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). - char buffer[num_bits() / BASE_BITS + 1]; + char buffer[num_bits() / BASE_BITS + 1] = {}; format_uint(buffer, value, num_digits, upper); - return detail::copy_str(buffer, buffer + num_digits, out); + return detail::copy_noinline(buffer, buffer + num_digits, out); } // A converter from UTF-8 to UTF-16. class utf8_to_utf16 { private: - wmemory_buffer buffer_; + basic_memory_buffer buffer_; public: FMT_API explicit utf8_to_utf16(string_view s); - operator wstring_view() const { return {&buffer_[0], size()}; } - size_t size() const { return buffer_.size() - 1; } - const wchar_t* c_str() const { return &buffer_[0]; } - std::wstring str() const { return {&buffer_[0], size()}; } + operator basic_string_view() const { return {&buffer_[0], size()}; } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const wchar_t* { return &buffer_[0]; } + auto str() const -> std::wstring { return {&buffer_[0], size()}; } }; -template struct null {}; +enum class to_utf8_error_policy { abort, replace }; -// Workaround an array initialization issue in gcc 4.8. -template struct fill_t { +// A converter from UTF-16/UTF-32 (host endian) to UTF-8. +template class to_utf8 { private: - enum { max_size = 4 }; - Char data_[max_size]; - unsigned char size_; + Buffer buffer_; public: - FMT_CONSTEXPR void operator=(basic_string_view s) { - auto size = s.size(); - if (size > max_size) { - FMT_THROW(format_error("invalid fill")); - return; + to_utf8() {} + explicit to_utf8(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) { + static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4, + "Expect utf16 or utf32"); + if (!convert(s, policy)) + FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16" + : "invalid utf32")); + } + operator string_view() const { return string_view(&buffer_[0], size()); } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const char* { return &buffer_[0]; } + auto str() const -> std::string { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a bool instead of throwing exception on + // conversion error. This method may still throw in case of memory allocation + // error. + auto convert(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + if (!convert(buffer_, s, policy)) return false; + buffer_.push_back(0); + return true; + } + static auto convert(Buffer& buf, basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + for (auto p = s.begin(); p != s.end(); ++p) { + uint32_t c = static_cast(*p); + if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) { + // Handle a surrogate pair. + ++p; + if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { + if (policy == to_utf8_error_policy::abort) return false; + buf.append(string_view("\xEF\xBF\xBD")); + --p; + } else { + c = (c << 10) + static_cast(*p) - 0x35fdc00; + } + } else if (c < 0x80) { + buf.push_back(static_cast(c)); + } else if (c < 0x800) { + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if (c >= 0x10000 && c <= 0x10ffff) { + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else { + return false; + } } - for (size_t i = 0; i < size; ++i) data_[i] = s[i]; - size_ = static_cast(size); + return true; } +}; - size_t size() const { return size_; } - const Char* data() const { return data_; } +// Computes 128-bit result of multiplication of two 64-bit unsigned integers. +inline auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return {static_cast(p >> 64), static_cast(p)}; +#elif defined(_MSC_VER) && defined(_M_X64) + auto hi = uint64_t(); + auto lo = _umul128(x, y, &hi); + return {hi, lo}; +#else + const uint64_t mask = static_cast(max_value()); - FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; } - FMT_CONSTEXPR const Char& operator[](size_t index) const { - return data_[index]; - } + uint64_t a = x >> 32; + uint64_t b = x & mask; + uint64_t c = y >> 32; + uint64_t d = y & mask; - static FMT_CONSTEXPR fill_t make() { - auto fill = fill_t(); - fill[0] = Char(' '); - fill.size_ = 1; - return fill; - } -}; -} // namespace detail + uint64_t ac = a * c; + uint64_t bc = b * c; + uint64_t ad = a * d; + uint64_t bd = b * d; + + uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask); + + return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), + (intermediate << 32) + (bd & mask)}; +#endif +} -// We cannot use enum classes as bit fields because of a gcc bug -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. -namespace align { -enum type { none, left, right, center, numeric }; +namespace dragonbox { +// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from +// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. +inline auto floor_log10_pow2(int e) noexcept -> int { + FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent"); + static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); + return (e * 315653) >> 20; } -using align_t = align::type; -namespace sign { -enum type { none, minus, plus, space }; +inline auto floor_log2_pow10(int e) noexcept -> int { + FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); + return (e * 1741647) >> 19; } -using sign_t = sign::type; -// Format specifiers for built-in and string types. -template struct basic_format_specs { - int width; - int precision; - char type; - align_t align : 4; - sign_t sign : 3; - bool alt : 1; // Alternate form ('#'). - detail::fill_t fill; - - constexpr basic_format_specs() - : width(0), - precision(-1), - type(0), - align(align::none), - sign(sign::none), - alt(false), - fill(detail::fill_t::make()) {} +// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. +inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return static_cast(p >> 64); +#elif defined(_MSC_VER) && defined(_M_X64) + return __umulh(x, y); +#else + return umul128(x, y).high(); +#endif +} + +// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint128_fallback r = umul128(x, y.high()); + r += umul128_upper64(x, y.low()); + return r; +} + +FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback; + +// Type-specific information that Dragonbox uses. +template struct float_info; + +template <> struct float_info { + using carrier_uint = uint32_t; + static const int exponent_bits = 8; + static const int kappa = 1; + static const int big_divisor = 100; + static const int small_divisor = 10; + static const int min_k = -31; + static const int max_k = 46; + static const int shorter_interval_tie_lower_threshold = -35; + static const int shorter_interval_tie_upper_threshold = -35; }; -using format_specs = basic_format_specs; +template <> struct float_info { + using carrier_uint = uint64_t; + static const int exponent_bits = 11; + static const int kappa = 2; + static const int big_divisor = 1000; + static const int small_divisor = 100; + static const int min_k = -292; + static const int max_k = 341; + static const int shorter_interval_tie_lower_threshold = -77; + static const int shorter_interval_tie_upper_threshold = -77; +}; -namespace detail { +// An 80- or 128-bit floating point number. +template +struct float_info::digits == 64 || + std::numeric_limits::digits == 113 || + is_float128::value>> { + using carrier_uint = detail::uint128_t; + static const int exponent_bits = 15; +}; -// A floating-point presentation format. -enum class float_format : unsigned char { - general, // General: exponent notation or fixed point based on magnitude. - exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. - fixed, // Fixed point with the default precision of 6, e.g. 0.0012. - hex +// A double-double floating point number. +template +struct float_info::value>> { + using carrier_uint = detail::uint128_t; }; -struct float_specs { - int precision; - float_format format : 8; - sign_t sign : 8; - bool upper : 1; - bool locale : 1; - bool binary32 : 1; - bool use_grisu : 1; - bool showpoint : 1; +template struct decimal_fp { + using significand_type = typename float_info::carrier_uint; + significand_type significand; + int exponent; }; +template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; +} // namespace dragonbox + +// Returns true iff Float has the implicit bit which is not stored. +template constexpr auto has_implicit_bit() -> bool { + // An 80-bit FP number has a 64-bit significand an no implicit bit. + return std::numeric_limits::digits != 64; +} + +// Returns the number of significand bits stored in Float. The implicit bit is +// not counted since it is not stored. +template constexpr auto num_significand_bits() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 112 + : (std::numeric_limits::digits - + (has_implicit_bit() ? 1 : 0)); +} + +template +constexpr auto exponent_mask() -> + typename dragonbox::float_info::carrier_uint { + using float_uint = typename dragonbox::float_info::carrier_uint; + return ((float_uint(1) << dragonbox::float_info::exponent_bits) - 1) + << num_significand_bits(); +} +template constexpr auto exponent_bias() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 16383 + : std::numeric_limits::max_exponent - 1; +} + // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. -template It write_exponent(int exp, It it) { +template +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); if (exp < 0) { *it++ = static_cast('-'); @@ -1096,333 +1589,346 @@ template It write_exponent(int exp, It it) { *it++ = static_cast('+'); } if (exp >= 100) { - const char* top = data::digits[exp / 100]; + const char* top = digits2(to_unsigned(exp / 100)); if (exp >= 1000) *it++ = static_cast(top[0]); *it++ = static_cast(top[1]); exp %= 100; } - const char* d = data::digits[exp]; + const char* d = digits2(to_unsigned(exp)); *it++ = static_cast(d[0]); *it++ = static_cast(d[1]); return it; } -template class float_writer { - private: - // The number is given as v = digits_ * pow(10, exp_). - const char* digits_; - int num_digits_; - int exp_; - size_t size_; - float_specs specs_; - Char decimal_point_; - - template It prettify(It it) const { - // pow(10, full_exp - 1) <= v <= pow(10, full_exp). - int full_exp = num_digits_ + exp_; - if (specs_.format == float_format::exp) { - // Insert a decimal point after the first digit and add an exponent. - *it++ = static_cast(*digits_); - int num_zeros = specs_.precision - num_digits_; - if (num_digits_ > 1 || specs_.showpoint) *it++ = decimal_point_; - it = copy_str(digits_ + 1, digits_ + num_digits_, it); - if (num_zeros > 0 && specs_.showpoint) - it = std::fill_n(it, num_zeros, static_cast('0')); - *it++ = static_cast(specs_.upper ? 'E' : 'e'); - return write_exponent(full_exp - 1, it); - } - if (num_digits_ <= full_exp) { - // 1234e7 -> 12340000000[.0+] - it = copy_str(digits_, digits_ + num_digits_, it); - it = std::fill_n(it, full_exp - num_digits_, static_cast('0')); - if (specs_.showpoint || specs_.precision < 0) { - *it++ = decimal_point_; - int num_zeros = specs_.precision - full_exp; - if (num_zeros <= 0) { - if (specs_.format != float_format::fixed) - *it++ = static_cast('0'); - return it; - } -#ifdef FMT_FUZZ - if (num_zeros > 5000) - throw std::runtime_error("fuzz mode - avoiding excessive cpu use"); -#endif - it = std::fill_n(it, num_zeros, static_cast('0')); - } - } else if (full_exp > 0) { - // 1234e-2 -> 12.34[0+] - it = copy_str(digits_, digits_ + full_exp, it); - if (!specs_.showpoint) { - // Remove trailing zeros. - int num_digits = num_digits_; - while (num_digits > full_exp && digits_[num_digits - 1] == '0') - --num_digits; - if (num_digits != full_exp) *it++ = decimal_point_; - return copy_str(digits_ + full_exp, digits_ + num_digits, it); - } - *it++ = decimal_point_; - it = copy_str(digits_ + full_exp, digits_ + num_digits_, it); - if (specs_.precision > num_digits_) { - // Add trailing zeros. - int num_zeros = specs_.precision - num_digits_; - it = std::fill_n(it, num_zeros, static_cast('0')); - } - } else { - // 1234e-6 -> 0.001234 - *it++ = static_cast('0'); - int num_zeros = -full_exp; - int num_digits = num_digits_; - if (num_digits == 0 && specs_.precision >= 0 && - specs_.precision < num_zeros) { - num_zeros = specs_.precision; - } - // Remove trailing zeros. - if (!specs_.showpoint) - while (num_digits > 0 && digits_[num_digits - 1] == '0') --num_digits; - if (num_zeros != 0 || num_digits != 0 || specs_.showpoint) { - *it++ = decimal_point_; - it = std::fill_n(it, num_zeros, static_cast('0')); - it = copy_str(digits_, digits_ + num_digits, it); - } - } - return it; - } - - public: - float_writer(const char* digits, int num_digits, int exp, float_specs specs, - Char decimal_point) - : digits_(digits), - num_digits_(num_digits), - exp_(exp), - specs_(specs), - decimal_point_(decimal_point) { - int full_exp = num_digits + exp - 1; - int precision = specs.precision > 0 ? specs.precision : 16; - if (specs_.format == float_format::general && - !(full_exp >= -4 && full_exp < precision)) { - specs_.format = float_format::exp; - } - size_ = prettify(counting_iterator()).count(); - size_ += specs.sign ? 1 : 0; - } - - size_t size() const { return size_; } - - template It operator()(It it) const { - if (specs_.sign) *it++ = static_cast(data::signs[specs_.sign]); - return prettify(it); +// A floating-point number f * pow(2, e) where F is an unsigned type. +template struct basic_fp { + F f; + int e; + + static constexpr const int num_significand_bits = + static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() : f(0), e(0) {} + constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. + template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = + detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto biased_e = static_cast((u & exponent_mask()) >> + num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) + // other than the smallest normalized number (biased_e > 1). + auto is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e == 0) + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); + e = biased_e - exponent_bias() - num_float_significand_bits; + if (!has_implicit_bit()) ++e; + return is_predecessor_closer; + } + + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); } }; -template -int format_float(T value, int precision, float_specs specs, buffer& buf); - -// Formats a floating-point number with snprintf. -template -int snprintf_float(T value, int precision, float_specs specs, - buffer& buf); - -template T promote_float(T value) { return value; } -inline double promote_float(float value) { return static_cast(value); } - -template -FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) { - switch (spec) { - case 0: - case 'd': - handler.on_dec(); - break; - case 'x': - case 'X': - handler.on_hex(); - break; - case 'b': - case 'B': - handler.on_bin(); - break; - case 'o': - handler.on_oct(); - break; -#ifdef FMT_DEPRECATED_N_SPECIFIER - case 'n': -#endif - case 'L': - handler.on_num(); - break; - case 'c': - handler.on_chr(); - break; - default: - handler.on_error(); - } +using fp = basic_fp; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template +FMT_CONSTEXPR auto normalize(basic_fp value) -> basic_fp { + // Handle subnormals. + const auto implicit_bit = F(1) << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = basic_fp::num_significand_bits - + num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; } -template -FMT_CONSTEXPR float_specs parse_float_type_spec( - const basic_format_specs& specs, ErrorHandler&& eh = {}) { - auto result = float_specs(); - result.showpoint = specs.alt; - switch (specs.type) { - case 0: - result.format = float_format::general; - result.showpoint |= specs.precision > 0; - break; - case 'G': - result.upper = true; - FMT_FALLTHROUGH; - case 'g': - result.format = float_format::general; - break; - case 'E': - result.upper = true; - FMT_FALLTHROUGH; - case 'e': - result.format = float_format::exp; - result.showpoint |= specs.precision != 0; - break; - case 'F': - result.upper = true; - FMT_FALLTHROUGH; - case 'f': - result.format = float_format::fixed; - result.showpoint |= specs.precision != 0; - break; - case 'A': - result.upper = true; - FMT_FALLTHROUGH; - case 'a': - result.format = float_format::hex; - break; -#ifdef FMT_DEPRECATED_N_SPECIFIER - case 'n': +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t { +#if FMT_USE_INT128 + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +#else + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); #endif - case 'L': - result.locale = true; - break; - default: - eh.on_error("invalid type specifier"); - break; - } - return result; } -template -FMT_CONSTEXPR void handle_char_specs(const basic_format_specs* specs, - Handler&& handler) { - if (!specs) return handler.on_char(); - if (specs->type && specs->type != 'c') return handler.on_int(); - if (specs->align == align::numeric || specs->sign != sign::none || specs->alt) - handler.on_error("invalid format specifier for char"); - handler.on_char(); +FMT_CONSTEXPR inline auto operator*(fp x, fp y) -> fp { + return {multiply(x.f, y.f), x.e + y.e + 64}; } -template -FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) { - if (spec == 0 || spec == 's') - handler.on_string(); - else if (spec == 'p') - handler.on_pointer(); - else - handler.on_error("invalid type specifier"); -} +template () == num_bits()> +using convert_float_result = + conditional_t::value || doublish, double, T>; -template -FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) { - if (spec != 0 && spec != 's') eh.on_error("invalid type specifier"); +template +constexpr auto convert_float(T value) -> convert_float_result { + return static_cast>(value); } -template -FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { - if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier"); -} - -template class int_type_checker : private ErrorHandler { - public: - FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} - - FMT_CONSTEXPR void on_dec() {} - FMT_CONSTEXPR void on_hex() {} - FMT_CONSTEXPR void on_bin() {} - FMT_CONSTEXPR void on_oct() {} - FMT_CONSTEXPR void on_num() {} - FMT_CONSTEXPR void on_chr() {} - - FMT_CONSTEXPR void on_error() { - ErrorHandler::on_error("invalid type specifier"); - } -}; - -template -class char_specs_checker : public ErrorHandler { - private: - char type_; - - public: - FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh) - : ErrorHandler(eh), type_(type) {} - - FMT_CONSTEXPR void on_int() { - handle_int_type_spec(type_, int_type_checker(*this)); - } - FMT_CONSTEXPR void on_char() {} -}; - -template -class cstring_type_checker : public ErrorHandler { - public: - FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh) - : ErrorHandler(eh) {} - - FMT_CONSTEXPR void on_string() {} - FMT_CONSTEXPR void on_pointer() {} -}; - -template -FMT_NOINLINE OutputIt fill(OutputIt it, size_t n, const fill_t& fill) { - auto fill_size = fill.size(); - if (fill_size == 1) return std::fill_n(it, n, fill[0]); - for (size_t i = 0; i < n; ++i) it = std::copy_n(fill.data(), fill_size, it); - return it; +template +FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t& fill) + -> OutputIt { + auto fill_size = fill.size(); + if (fill_size == 1) return detail::fill_n(it, n, fill.template get()); + if (const Char* data = fill.template data()) { + for (size_t i = 0; i < n; ++i) it = copy(data, data + fill_size, it); + } + return it; } // Writes the output of f, padded according to format specifications in specs. // size: output size in code units. // width: output display width in (terminal) column positions. -template -inline OutputIt write_padded(OutputIt out, - const basic_format_specs& specs, size_t size, - size_t width, const F& f) { +FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs& specs, + size_t size, size_t width, F&& f) -> OutputIt { static_assert(align == align::left || align == align::right, ""); unsigned spec_width = to_unsigned(specs.width); size_t padding = spec_width > width ? spec_width - width : 0; - auto* shifts = align == align::left ? data::left_padding_shifts - : data::right_padding_shifts; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; size_t left_padding = padding >> shifts[specs.align]; + size_t right_padding = padding - left_padding; auto it = reserve(out, size + padding * specs.fill.size()); - it = fill(it, left_padding, specs.fill); + if (left_padding != 0) it = fill(it, left_padding, specs.fill); it = f(it); - it = fill(it, padding - left_padding, specs.fill); + if (right_padding != 0) it = fill(it, right_padding, specs.fill); return base_iterator(out, it); } -template -inline OutputIt write_padded(OutputIt out, - const basic_format_specs& specs, size_t size, - const F& f) { - return write_padded(out, specs, size, size, f); +constexpr auto write_padded(OutputIt out, const format_specs& specs, + size_t size, F&& f) -> OutputIt { + return write_padded(out, specs, size, size, f); +} + +template +FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, + const format_specs& specs = {}) -> OutputIt { + return write_padded( + out, specs, bytes.size(), [bytes](reserve_iterator it) { + const char* data = bytes.data(); + return copy(data, data + bytes.size(), it); + }); +} + +template +auto write_ptr(OutputIt out, UIntPtr value, const format_specs* specs) + -> OutputIt { + int num_digits = count_digits<4>(value); + auto size = to_unsigned(num_digits) + size_t(2); + auto write = [=](reserve_iterator it) { + *it++ = static_cast('0'); + *it++ = static_cast('x'); + return format_uint<4, Char>(it, value, num_digits); + }; + return specs ? write_padded(out, *specs, size, write) + : base_iterator(out, write(reserve(out, size))); +} + +// Returns true iff the code point cp is printable. +FMT_API auto is_printable(uint32_t cp) -> bool; + +inline auto needs_escape(uint32_t cp) -> bool { + return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || + !is_printable(cp); +} + +template struct find_escape_result { + const Char* begin; + const Char* end; + uint32_t cp; +}; + +template +auto find_escape(const Char* begin, const Char* end) + -> find_escape_result { + for (; begin != end; ++begin) { + uint32_t cp = static_cast>(*begin); + if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; + if (needs_escape(cp)) return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char* begin, const char* end) + -> find_escape_result { + if (!use_utf8()) return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), + [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; +} + +#define FMT_STRING_IMPL(s, base, explicit) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ + using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ + operator fmt::basic_string_view() const { \ + return fmt::detail_exported::compile_string_to_view(s); \ + } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() + +/** + * Constructs a compile-time format string from a string literal `s`. + * + * **Example**: + * + * // A compile-time error because 'd' is an invalid specifier for strings. + * std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, ) + +template +auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { + *out++ = static_cast('\\'); + *out++ = static_cast(prefix); + Char buf[width]; + fill_n(buf, width, static_cast('0')); + format_uint<4>(buf, cp, width); + return copy(buf, buf + width, out); +} + +template +auto write_escaped_cp(OutputIt out, const find_escape_result& escape) + -> OutputIt { + auto c = static_cast(escape.cp); + switch (escape.cp) { + case '\n': + *out++ = static_cast('\\'); + c = static_cast('n'); + break; + case '\r': + *out++ = static_cast('\\'); + c = static_cast('r'); + break; + case '\t': + *out++ = static_cast('\\'); + c = static_cast('t'); + break; + case '"': + FMT_FALLTHROUGH; + case '\'': + FMT_FALLTHROUGH; + case '\\': + *out++ = static_cast('\\'); + break; + default: + if (escape.cp < 0x100) return write_codepoint<2, Char>(out, 'x', escape.cp); + if (escape.cp < 0x10000) + return write_codepoint<4, Char>(out, 'u', escape.cp); + if (escape.cp < 0x110000) + return write_codepoint<8, Char>(out, 'U', escape.cp); + for (Char escape_char : basic_string_view( + escape.begin, to_unsigned(escape.end - escape.begin))) { + out = write_codepoint<2, Char>(out, 'x', + static_cast(escape_char) & 0xFF); + } + return out; + } + *out++ = c; + return out; +} + +template +auto write_escaped_string(OutputIt out, basic_string_view str) + -> OutputIt { + *out++ = static_cast('"'); + auto begin = str.begin(), end = str.end(); + do { + auto escape = find_escape(begin, end); + out = copy(begin, escape.begin, out); + begin = escape.end; + if (!begin) break; + out = write_escaped_cp(out, escape); + } while (begin != end); + *out++ = static_cast('"'); + return out; +} + +template +auto write_escaped_char(OutputIt out, Char v) -> OutputIt { + Char v_array[1] = {v}; + *out++ = static_cast('\''); + if ((needs_escape(static_cast(v)) && v != static_cast('"')) || + v == static_cast('\'')) { + out = write_escaped_cp(out, + find_escape_result{v_array, v_array + 1, + static_cast(v)}); + } else { + *out++ = v; + } + *out++ = static_cast('\''); + return out; } template -OutputIt write_bytes(OutputIt out, string_view bytes, - const basic_format_specs& specs) { - using iterator = remove_reference_t; - return write_padded(out, specs, bytes.size(), [bytes](iterator it) { - const char* data = bytes.data(); - return copy_str(data, data + bytes.size(), it); +FMT_CONSTEXPR auto write_char(OutputIt out, Char value, + const format_specs& specs) -> OutputIt { + bool is_debug = specs.type == presentation_type::debug; + return write_padded(out, specs, 1, [=](reserve_iterator it) { + if (is_debug) return write_escaped_char(it, value); + *it++ = value; + return it; }); } +template +FMT_CONSTEXPR auto write(OutputIt out, Char value, const format_specs& specs, + locale_ref loc = {}) -> OutputIt { + // char is formatted as unsigned char for consistency across platforms. + using unsigned_type = + conditional_t::value, unsigned char, unsigned>; + return check_char_specs(specs) + ? write_char(out, value, specs) + : write(out, static_cast(value), specs, loc); +} // Data for write_int that doesn't depend on output iterator type. It is used to // avoid template code bloat. @@ -1430,9 +1936,9 @@ template struct write_int_data { size_t size; size_t padding; - write_int_data(int num_digits, string_view prefix, - const basic_format_specs& specs) - : size(prefix.size() + to_unsigned(num_digits)), padding(0) { + FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, + const format_specs& specs) + : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { if (specs.align == align::numeric) { auto width = to_unsigned(specs.width); if (width > size) { @@ -1440,7 +1946,7 @@ template struct write_int_data { size = width; } } else if (specs.precision > num_digits) { - size = prefix.size() + to_unsigned(specs.precision); + size = (prefix >> 24) + to_unsigned(specs.precision); padding = to_unsigned(specs.precision - num_digits); } } @@ -1448,1577 +1954,1966 @@ template struct write_int_data { // Writes an integer in the format // -// where are written by f(it). -template -OutputIt write_int(OutputIt out, int num_digits, string_view prefix, - const basic_format_specs& specs, F f) { - auto data = write_int_data(num_digits, prefix, specs); - using iterator = remove_reference_t; - return write_padded(out, specs, data.size, [=](iterator it) { - if (prefix.size() != 0) - it = copy_str(prefix.begin(), prefix.end(), it); - it = std::fill_n(it, data.padding, static_cast('0')); - return f(it); - }); -} - -template -OutputIt write(OutputIt out, basic_string_view s, - const basic_format_specs& specs) { - auto data = s.data(); - auto size = s.size(); - if (specs.precision >= 0 && to_unsigned(specs.precision) < size) - size = code_point_index(s, to_unsigned(specs.precision)); - auto width = specs.width != 0 - ? count_code_points(basic_string_view(data, size)) - : 0; - using iterator = remove_reference_t; - return write_padded(out, specs, size, width, [=](iterator it) { - return copy_str(data, data + size, it); - }); -} - -// The handle_int_type_spec handler that writes an integer. -template struct int_writer { - OutputIt out; - locale_ref locale; - const basic_format_specs& specs; - UInt abs_value; - char prefix[4]; - unsigned prefix_size; - - using iterator = - remove_reference_t(), 0))>; - - string_view get_prefix() const { return string_view(prefix, prefix_size); } - - template - int_writer(OutputIt output, locale_ref loc, Int value, - const basic_format_specs& s) - : out(output), - locale(loc), - specs(s), - abs_value(static_cast(value)), - prefix_size(0) { - static_assert(std::is_same, UInt>::value, ""); - if (is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (specs.sign != sign::none && specs.sign != sign::minus) { - prefix[0] = specs.sign == sign::plus ? '+' : ' '; - ++prefix_size; +// where are written by write_digits(it). +// prefix contains chars in three lower bytes and the size in the fourth byte. +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, + unsigned prefix, + const format_specs& specs, + W write_digits) -> OutputIt { + // Slightly faster check for specs.width == 0 && specs.precision == -1. + if ((specs.width | (specs.precision + 1)) == 0) { + auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); + if (prefix != 0) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); } + return base_iterator(out, write_digits(it)); } + auto data = write_int_data(num_digits, prefix, specs); + return write_padded( + out, specs, data.size, [=](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + it = detail::fill_n(it, data.padding, static_cast('0')); + return write_digits(it); + }); +} - void on_dec() { - auto num_digits = count_digits(abs_value); - out = write_int( - out, num_digits, get_prefix(), specs, [this, num_digits](iterator it) { - return format_decimal(it, abs_value, num_digits).end; - }); - } - - void on_hex() { - if (specs.alt) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = specs.type; - } - int num_digits = count_digits<4>(abs_value); - out = write_int(out, num_digits, get_prefix(), specs, - [this, num_digits](iterator it) { - return format_uint<4, Char>(it, abs_value, num_digits, - specs.type != 'x'); - }); - } +template class digit_grouping { + private: + std::string grouping_; + std::basic_string thousands_sep_; - void on_bin() { - if (specs.alt) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = static_cast(specs.type); - } - int num_digits = count_digits<1>(abs_value); - out = write_int(out, num_digits, get_prefix(), specs, - [this, num_digits](iterator it) { - return format_uint<1, Char>(it, abs_value, num_digits); - }); - } + struct next_state { + std::string::const_iterator group; + int pos; + }; + auto initial_state() const -> next_state { return {grouping_.begin(), 0}; } - void on_oct() { - int num_digits = count_digits<3>(abs_value); - if (specs.alt && specs.precision <= num_digits && abs_value != 0) { - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. - prefix[prefix_size++] = '0'; - } - out = write_int(out, num_digits, get_prefix(), specs, - [this, num_digits](iterator it) { - return format_uint<3, Char>(it, abs_value, num_digits); - }); + // Returns the next digit group separator position. + auto next(next_state& state) const -> int { + if (thousands_sep_.empty()) return max_value(); + if (state.group == grouping_.end()) return state.pos += grouping_.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; } - enum { sep_size = 1 }; - - void on_num() { - std::string groups = grouping(locale); - if (groups.empty()) return on_dec(); - auto sep = thousands_sep(locale); - if (!sep) return on_dec(); - int num_digits = count_digits(abs_value); - int size = num_digits, n = num_digits; - std::string::const_iterator group = groups.cbegin(); - while (group != groups.cend() && n > *group && *group > 0 && - *group != max_value()) { - size += sep_size; - n -= *group; - ++group; + public: + explicit digit_grouping(locale_ref loc, bool localized = true) { + if (!localized) return; + auto sep = thousands_sep(loc); + grouping_ = sep.grouping; + if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); + } + digit_grouping(std::string grouping, std::basic_string sep) + : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {} + + auto has_separator() const -> bool { return !thousands_sep_.empty(); } + + auto count_separators(int num_digits) const -> int { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + auto apply(Out out, basic_string_view digits) const -> Out { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) { + if (i >= num_digits) break; + separators.push_back(i); } - if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back()); - char digits[40]; - format_decimal(digits, abs_value, num_digits); - basic_memory_buffer buffer; - size += prefix_size; - buffer.resize(size); - basic_string_view s(&sep, sep_size); - // Index of a decimal digit with the least significant digit having index 0. - int digit_index = 0; - group = groups.cbegin(); - auto p = buffer.data() + size; - for (int i = num_digits - 1; i >= 0; --i) { - *--p = static_cast(digits[i]); - if (*group <= 0 || ++digit_index % *group != 0 || - *group == max_value()) - continue; - if (group + 1 != groups.cend()) { - digit_index = 0; - ++group; + for (int i = 0, sep_index = static_cast(separators.size() - 1); + i < num_digits; ++i) { + if (num_digits - i == separators[sep_index]) { + out = copy(thousands_sep_.data(), + thousands_sep_.data() + thousands_sep_.size(), out); + --sep_index; } - p -= s.size(); - std::uninitialized_copy(s.data(), s.data() + s.size(), - make_checked(p, s.size())); + *out++ = static_cast(digits[to_unsigned(i)]); } - if (prefix_size != 0) p[-1] = static_cast('-'); - using iterator_t = remove_reference_t; - auto data = buffer.data(); - out = write_padded(out, specs, size, size, [=](iterator_t it) { - return copy_str(data, data + size, it); - }); - } - - void on_chr() { *out++ = static_cast(abs_value); } - - FMT_NORETURN void on_error() { - FMT_THROW(format_error("invalid type specifier")); + return out; } }; -template -OutputIt write_nonfinite(OutputIt out, bool isinf, - const basic_format_specs& specs, - const float_specs& fspecs) { - auto str = - isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); - constexpr size_t str_size = 3; - auto sign = fspecs.sign; - auto size = str_size + (sign ? 1 : 0); - using iterator = remove_reference_t; - return write_padded(out, specs, size, [=](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); - return copy_str(str, str + str_size, it); - }); -} - -template ::value)> -OutputIt write(OutputIt out, T value, basic_format_specs specs, - locale_ref loc = {}) { - if (const_check(!is_supported_floating_point(value))) return out; - float_specs fspecs = parse_float_type_spec(specs); - fspecs.sign = specs.sign; - if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. - fspecs.sign = sign::minus; - value = -value; - } else if (fspecs.sign == sign::minus) { - fspecs.sign = sign::none; - } - - if (!std::isfinite(value)) - return write_nonfinite(out, std::isinf(value), specs, fspecs); - - if (specs.align == align::numeric && fspecs.sign) { - auto it = reserve(out, 1); - *it++ = static_cast(data::signs[fspecs.sign]); - out = base_iterator(out, it); - fspecs.sign = sign::none; - if (specs.width != 0) --specs.width; - } - - memory_buffer buffer; - if (fspecs.format == float_format::hex) { - if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]); - snprintf_float(promote_float(value), specs.precision, fspecs, buffer); - return write_bytes(out, {buffer.data(), buffer.size()}, specs); - } - int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; - if (fspecs.format == float_format::exp) { - if (precision == max_value()) - FMT_THROW(format_error("number is too big")); - else - ++precision; - } - if (const_check(std::is_same())) fspecs.binary32 = true; - fspecs.use_grisu = use_grisu(); - int exp = format_float(promote_float(value), precision, fspecs, buffer); - fspecs.precision = precision; - Char point = - fspecs.locale ? decimal_point(loc) : static_cast('.'); - float_writer w(buffer.data(), static_cast(buffer.size()), exp, - fspecs, point); - return write_padded(out, specs, w.size(), w); -} - -template ::value)> -OutputIt write(OutputIt out, T value) { - if (const_check(!is_supported_floating_point(value))) return out; - auto fspecs = float_specs(); - if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. - fspecs.sign = sign::minus; - value = -value; - } - - auto specs = basic_format_specs(); - if (!std::isfinite(value)) - return write_nonfinite(out, std::isinf(value), specs, fspecs); - - memory_buffer buffer; - int precision = -1; - if (const_check(std::is_same())) fspecs.binary32 = true; - fspecs.use_grisu = use_grisu(); - int exp = format_float(promote_float(value), precision, fspecs, buffer); - fspecs.precision = precision; - float_writer w(buffer.data(), static_cast(buffer.size()), exp, - fspecs, static_cast('.')); - return base_iterator(out, w(reserve(out, w.size()))); -} - -template -OutputIt write_char(OutputIt out, Char value, - const basic_format_specs& specs) { - using iterator = remove_reference_t; - return write_padded(out, specs, 1, [=](iterator it) { - *it++ = value; - return it; - }); +FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { + prefix |= prefix != 0 ? value << 8 : value; + prefix += (1u + (value > 0xff ? 1 : 0)) << 24; } -template -OutputIt write_ptr(OutputIt out, UIntPtr value, - const basic_format_specs* specs) { - int num_digits = count_digits<4>(value); - auto size = to_unsigned(num_digits) + size_t(2); - using iterator = remove_reference_t; - auto write = [=](iterator it) { - *it++ = static_cast('0'); - *it++ = static_cast('x'); - return format_uint<4, Char>(it, value, num_digits); - }; - return specs ? write_padded(out, *specs, size, write) - : base_iterator(out, write(reserve(out, size))); -} - -template struct is_integral : std::is_integral {}; -template <> struct is_integral : std::true_type {}; -template <> struct is_integral : std::true_type {}; - -template -OutputIt write(OutputIt out, monostate) { - FMT_ASSERT(false, ""); - return out; +// Writes a decimal integer with digit grouping. +template +auto write_int(OutputIt out, UInt value, unsigned prefix, + const format_specs& specs, const digit_grouping& grouping) + -> OutputIt { + static_assert(std::is_same, UInt>::value, ""); + int num_digits = 0; + auto buffer = memory_buffer(); + switch (specs.type) { + default: + FMT_ASSERT(false, ""); + FMT_FALLTHROUGH; + case presentation_type::none: + case presentation_type::dec: + num_digits = count_digits(value); + format_decimal(appender(buffer), value, num_digits); + break; + case presentation_type::hex: + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'X' : 'x') << 8 | '0'); + num_digits = count_digits<4>(value); + format_uint<4, char>(appender(buffer), value, num_digits, specs.upper); + break; + case presentation_type::oct: + num_digits = count_digits<3>(value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && value != 0) + prefix_append(prefix, '0'); + format_uint<3, char>(appender(buffer), value, num_digits); + break; + case presentation_type::bin: + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'B' : 'b') << 8 | '0'); + num_digits = count_digits<1>(value); + format_uint<1, char>(appender(buffer), value, num_digits); + break; + case presentation_type::chr: + return write_char(out, static_cast(value), specs); + } + + unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) + + to_unsigned(grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + return grouping.apply(it, string_view(buffer.data(), buffer.size())); + }); } -template ::value)> -OutputIt write(OutputIt out, string_view value) { - auto it = reserve(out, value.size()); - it = copy_str(value.begin(), value.end(), it); - return base_iterator(out, it); +// Writes a localized value. +FMT_API auto write_loc(appender out, loc_value value, const format_specs& specs, + locale_ref loc) -> bool; +template +inline auto write_loc(OutputIt, loc_value, const format_specs&, locale_ref) + -> bool { + return false; } -template -OutputIt write(OutputIt out, basic_string_view value) { - auto it = reserve(out, value.size()); - it = std::copy(value.begin(), value.end(), it); - return base_iterator(out, it); -} +template struct write_int_arg { + UInt abs_value; + unsigned prefix; +}; -template ::value && - !std::is_same::value && - !std::is_same::value)> -OutputIt write(OutputIt out, T value) { +template +FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) + -> write_int_arg> { + auto prefix = 0u; auto abs_value = static_cast>(value); - bool negative = is_negative(value); - // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. - if (negative) abs_value = ~abs_value + 1; - int num_digits = count_digits(abs_value); - auto it = reserve(out, (negative ? 1 : 0) + static_cast(num_digits)); - if (negative) *it++ = static_cast('-'); - it = format_decimal(it, abs_value, num_digits).end; - return base_iterator(out, it); -} - -template -OutputIt write(OutputIt out, bool value) { - return write(out, string_view(value ? "true" : "false")); -} - -template -OutputIt write(OutputIt out, Char value) { - auto it = reserve(out, 1); - *it++ = value; - return base_iterator(out, it); -} - -template -OutputIt write(OutputIt out, const Char* value) { - if (!value) { - FMT_THROW(format_error("string pointer is null")); + if (is_negative(value)) { + prefix = 0x01000000 | '-'; + abs_value = 0 - abs_value; } else { - auto length = std::char_traits::length(value); - out = write(out, basic_string_view(value, length)); + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + prefix = prefixes[sign]; } - return out; -} - -template -OutputIt write(OutputIt out, const void* value) { - return write_ptr(out, to_uintptr(value), nullptr); -} - -template -auto write(OutputIt out, const T& value) -> typename std::enable_if< - mapped_type_constant>::value == - type::custom_type, - OutputIt>::type { - basic_format_context ctx(out, {}, {}); - return formatter().format(value, ctx); + return {abs_value, prefix}; } -// An argument visitor that formats the argument and writes it via the output -// iterator. It's a class and not a generic lambda for compatibility with C++11. -template struct default_arg_formatter { - using context = basic_format_context; +template struct loc_writer { + basic_appender out; + const format_specs& specs; + std::basic_string sep; + std::string grouping; + std::basic_string decimal_point; - OutputIt out; - basic_format_args args; - locale_ref loc; - - template OutputIt operator()(T value) { - return write(out, value); + template ::value)> + auto operator()(T value) -> bool { + auto arg = make_write_int_arg(value, specs.sign); + write_int(out, static_cast>(arg.abs_value), arg.prefix, + specs, digit_grouping(grouping, sep)); + return true; } - OutputIt operator()(typename basic_format_arg::handle handle) { - basic_format_parse_context parse_ctx({}); - basic_format_context format_ctx(out, args, loc); - handle.format(parse_ctx, format_ctx); - return format_ctx.out(); + template ::value)> + auto operator()(T) -> bool { + return false; } }; -template -class arg_formatter_base { - public: - using iterator = OutputIt; - using char_type = Char; - using format_specs = basic_format_specs; - - private: - iterator out_; - locale_ref locale_; - format_specs* specs_; - - // Attempts to reserve space for n extra characters in the output range. - // Returns a pointer to the reserved range or a reference to out_. - auto reserve(size_t n) -> decltype(detail::reserve(out_, n)) { - return detail::reserve(out_, n); - } - - using reserve_iterator = remove_reference_t(), 0))>; - - template void write_int(T value, const format_specs& spec) { - using uint_type = uint32_or_64_or_128_t; - int_writer w(out_, locale_, value, spec); - handle_int_type_spec(spec.type, w); - out_ = w.out; - } - - void write(char value) { - auto&& it = reserve(1); - *it++ = value; - } - - template ::value)> - void write(Ch value) { - out_ = detail::write(out_, value); - } - - void write(string_view value) { - auto&& it = reserve(value.size()); - it = copy_str(value.begin(), value.end(), it); +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, + const format_specs& specs, locale_ref) + -> OutputIt { + static_assert(std::is_same>::value, ""); + auto abs_value = arg.abs_value; + auto prefix = arg.prefix; + switch (specs.type) { + default: + FMT_ASSERT(false, ""); + FMT_FALLTHROUGH; + case presentation_type::none: + case presentation_type::dec: { + int num_digits = count_digits(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_decimal(it, abs_value, num_digits).end; + }); } - void write(wstring_view value) { - static_assert(std::is_same::value, ""); - auto&& it = reserve(value.size()); - it = std::copy(value.begin(), value.end(), it); + case presentation_type::hex: { + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'X' : 'x') << 8 | '0'); + int num_digits = count_digits<4>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<4, Char>(it, abs_value, num_digits, specs.upper); + }); } - - template - void write(const Ch* s, size_t size, const format_specs& specs) { - auto width = specs.width != 0 - ? count_code_points(basic_string_view(s, size)) - : 0; - out_ = write_padded(out_, specs, size, width, [=](reserve_iterator it) { - return copy_str(s, s + size, it); - }); + case presentation_type::oct: { + int num_digits = count_digits<3>(abs_value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) + prefix_append(prefix, '0'); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<3, Char>(it, abs_value, num_digits); + }); } - - template - void write(basic_string_view s, const format_specs& specs = {}) { - out_ = detail::write(out_, s, specs); + case presentation_type::bin: { + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'B' : 'b') << 8 | '0'); + int num_digits = count_digits<1>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<1, Char>(it, abs_value, num_digits); + }); } - - void write_pointer(const void* p) { - out_ = write_ptr(out_, to_uintptr(p), specs_); + case presentation_type::chr: + return write_char(out, static_cast(abs_value), specs); } +} +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline(OutputIt out, + write_int_arg arg, + const format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, arg, specs, loc); +} +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR FMT_INLINE auto write(basic_appender out, T value, + const format_specs& specs, locale_ref loc) + -> basic_appender { + if (specs.localized && write_loc(out, value, specs, loc)) return out; + return write_int_noinline(out, make_write_int_arg(value, specs.sign), + specs, loc); +} +// An inlined version of write used in format string compilation. +template ::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const format_specs& specs, locale_ref loc) + -> OutputIt { + if (specs.localized && write_loc(out, value, specs, loc)) return out; + return write_int(out, make_write_int_arg(value, specs.sign), specs, + loc); +} - struct char_spec_handler : ErrorHandler { - arg_formatter_base& formatter; - Char value; +// An output iterator that counts the number of objects written to it and +// discards them. +class counting_iterator { + private: + size_t count_; - char_spec_handler(arg_formatter_base& f, Char val) - : formatter(f), value(val) {} + public: + using iterator_category = std::output_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + FMT_UNCHECKED_ITERATOR(counting_iterator); - void on_int() { - // char is only formatted as int if there are specs. - formatter.write_int(static_cast(value), *formatter.specs_); - } - void on_char() { - if (formatter.specs_) - formatter.out_ = write_char(formatter.out_, value, *formatter.specs_); - else - formatter.write(value); - } + struct value_type { + template FMT_CONSTEXPR void operator=(const T&) {} }; - struct cstring_spec_handler : error_handler { - arg_formatter_base& formatter; - const Char* value; - - cstring_spec_handler(arg_formatter_base& f, const Char* val) - : formatter(f), value(val) {} + FMT_CONSTEXPR counting_iterator() : count_(0) {} - void on_string() { formatter.write(value); } - void on_pointer() { formatter.write_pointer(value); } - }; - - protected: - iterator out() { return out_; } - format_specs* specs() { return specs_; } + FMT_CONSTEXPR auto count() const -> size_t { return count_; } - void write(bool value) { - if (specs_) - write(string_view(value ? "true" : "false"), *specs_); - else - out_ = detail::write(out_, value); + FMT_CONSTEXPR auto operator++() -> counting_iterator& { + ++count_; + return *this; } - - void write(const Char* value) { - if (!value) { - FMT_THROW(format_error("string pointer is null")); - } else { - auto length = std::char_traits::length(value); - basic_string_view sv(value, length); - specs_ ? write(sv, *specs_) : write(sv); - } + FMT_CONSTEXPR auto operator++(int) -> counting_iterator { + auto it = *this; + ++*this; + return it; } - public: - arg_formatter_base(OutputIt out, format_specs* s, locale_ref loc) - : out_(out), locale_(loc), specs_(s) {} - - iterator operator()(monostate) { - FMT_ASSERT(false, "invalid argument type"); - return out_; + FMT_CONSTEXPR friend auto operator+(counting_iterator it, difference_type n) + -> counting_iterator { + it.count_ += static_cast(n); + return it; } - template ::value)> - FMT_INLINE iterator operator()(T value) { - if (specs_) - write_int(value, *specs_); - else - out_ = detail::write(out_, value); - return out_; - } + FMT_CONSTEXPR auto operator*() const -> value_type { return {}; } +}; - iterator operator()(Char value) { - handle_char_specs(specs_, - char_spec_handler(*this, static_cast(value))); - return out_; - } +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, + const format_specs& specs) -> OutputIt { + auto data = s.data(); + auto size = s.size(); + if (specs.precision >= 0 && to_unsigned(specs.precision) < size) + size = code_point_index(s, to_unsigned(specs.precision)); + bool is_debug = specs.type == presentation_type::debug; + size_t width = 0; - iterator operator()(bool value) { - if (specs_ && specs_->type) return (*this)(value ? 1 : 0); - write(value != 0); - return out_; - } + if (is_debug) size = write_escaped_string(counting_iterator{}, s).count(); - template ::value)> - iterator operator()(T value) { - auto specs = specs_ ? *specs_ : format_specs(); - if (const_check(is_supported_floating_point(value))) - out_ = detail::write(out_, value, specs, locale_); + if (specs.width != 0) { + if (is_debug) + width = size; else - FMT_ASSERT(false, "unsupported float argument type"); - return out_; - } - - iterator operator()(const Char* value) { - if (!specs_) return write(value), out_; - handle_cstring_type_spec(specs_->type, cstring_spec_handler(*this, value)); - return out_; - } - - iterator operator()(basic_string_view value) { - if (specs_) { - check_string_type_spec(specs_->type, error_handler()); - write(value, *specs_); - } else { - write(value); - } - return out_; + width = compute_width(basic_string_view(data, size)); } + return write_padded(out, specs, size, width, + [=](reserve_iterator it) { + if (is_debug) return write_escaped_string(it, s); + return copy(data, data + size, it); + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, + basic_string_view> s, + const format_specs& specs, locale_ref) -> OutputIt { + return write(out, s, specs); +} +template +FMT_CONSTEXPR auto write(OutputIt out, const Char* s, const format_specs& specs, + locale_ref) -> OutputIt { + if (specs.type == presentation_type::pointer) + return write_ptr(out, bit_cast(s), &specs); + if (!s) report_error("string pointer is null"); + return write(out, basic_string_view(s), specs, {}); +} - iterator operator()(const void* value) { - if (specs_) check_pointer_type_spec(specs_->type, error_handler()); - write_pointer(value); - return out_; +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + auto abs_value = static_cast>(value); + bool negative = is_negative(value); + // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. + if (negative) abs_value = ~abs_value + 1; + int num_digits = count_digits(abs_value); + auto size = (negative ? 1 : 0) + static_cast(num_digits); + if (auto ptr = to_pointer(out, size)) { + if (negative) *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; } -}; - -template FMT_CONSTEXPR bool is_name_start(Char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; + if (negative) *out++ = static_cast('-'); + return format_decimal(out, abs_value, num_digits).end; } -// Parses the range [begin, end) as an unsigned integer. This function assumes -// that the range is non-empty and the first character is a digit. -template -FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end, - ErrorHandler&& eh) { - FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); - unsigned value = 0; - // Convert to unsigned to prevent a warning. - constexpr unsigned max_int = max_value(); - unsigned big = max_int / 10; - do { - // Check for overflow. - if (value > big) { - value = max_int + 1; +// DEPRECATED! +template +FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, + format_specs& specs) -> const Char* { + FMT_ASSERT(begin != end, ""); + auto align = align::none; + auto p = begin + code_point_length(begin); + if (end - p <= 0) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = align::left; + break; + case '>': + align = align::right; + break; + case '^': + align = align::center; break; } - value = value * 10 + unsigned(*begin - '0'); - ++begin; - } while (begin != end && '0' <= *begin && *begin <= '9'); - if (value > max_int) eh.on_error("number is too big"); - return static_cast(value); -} - -template class custom_formatter { - private: - using char_type = typename Context::char_type; - - basic_format_parse_context& parse_ctx_; - Context& ctx_; - - public: - explicit custom_formatter(basic_format_parse_context& parse_ctx, - Context& ctx) - : parse_ctx_(parse_ctx), ctx_(ctx) {} - - bool operator()(typename basic_format_arg::handle h) const { - h.format(parse_ctx_, ctx_); - return true; + if (align != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '}') return begin; + if (c == '{') { + report_error("invalid fill character '{'"); + return begin; + } + specs.fill = basic_string_view(begin, to_unsigned(p - begin)); + begin = p + 1; + } else { + ++begin; + } + break; + } else if (p == begin) { + break; + } + p = begin; } + specs.align = align; + return begin; +} - template bool operator()(T) const { return false; } +// A floating-point presentation format. +enum class float_format : unsigned char { + general, // General: exponent notation or fixed point based on magnitude. + exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. + fixed // Fixed point with the default precision of 6, e.g. 0.0012. }; -template -using is_integer = - bool_constant::value && !std::is_same::value && - !std::is_same::value && - !std::is_same::value>; - -template class width_checker { - public: - explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} - - template ::value)> - FMT_CONSTEXPR unsigned long long operator()(T value) { - if (is_negative(value)) handler_.on_error("negative width"); - return static_cast(value); - } - - template ::value)> - FMT_CONSTEXPR unsigned long long operator()(T) { - handler_.on_error("width is not integer"); - return 0; - } - - private: - ErrorHandler& handler_; +struct float_specs { + int precision; + float_format format : 8; + sign_t sign : 8; + bool locale : 1; + bool binary32 : 1; + bool showpoint : 1; }; -template class precision_checker { - public: - explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} - - template ::value)> - FMT_CONSTEXPR unsigned long long operator()(T value) { - if (is_negative(value)) handler_.on_error("negative precision"); - return static_cast(value); +// DEPRECATED! +FMT_CONSTEXPR inline auto parse_float_type_spec(const format_specs& specs) + -> float_specs { + auto result = float_specs(); + result.showpoint = specs.alt; + result.locale = specs.localized; + switch (specs.type) { + default: + FMT_FALLTHROUGH; + case presentation_type::none: + result.format = float_format::general; + break; + case presentation_type::exp: + result.format = float_format::exp; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::fixed: + result.format = float_format::fixed; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::general: + result.format = float_format::general; + break; } + return result; +} - template ::value)> - FMT_CONSTEXPR unsigned long long operator()(T) { - handler_.on_error("precision is not integer"); - return 0; - } +template +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, + format_specs specs, sign_t sign) + -> OutputIt { + auto str = + isnan ? (specs.upper ? "NAN" : "nan") : (specs.upper ? "INF" : "inf"); + constexpr size_t str_size = 3; + auto size = str_size + (sign ? 1 : 0); + // Replace '0'-padding with space for non-finite values. + const bool is_zero_fill = + specs.fill.size() == 1 && specs.fill.template get() == '0'; + if (is_zero_fill) specs.fill = ' '; + return write_padded(out, specs, size, + [=](reserve_iterator it) { + if (sign) *it++ = detail::sign(sign); + return copy(str, str + str_size, it); + }); +} - private: - ErrorHandler& handler_; +// A decimal floating-point number significand * pow(10, exp). +struct big_decimal_fp { + const char* significand; + int significand_size; + int exponent; }; -// A format specifier handler that sets fields in basic_format_specs. -template class specs_setter { - public: - explicit FMT_CONSTEXPR specs_setter(basic_format_specs& specs) - : specs_(specs) {} - - FMT_CONSTEXPR specs_setter(const specs_setter& other) - : specs_(other.specs_) {} - - FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } - FMT_CONSTEXPR void on_fill(basic_string_view fill) { - specs_.fill = fill; - } - FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; } - FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; } - FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; } - FMT_CONSTEXPR void on_hash() { specs_.alt = true; } +constexpr auto get_significand_size(const big_decimal_fp& f) -> int { + return f.significand_size; +} +template +inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { + return count_digits(f.significand); +} - FMT_CONSTEXPR void on_zero() { - specs_.align = align::numeric; - specs_.fill[0] = Char('0'); - } +template +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { + return copy(significand, significand + significand_size, out); +} +template +inline auto write_significand(OutputIt out, UInt significand, + int significand_size) -> OutputIt { + return format_decimal(out, significand, significand_size).end; +} +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_separator()) { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} - FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } - FMT_CONSTEXPR void on_precision(int precision) { - specs_.precision = precision; +template ::value)> +inline auto write_significand(Char* out, UInt significand, int significand_size, + int integral_size, Char decimal_point) -> Char* { + if (!decimal_point) + return format_decimal(out, significand, significand_size).end; + out += significand_size + 1; + Char* end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) { + out -= 2; + copy2(out, digits2(static_cast(significand % 100))); + significand /= 100; } - FMT_CONSTEXPR void end_precision() {} - - FMT_CONSTEXPR void on_type(Char type) { - specs_.type = static_cast(type); + if (floating_size % 2 != 0) { + *--out = static_cast('0' + significand % 10); + significand /= 10; } + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); + return end; +} - protected: - basic_format_specs& specs_; -}; +template >::value)> +inline auto write_significand(OutputIt out, UInt significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. + Char buffer[digits10() + 2]; + auto end = write_significand(buffer, significand, significand_size, + integral_size, decimal_point); + return detail::copy_noinline(buffer, end, out); +} -template class numeric_specs_checker { - public: - FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, detail::type arg_type) - : error_handler_(eh), arg_type_(arg_type) {} +template +FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + out = detail::copy_noinline(significand, significand + integral_size, + out); + if (!decimal_point) return out; + *out++ = decimal_point; + return detail::copy_noinline(significand + integral_size, + significand + significand_size, out); +} - FMT_CONSTEXPR void require_numeric_argument() { - if (!is_arithmetic_type(arg_type_)) - error_handler_.on_error("format specifier requires numeric argument"); - } +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int integral_size, + Char decimal_point, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(basic_appender(buffer), significand, significand_size, + integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_noinline(buffer.data() + integral_size, + buffer.end(), out); +} - FMT_CONSTEXPR void check_sign() { - require_numeric_argument(); - if (is_integral_type(arg_type_) && arg_type_ != type::int_type && - arg_type_ != type::long_long_type && arg_type_ != type::char_type) { - error_handler_.on_error("format specifier requires signed argument"); +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + auto significand = f.significand; + int significand_size = get_significand_size(f); + const Char zero = static_cast('0'); + auto sign = fspecs.sign; + size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); + using iterator = reserve_iterator; + + Char decimal_point = + fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + + int output_exp = f.exponent + significand_size - 1; + auto use_exp_format = [=]() { + if (fspecs.format == float_format::exp) return true; + if (fspecs.format != float_format::general) return false; + // Use the fixed notation if the exponent is in [exp_lower, exp_upper), + // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. + const int exp_lower = -4, exp_upper = 16; + return output_exp < exp_lower || + output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); + }; + if (use_exp_format()) { + int num_zeros = 0; + if (fspecs.showpoint) { + num_zeros = fspecs.precision - significand_size; + if (num_zeros < 0) num_zeros = 0; + size += to_unsigned(num_zeros); + } else if (significand_size == 1) { + decimal_point = Char(); } + auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; + int exp_digits = 2; + if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; + + size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); + char exp_char = specs.upper ? 'E' : 'e'; + auto write = [=](iterator it) { + if (sign) *it++ = detail::sign(sign); + // Insert a decimal point after the first digit and add an exponent. + it = write_significand(it, significand, significand_size, 1, + decimal_point); + if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); + *it++ = static_cast(exp_char); + return write_exponent(output_exp, it); + }; + return specs.width > 0 + ? write_padded(out, specs, size, write) + : base_iterator(out, write(reserve(out, size))); } - FMT_CONSTEXPR void check_precision() { - if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type) - error_handler_.on_error("precision not allowed for this argument type"); + int exp = f.exponent + significand_size; + if (f.exponent >= 0) { + // 1234e5 -> 123400000[.0+] + size += to_unsigned(f.exponent); + int num_zeros = fspecs.precision - exp; + abort_fuzzing_if(num_zeros > 5000); + if (fspecs.showpoint) { + ++size; + if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0; + if (num_zeros > 0) size += to_unsigned(num_zeros); + } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, + f.exponent, grouping); + if (!fspecs.showpoint) return it; + *it++ = decimal_point; + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } else if (exp > 0) { + // 1234e-2 -> 12.34[0+] + int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; + size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, exp, + decimal_point, grouping); + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); } + // 1234e-6 -> 0.001234 + int num_zeros = -exp; + if (significand_size == 0 && fspecs.precision >= 0 && + fspecs.precision < num_zeros) { + num_zeros = fspecs.precision; + } + bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; + size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + *it++ = zero; + if (!pointy) return it; + *it++ = decimal_point; + it = detail::fill_n(it, num_zeros, zero); + return write_significand(it, significand, significand_size); + }); +} - private: - ErrorHandler& error_handler_; - detail::type arg_type_; -}; - -// A format specifier handler that checks if specifiers are consistent with the -// argument type. -template class specs_checker : public Handler { - private: - numeric_specs_checker checker_; - - // Suppress an MSVC warning about using this in initializer list. - FMT_CONSTEXPR Handler& error_handler() { return *this; } - +template class fallback_digit_grouping { public: - FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type) - : Handler(handler), checker_(error_handler(), arg_type) {} - - FMT_CONSTEXPR specs_checker(const specs_checker& other) - : Handler(other), checker_(error_handler(), other.arg_type_) {} - - FMT_CONSTEXPR void on_align(align_t align) { - if (align == align::numeric) checker_.require_numeric_argument(); - Handler::on_align(align); - } + constexpr fallback_digit_grouping(locale_ref, bool) {} - FMT_CONSTEXPR void on_plus() { - checker_.check_sign(); - Handler::on_plus(); - } + constexpr auto has_separator() const -> bool { return false; } - FMT_CONSTEXPR void on_minus() { - checker_.check_sign(); - Handler::on_minus(); - } + constexpr auto count_separators(int) const -> int { return 0; } - FMT_CONSTEXPR void on_space() { - checker_.check_sign(); - Handler::on_space(); + template + constexpr auto apply(Out out, basic_string_view) const -> Out { + return out; } +}; - FMT_CONSTEXPR void on_hash() { - checker_.require_numeric_argument(); - Handler::on_hash(); +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, float_specs fspecs, + locale_ref loc) -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, f, specs, fspecs, + loc); + } else { + return do_write_float(out, f, specs, fspecs, loc); } +} - FMT_CONSTEXPR void on_zero() { - checker_.require_numeric_argument(); - Handler::on_zero(); - } +template constexpr auto isnan(T value) -> bool { + return value != value; // std::isnan doesn't support __float128. +} - FMT_CONSTEXPR void end_precision() { checker_.check_precision(); } -}; +template +struct has_isfinite : std::false_type {}; -template