Files
openairinterface5g/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
2026-05-28 15:10:32 -04:00

1269 lines
41 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
/*!
* \brief MAC data structures, constant, and function prototype
*/
/*@}*/
#ifndef __LAYER2_NR_MAC_GNB_H__
#define __LAYER2_NR_MAC_GNB_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <complex.h>
#include <pthread.h>
#include "fsn.h"
#include "common/utils/ds/seq_arr.h"
#include "common/utils/nr/nr_common.h"
#include "common/utils/ds/byte_array.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h"
#define NR_SCHED_LOCK(lock) \
do { \
int rc = pthread_mutex_lock(lock); \
AssertFatal(rc == 0, "error while locking scheduler mutex, pthread_mutex_lock() returned %d\n", rc); \
} while (0)
#define NR_SCHED_UNLOCK(lock) \
do { \
int rc = pthread_mutex_unlock(lock); \
AssertFatal(rc == 0, "error while locking scheduler mutex, pthread_mutex_unlock() returned %d\n", rc); \
} while (0)
#define NR_SCHED_ENSURE_LOCKED(lock)\
do {\
int rc = pthread_mutex_trylock(lock); \
AssertFatal(rc == EBUSY, "this function should be called with the scheduler mutex locked, pthread_mutex_trylock() returned %d\n", rc);\
} while (0)
/* Commmon */
#include "radio/COMMON/common_lib.h"
#include "common/platform_constants.h"
#include "common/ran_context.h"
#include "collection/linear_alloc.h"
/* RRC */
#include "NR_BCCH-BCH-Message.h"
#include "NR_CellGroupConfig.h"
#include "NR_BCCH-DL-SCH-Message.h"
#include "nr_radio_config.h"
/* PHY */
#include "time_meas.h"
/* Interface */
#include "nfapi_nr_interface_scf.h"
#include "nfapi_nr_interface.h"
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
#include "mac_rrc_ul.h"
/* MAC */
#include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
#include "LAYER2/NR_MAC_gNB/mac_config.h"
#include "NR_TAG.h"
/* Defs */
#define MAX_NUM_BWP 5
#define MAX_NUM_CORESET 12
/*!\brief Maximum number of random access process */
#define NR_NB_RA_PROC_MAX 4
#define MAX_NUM_OF_SSB 64
#define MAX_NUM_NR_PRACH_PREAMBLES 64
uint8_t nr_get_rv(int rel_round);
/*! \brief NR_list_t is a "list" (of users, HARQ processes, slices, ...).
* Especially useful in the scheduler and to keep "classes" of users. */
typedef struct {
int head;
int *next;
int tail;
int len;
} NR_list_t;
typedef enum {
nrRA_gNB_IDLE,
nrRA_Msg2,
nrRA_WAIT_MsgA_PUSCH,
nrRA_WAIT_Msg3,
nrRA_Msg3_retransmission,
nrRA_Msg4,
nrRA_MsgB,
nrRA_WAIT_Msg4_MsgB_ACK,
} RA_gNB_state_t;
static const char *const nrra_text[] =
{"IDLE", "Msg2", "WAIT_MsgA_PUSCH", "WAIT_Msg3", "Msg3_retransmission", "Msg4", "MsgB", "WAIT_Msg4_MsgB_ACK"};
typedef struct {
int idx;
bool new_beam;
} NR_beam_alloc_t;
typedef struct nr_pdsch_AntennaPorts_t {
int N1;
int N2;
int XP;
} nr_pdsch_AntennaPorts_t;
typedef struct nr_mac_timers {
int sr_ProhibitTimer;
int sr_TransMax;
int sr_ProhibitTimer_v1700;
int t300;
int t301;
int t310;
int n310;
int t311;
int n311;
int t319;
} nr_mac_timers_t;
typedef struct nr_redcap_config {
int8_t cellBarredRedCap1Rx_r17;
int8_t cellBarredRedCap2Rx_r17;
uint8_t intraFreqReselectionRedCap_r17;
} nr_redcap_config_t;
typedef struct {
int dl_FreqDensity0_0;
int dl_FreqDensity1_0;
int dl_TimeDensity0_0;
int dl_TimeDensity1_0;
int dl_TimeDensity2_0;
int dl_EpreRatio_0;
int dl_ReOffset_0;
int ul_FreqDensity0_0;
int ul_FreqDensity1_0;
int ul_TimeDensity0_0;
int ul_TimeDensity1_0;
int ul_TimeDensity2_0;
int ul_ReOffset_0;
int ul_MaxPorts_0;
int ul_Power_0;
} nr_ptrs_config_t;
typedef struct {
int id;
int scs;
int location_and_bw;
} nr_bwp_config_t;
typedef enum {
SSB_RSRP,
CRI_RSRP,
SSB_SINR,
} nr_config_report_type_t;
typedef struct nr_beam_table {
int num_weights_per_beam;
int num_beams;
uint16_t *beam_ids;
double complex **beam_weights;
} nr_beam_table_t;
typedef struct nr_power_config {
/// target SNR
int target_snrx10;
/// RSSI threshold for power control. Limits power control commands when RSSI reaches threshold.
int rssi_threshold;
/// Failure threshold (compared to consecutive PUSCH DTX)
int failure_thres;
} nr_power_config_t;
typedef struct nr_mac_config_s {
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts;
int pusch_AntennaPorts;
int minRXTXTIME;
int do_CSIRS;
int do_SRS;
int do_TCI;
int max_num_rsrp;
bool force_256qam_off;
bool force_UL256qam_off;
bool use_deltaMCS;
int maxMIMO_layers;
bool disable_harq;
nr_power_config_t pusch;
/// SNR threshold needed to put or not a PRB in the black list
int ul_prbblack_SNR_threshold;
nr_power_config_t pucch;
nr_mac_timers_t timer_config;
int num_dlharq;
int num_ulharq;
// BWP information
int num_additional_bwps;
int first_active_bwp;
nr_bwp_config_t bwp_config[4];
/// beamforming weight matrix size
int nb_bfw[2];
int32_t *bw_list;
int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
nr_redcap_config_t *redcap;
nr_ptrs_config_t *ptrs;
nr_config_report_type_t report_type;
nr_beam_table_t bt;
} nr_mac_config_t;
typedef struct NR_preamble_ue {
uint8_t num_preambles;
uint8_t preamble_list[MAX_NUM_NR_PRACH_PREAMBLES];
} NR_preamble_ue_t;
typedef struct NR_sched_pdcch {
uint16_t BWPSize;
uint16_t BWPStart;
uint8_t CyclicPrefix;
uint8_t SubcarrierSpacing;
uint8_t StartSymbolIndex;
uint8_t CceRegMappingType;
uint8_t RegBundleSize;
uint8_t InterleaverSize;
uint16_t ShiftIndex;
uint8_t DurationSymbols;
uint16_t n_rb;
uint16_t rb_start;
} NR_sched_pdcch_t;
/*! \brief gNB template for the Random access information */
typedef struct {
/// Flag to indicate this process is active
RA_gNB_state_t ra_state;
/// CORESET0 configured flag
int coreset0_configured;
/// Frame where preamble was received
int preamble_frame;
/// Slot where preamble was received
uint8_t preamble_slot;
/// Received preamble_index
uint8_t preamble_index;
/// Timing offset indicated by PHY
int16_t timing_offset;
/// Subframe where Msg2 is to be sent
uint8_t Msg2_slot;
/// Frame where Msg2 is to be sent
frame_t Msg2_frame;
/// Subframe where Msg3 is to be sent
slot_t Msg3_slot;
/// Frame where Msg3 is to be sent
frame_t Msg3_frame;
/// Msg3 time domain allocation index
int Msg3_tda_id;
/// Msg3 beam matrix index
NR_beam_alloc_t Msg3_beam;
/// harq_pid used for Msg4 transmission
uint8_t harq_pid;
/// RA RNTI allocated from received PRACH
uint16_t RA_rnti;
/// MsgB RNTI allocated from received MsgA
uint16_t MsgB_rnti;
/// Received UE Contention Resolution Identifier
uint8_t cont_res_id[6];
/// Msg3 first RB
int msg3_first_rb;
/// Msg3 number of RB
int msg3_nb_rb;
/// Msg3 BWP start
int msg3_bwp_start;
/// Msg3 TPC command
uint8_t msg3_TPC;
/// Round of Msg3 HARQ
uint8_t msg3_round;
int msg3_startsymb;
int msg3_nbSymb;
/// MAC PDU length for Msg4
int mac_pdu_length;
/// Preambles for contention-free access
NR_preamble_ue_t preambles;
int contention_resolution_timer;
nr_ra_type_t ra_type;
/// CFRA flag
bool cfra;
} NR_RA_t;
/*! \brief gNB common channels */
typedef struct {
frame_type_t frame_type;
NR_BCCH_BCH_Message_t *mib;
NR_BCCH_DL_SCH_Message_t *sib1;
seq_arr_t *du_SIBs;
NR_ServingCellConfigCommon_t *ServingCellConfigCommon;
/// Outgoing MIB PDU for PHY
uint8_t MIB_pdu[3];
/// Outgoing BCCH pdu for PHY
uint8_t sib1_bcch_pdu[NR_MAX_SIB_LENGTH / 8];
int sib1_bcch_length;
/// used for otherSIB data
uint8_t other_sib_bcch_pdu[2][NR_MAX_SIB_LENGTH / 8];
int other_sib_bcch_length[2];
/// VRB map for common channels
uint16_t vrb_map[MAX_NUM_BEAM_PERIODS][275];
/// VRB map for common channels and PUSCH, dynamically allocated because
/// length depends on number of slots and RBs
uint16_t *vrb_map_UL[MAX_NUM_BEAM_PERIODS];
///Number of active SSBs
int num_active_ssb;
//Total available prach occasions per configuration period
int total_prach_occasions_per_config_period;
//Total available prach occasions
int total_prach_occasions;
//Max Association period
int association_period;
//SSB index
uint8_t ssb_index[MAX_NUM_OF_SSB];
//CB preambles for each SSB
int cb_preambles_per_ssb;
/// Max prach length in slots
int prach_len;
nr_prach_info_t prach_info;
} NR_COMMON_channels_t;
// SP ZP CSI-RS Resource Set Activation/Deactivation MAC CE
typedef struct sp_zp_csirs {
bool is_scheduled; //ZP CSI-RS ACT/Deact MAC CE is scheduled
bool act_deact; //Activation/Deactivation indication
uint8_t serv_cell_id; //Identity of Serving cell for which MAC CE applies
uint8_t bwpid; //Downlink BWP id
uint8_t rsc_id; //SP ZP CSI-RS resource set
} sp_zp_csirs_t;
//SP CSI-RS / CSI-IM Resource Set Activation/Deactivation MAC CE
#define MAX_CSI_RESOURCE_SET 64
typedef struct csi_rs_im {
bool is_scheduled;
bool act_deact;
uint8_t serv_cellid;
uint8_t bwp_id;
bool im;
uint8_t csi_im_rsc_id;
uint8_t nzp_csi_rsc_id;
uint8_t nb_tci_resource_set_id;
uint8_t tci_state_id [ MAX_CSI_RESOURCE_SET ];
} csi_rs_im_t;
typedef struct tciStateInd {
bool is_scheduled;
uint32_t coresetId;
uint32_t tciStateId;
} tciStateInd_t;
typedef struct pucchSpatialRelation {
bool is_scheduled;
uint8_t servingCellId;
uint8_t bwpId;
uint8_t pucchResourceId;
bool s0tos7_actDeact[8];
} pucchSpatialRelation_t;
typedef struct SPCSIReportingpucch {
bool is_scheduled;
uint8_t servingCellId;
uint8_t bwpId;
bool s0tos3_actDeact[4];
} SPCSIReportingpucch_t;
#define MAX_APERIODIC_TRIGGER_STATES 128 //38.331
typedef struct aperiodicCSI_triggerStateSelection {
bool is_scheduled;
uint8_t servingCellId;
uint8_t bwpId;
uint8_t highestTriggerStateSelected;
bool triggerStateSelection[MAX_APERIODIC_TRIGGER_STATES];
} aperiodicCSI_triggerStateSelection_t;
#define MAX_TCI_STATES 128 //38.331
typedef struct pdschTciStatesActDeact {
bool is_scheduled;
uint8_t servingCellId;
uint8_t bwpId;
uint8_t highestTciStateActivated;
bool tciStateActDeact[MAX_TCI_STATES];
uint8_t codepoint[8];
} pdschTciStatesActDeact_t;
typedef struct UE_info {
sp_zp_csirs_t sp_zp_csi_rs;
csi_rs_im_t csi_im;
tciStateInd_t tci_state_ind;
pucchSpatialRelation_t pucch_spatial_relation;
SPCSIReportingpucch_t SP_CSI_reporting_pucch;
aperiodicCSI_triggerStateSelection_t aperi_CSI_trigger;
pdschTciStatesActDeact_t pdsch_TCI_States_ActDeact;
} NR_UE_mac_ce_ctrl_t;
typedef struct NR_sched_pucch {
bool active;
int frame;
int ul_slot;
bool sr_flag;
int csi_bits;
bool simultaneous_harqcsi;
uint8_t dai_c;
uint8_t timing_indicator;
uint8_t resource_indicator;
int r_pucch;
int prb_start;
int second_hop_prb;
int nr_of_symb;
int start_symb;
} NR_sched_pucch_t;
typedef struct NR_pusch_dmrs {
uint8_t N_PRB_DMRS;
uint8_t num_dmrs_symb;
uint16_t ul_dmrs_symb_pos;
uint8_t num_dmrs_cdm_grps_no_data;
nfapi_nr_dmrs_type_e dmrs_config_type;
int dmrs_scrambling_id;
int pusch_identity;
int scid;
int low_papr_sequence_number;
NR_PTRS_UplinkConfig_t *ptrsConfig;
} NR_pusch_dmrs_t;
typedef struct NR_sched_pusch {
int frame;
int slot;
/// RB allocation within active uBWP
uint16_t rbSize;
uint16_t rbStart;
/// MCS
uint8_t mcs;
/// TBS-related info
uint16_t R;
uint8_t Qm;
uint32_t tb_size;
/// UL HARQ PID to use for this UE, or -1 for "any new"
int8_t ul_harq_pid;
uint8_t nrOfLayers;
int tpmi;
// time_domain_allocation is the index of a list of tda
int time_domain_allocation;
NR_tda_info_t tda_info;
NR_pusch_dmrs_t dmrs_info;
bwp_info_t bwp_info;
int phr_txpower_calc;
/// TPC command for this PUSCH
int tpc_pusch;
} NR_sched_pusch_t;
typedef struct NR_pdsch_dmrs {
uint8_t dmrs_ports_id;
uint8_t N_PRB_DMRS;
uint8_t N_DMRS_SLOT;
uint16_t dl_dmrs_symb_pos;
uint8_t numDmrsCdmGrpsNoData;
uint32_t scrambling_id;
int n_scid;
nfapi_nr_dmrs_type_e dmrsConfigType;
NR_PTRS_DownlinkConfig_t *phaseTrackingRS;
} NR_pdsch_dmrs_t;
struct NR_UE_info;
struct gNB_MAC_INST_s;
typedef void (*feedback_action_t)(struct gNB_MAC_INST_s *mac, struct NR_UE_info *ue);
typedef struct NR_sched_pdsch {
/// RB allocation within active BWP
uint16_t rbSize;
uint16_t rbStart;
/// MCS-related infos
uint8_t mcs;
/// TBS-related info
uint16_t R;
uint8_t Qm;
uint32_t tb_size;
/// DL HARQ PID to use for this UE, or -1 for "any new"
int8_t dl_harq_pid;
// pucch format allocation
int16_t pucch_allocation;
uint16_t pm_index;
uint8_t nrOfLayers;
bwp_info_t bwp_info;
NR_pdsch_dmrs_t dmrs_parms;
// time_domain_allocation is the index of a list of tda
int time_domain_allocation;
NR_tda_info_t tda_info;
feedback_action_t action;
} NR_sched_pdsch_t;
typedef struct NR_UE_harq {
bool is_waiting;
uint8_t ndi;
uint8_t round;
uint16_t feedback_frame;
uint16_t feedback_slot;
/* Transport block to be sent using this HARQ process */
byte_array_t transportBlock;
uint32_t tb_size; // size of currently stored TB
bool start_tci_timer;
/// sched_pdsch keeps information on MCS etc used for the initial transmission
NR_sched_pdsch_t sched_pdsch;
} NR_UE_harq_t;
//! fixme : need to enhace for the multiple TB CQI report
typedef struct NR_bler_stats {
frame_t last_frame;
float bler;
uint8_t mcs;
uint64_t rounds[8];
int last_num_sched; // scheduling count at last BLER update (for activity guard)
} NR_bler_stats_t;
//
/*! As per spec 38.214 section 5.2.1.4.2
* - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'disabled', the UE shall report in
a single report nrofReportedRS (higher layer configured) different CRI or SSBRI for each report setting.
* - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'enabled', the UE shall report in a
single reporting instance two different CRI or SSBRI for each report setting, where CSI-RS and/or SSB
resources can be received simultaneously by the UE either with a single spatial domain receive filter, or with
multiple simultaneous spatial domain receive filter
*/
#define MAX_NR_OF_REPORTED_RS 4
struct CRI_RI_LI_PMI_CQI {
uint8_t cri;
uint8_t ri;
uint8_t li;
uint8_t pmi_x1;
uint8_t pmi_x2;
uint8_t wb_cqi_1tb;
uint8_t wb_cqi_2tb;
uint8_t cqi_table;
uint8_t csi_report_id;
bool print_report;
};
typedef struct {
uint8_t resource_id;
int RSRP;
int SINRx10;
} RSRP_report_t;
typedef struct {
int nb;
RSRP_report_t r[MAX_NR_OF_REPORTED_RS];
} RSRP_report_list_t;
typedef struct CSI_Report {
struct CRI_RI_LI_PMI_CQI cri_ri_li_pmi_cqi_report;
RSRP_report_list_t ssb_rsrp_report;
RSRP_report_list_t csirs_rsrp_report;
} CSI_report_t;
typedef enum {
INACTIVE = 0,
ACTIVE_NOT_SCHED,
ACTIVE_SCHED
} NR_UL_harq_states_t;
typedef struct NR_UE_ul_harq {
bool is_waiting;
uint8_t ndi;
uint8_t round;
uint16_t feedback_slot;
/// sched_pusch keeps information on MCS etc used for the initial transmission
NR_sched_pusch_t sched_pusch;
} NR_UE_ul_harq_t;
typedef struct NR_QoS_config_s {
int fiveQI;
int priority;
} NR_QoS_config_t;
typedef struct nr_lc_config {
uint8_t lcid;
/// flag if corresponding RB is suspended
bool suspended;
/// priority as specified in 38.321
int priority;
/// associated NSSAI for DRB
nssai_t nssai;
/// QoS config for DRB
NR_QoS_config_t qos_config[NR_MAX_NUM_QFI];
} nr_lc_config_t;
typedef struct nr_power_control {
float avg_snr; /// average SNR (in dB)
int target_snrx10; /// UE-specific target SNR x10
float avg_rssi; /// average RSSI
int rssi_threshold; /// UE-specific RSSI threshld in 0.1dBm/dBFS, range -1280 to 0
float tpc_in_flight; /// TPCs applied by UE but not yet in average SNR
} nr_power_control_t;
/*! \brief scheduling control information set through an API */
typedef struct {
/// CCE index and aggregation, should be coherent with cce_list
NR_SearchSpace_t *search_space;
NR_ControlResourceSet_t *coreset;
NR_sched_pdcch_t sched_pdcch;
/// CCE index and Aggr. Level are shared for PUSCH/PDSCH allocation decisions
/// corresponding to the sched_pusch/sched_pdsch structures below
int cce_index;
int aggregation_level;
uint32_t dl_cce_fail, ul_cce_fail;
/// Array of PUCCH scheduling information
/// Its size depends on TDD configuration and max feedback time
/// There will be a structure for each UL slot in the active period determined by the size
NR_sched_pucch_t *sched_pucch;
int sched_pucch_size;
/// uplink bytes that are currently scheduled
int sched_ul_bytes;
/// estimation of the UL buffer size
int estimated_ul_buffer;
/// PHR info: power headroom level (dB)
int ph;
/// PHR info: nominal UE transmit power levels (dBm)
int pcmax;
/// UE-estimated maximum MCS (from CSI-RS)
uint8_t dl_max_mcs;
/// For UL synchronization: store last UL scheduling grant
frame_t last_ul_frame;
slot_t last_ul_slot;
/// total amount of data awaiting for this UE
uint32_t num_total_bytes;
/// per-LC status data
mac_rlc_status_resp_t rlc_status[NR_MAX_NUM_LCID];
/// Estimation of HARQ from BLER
NR_bler_stats_t dl_bler_stats;
NR_bler_stats_t ul_bler_stats;
uint16_t ta_frame;
int16_t ta_update;
bool ta_apply;
int pusch_consecutive_dtx_cnt;
int pucch_consecutive_dtx_cnt;
bool ul_failure;
int ul_failure_timer;
int release_timer;
CSI_report_t CSI_report;
bool SR;
/// information about every HARQ process
NR_UE_harq_t harq_processes[NR_MAX_HARQ_PROCESSES];
/// HARQ processes that are free
NR_list_t available_dl_harq;
/// HARQ processes that await feedback
NR_list_t feedback_dl_harq;
/// HARQ processes that await retransmission
NR_list_t retrans_dl_harq;
/// information about every UL HARQ process
NR_UE_ul_harq_t ul_harq_processes[NR_MAX_HARQ_PROCESSES];
/// UL HARQ processes that are free
NR_list_t available_ul_harq;
/// UL HARQ processes that await feedback
NR_list_t feedback_ul_harq;
/// UL HARQ processes that await retransmission
NR_list_t retrans_ul_harq;
NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl; // MAC CE related information
/// Timer for RRC processing procedures and transmission activity
NR_timer_t transm_interrupt;
NR_timer_t tci_beam_switch;
/// Timer for timeout before UE is set to UL failure (e.g.,
/// "TransmissionActionIndicator" handling
NR_timer_t transm_timeout;
/// sri, ul_ri and tpmi based on SRS
nr_srs_feedback_t srs_feedback;
/// per-LC configuration
seq_arr_t lc_config;
// pdcch closed loop adjust for PDCCH aggregation level, range <0, 1>
// 0 - good channel, 1 - bad channel
float pdcch_cl_adjust;
nr_power_control_t pusch_pc;
nr_power_control_t pucch_pc;
} NR_UE_sched_ctrl_t;
typedef struct NR_mac_dir_stats {
uint64_t lc_bytes[64];
uint64_t rounds[8];
uint64_t errors;
uint64_t total_bytes;
uint32_t current_bytes;
uint64_t total_sdu_bytes;
uint32_t total_rbs;
uint32_t total_rbs_retx;
uint32_t num_mac_sdu;
uint32_t current_rbs;
uint64_t prev_sdu_bytes;
frame_t last_goodput_frame;
} NR_mac_dir_stats_t;
typedef struct NR_mac_stats {
NR_mac_dir_stats_t dl;
NR_mac_dir_stats_t ul;
uint32_t ulsch_DTX;
uint64_t ulsch_total_bytes_scheduled;
uint32_t pucch0_DTX;
int cumul_rsrp;
uint8_t num_rsrp_meas;
int cumul_sinrx10;
uint8_t num_sinr_meas;
char srs_stats[50]; // Statistics may differ depending on SRS usage
int deltaMCS;
int NPRB;
} NR_mac_stats_t;
typedef struct NR_bler_options {
double upper;
double lower;
uint8_t min_mcs;
uint8_t max_mcs;
uint8_t harq_round_max;
} NR_bler_options_t;
typedef struct nr_mac_rrc_ul_if_s {
f1_reset_du_initiated_func_t f1_reset;
f1_reset_acknowledge_cu_initiated_func_t f1_reset_acknowledge;
f1_setup_request_func_t f1_setup_request;
gnb_du_configuration_update_t gnb_du_configuration_update;
ue_context_setup_response_func_t ue_context_setup_response;
ue_context_modification_response_func_t ue_context_modification_response;
ue_context_modification_required_func_t ue_context_modification_required;
ue_context_release_request_func_t ue_context_release_request;
ue_context_release_complete_func_t ue_context_release_complete;
initial_ul_rrc_message_transfer_func_t initial_ul_rrc_message_transfer;
} nr_mac_rrc_ul_if_t;
typedef struct measgap_config {
bool enable;
int mgrp_ms;
long mgrp;
long gapOffset;
long mgta;
int n_slots_mgta;
int n_slots_advance;
float mgl_ms;
long mgl;
int mgl_slots;
} measgap_config_t;
/*! \brief UE list used by gNB to order UEs/CC for scheduling*/
typedef struct NR_UE_info {
rnti_t rnti;
uid_t uid; // unique ID of this UE
/// scheduling control info
nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG];
NR_UE_sched_ctrl_t UE_sched_ctrl;
NR_UE_DL_BWP_t current_DL_BWP;
NR_UE_UL_BWP_t current_UL_BWP;
NR_UE_ServingCell_Info_t sc_info;
NR_mac_stats_t mac_stats;
/// currently active CellGroupConfig
NR_CellGroupConfig_t *CellGroup;
/// in case of reconfiguration, new CellConfig to apply
NR_CellGroupConfig_t *reconfigCellGroup;
NR_UE_NR_Capability_t *capability;
measgap_config_t measgap_config;
// UE selected beam index
uint16_t UE_beam_index;
/// Per-SSB L1-RSRP table, indexed by SSB index (resource_id from CSI report).
/// INT16_MIN means no measurement received yet for that beam.
int16_t beam_rsrp[MAX_NUM_OF_SSB];
/// Per-SSB L1-SINR×10 table, same indexing. INT16_MIN means no data.
int16_t beam_sinr[MAX_NUM_OF_SSB];
float ul_thr_ue;
float dl_thr_ue;
float ul_thr_ue_display; ///< slow EWMA for stable display (alpha=0.001)
float dl_thr_ue_display; ///< slow EWMA for stable display (alpha=0.001)
long pdsch_HARQ_ACK_Codebook;
bool is_redcap;
bool reestablish_rlc;
NR_RA_t *ra;
// 3GPP mandates that BWPs are enumerated consecutively, but we only send one (dedicated)
// BWP to the UE (and modify that BWP on reconfiguration); consequently, the BWP ID for a
// dedicated BWP is always 1 from the UE's point of view, even if the gNB has multiple BWPs.
// The below ID is the "true" (non-consecutive) BWP ID from the gNB's point of view
NR_BWP_Id_t local_bwp_id;
} NR_UE_info_t;
typedef struct {
/// scheduling control info
// last element always NULL
NR_UE_info_t *connected_ue_list[MAX_MOBILES_PER_GNB + 1];
NR_UE_info_t *access_ue_list[NR_NB_RA_PROC_MAX + 1];
// bitmap of CSI-RS already scheduled in current slot
int sched_csirs;
uid_allocator_t uid_allocator;
} NR_UEs_t;
typedef enum {
NO_BEAM_MODE,
PRECONFIGURED_BEAM_IDX,
LOPHY_BEAM_IDX,
} nr_beam_mode_t;
typedef struct {
/// list of allocated beams per period
int16_t **beam_allocation;
int beam_duration; // in slots
int beams_per_period;
int beam_allocation_size;
nr_beam_mode_t beam_mode;
} NR_beam_info_t;
#define UE_iterator(BaSe, VaR) for (NR_UE_info_t **VaR##pptr = BaSe, *VaR = *VaR##pptr; VaR; VaR = *(++VaR##pptr))
#define FOR_EACH_CANDIDATE(VaR, ArR, N) for (__typeof__(*(ArR)) *VaR = (ArR); VaR < (ArR) + (N); VaR++)
typedef struct {
/// current frame
frame_t frame;
/// current slot
slot_t slot;
/// FAPI DL req in which allocations are made
nfapi_nr_dl_tti_request_body_t *dl_req;
/// TX_data request holds the actual data
nfapi_nr_tx_data_request_t *TX_req;
} post_process_pdsch_t;
typedef struct {
/// current frame for DCI
frame_t frame;
/// current slot for DCI
slot_t slot;
/// FAPI UL_DCI.request in which allocations are to be made
nfapi_nr_ul_dci_request_t *ul_dci_req;
/// group PDCCH PDU per CORESET
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_coreset[MAX_NUM_CORESET];
} post_process_pusch_t;
/* forward declarations for scheduling types */
struct gNB_MAC_INST_s;
typedef struct nr_dl_candidate nr_dl_candidate_t;
/// Scheduling context passed to the RB allocation policy.
/// Contains per-beam VRB maps so the policy can handle beam partitioning
/// internally (e.g. for MU-MIMO cross-beam scheduling).
typedef struct nr_dl_sched_params nr_dl_sched_params_t;
struct nr_dl_sched_params {
struct gNB_MAC_INST_s *mac; ///< MAC instance (for CCE/PUCCH validation)
int CC_id;
frame_t frame;
slot_t slot;
int num_beams; ///< number of beams
int max_num_ue; ///< max UEs to schedule
uint16_t *vrb_map[MAX_NUM_BEAM_PERIODS]; ///< per-beam VRB maps [275], mutable
int n_rb_avail[MAX_NUM_BEAM_PERIODS]; ///< available RBs per beam
int min_mcs; ///< minimum MCS from BLER config
float bler_lower; ///< BLER lower threshold (increase MCS if below)
float bler_upper; ///< BLER upper threshold (decrease MCS if above)
};
/// Per-UE scheduling candidate — read-only inputs for the policy function.
struct nr_dl_candidate {
/* ── UE identity / scheduling state (set by collect, never modified after) ── */
NR_UE_info_t *UE;
uint16_t rnti; ///< UE RNTI (convenience, avoids UE pointer dereference)
bool is_retx; ///< true = HARQ retransmission pending
int8_t retx_harq_pid; ///< HARQ PID for retx, -1 if none
int retx_rbSize; ///< RBs needed for retx, 0 for new tx
uint32_t pending_bytes; ///< total bytes waiting in RLC buffers
uint32_t pending_bytes_per_lcid[NR_MAX_NUM_LCID]; ///< per-LCID bytes waiting in RLC buffers
uint64_t hol_delay_ms[NR_MAX_NUM_LCID]; ///< per-LCID head-of-line delay in milliseconds (age of oldest SDU)
float avg_throughput; ///< EWMA goodput in bps (dl_thr_ue)
float bler; ///< current BLER estimate
int current_mcs; ///< current MCS state (retx: from HARQ, new tx: from BLER tracker)
int max_mcs; ///< max allowed MCS (config + UE capability)
int last_num_sched; ///< scheduled occasions in last BLER window
bool bler_updated; ///< true if BLER was refreshed this frame
int mcs_table; ///< MCS table index (from BWP config)
int bwp_start; ///< UE's BWP start
int bwp_size; ///< UE's BWP size
uint64_t fiveQI; ///< 5QI from first DRB's QoS config (0 if none)
int priority; ///< LC priority from first DRB (lower = higher priority, 0 if none)
nssai_t nssai; ///< slice/service type/differentiator from first DRB
bool skipped; ///< true if dropped by TDA/beam select (skip in downstream stages)
bool scheduled; ///< true if accepted by the RB-allocation policy
/* ── UE CSI observations (set by collect, read-only after) ─────────────── */
uint16_t cqi; ///< UE-reported wideband CQI
uint8_t csi_ri; ///< UE-reported rank indicator (0 = rank-1); forced to 0 for DCI 1_0
int csi_pm_index; ///< PM index derived from UE-reported PMI + antenna config
const int16_t *beam_rsrp; ///< per-SSB L1-RSRP; points into NR_UE_info_t::beam_rsrp. INT16_MIN = no data
const int16_t *beam_sinr; ///< per-SSB L1-SINR×10; same indexing. INT16_MIN = no data
/* ── gNB decisions (written by the named pipeline stage) ───────────────── */
/* Use NR_sched_pdsch_t for fields shared with HARQ/dispatch (mcs, rbStart,
* rbSize, nrOfLayers, pm_index, tda, tda_info, pucch_allocation).*/
NR_sched_pdsch_t sched_pdsch;
uint16_t alloc_slbitmap; ///< symbol bitmap derived from sched_pdsch.tda_info
/* dl_beam_select: beam selection */
int alloc_beam_dir; ///< beam direction index (initialised from UE->UE_beam_index; may be overridden)
int alloc_beam_idx; ///< hardware beam structure index, set by beam_allocation_procedure
bool alloc_new_beam; ///< true if beam alloc claimed a fresh slot (release via reset_beam_status if unscheduled)
/* commit_alloc: CCE/PUCCH validation */
int alloc_cce_index; ///< CCE index for PDCCH
int alloc_aggregation_level; ///< PDCCH aggregation level
NR_sched_pdcch_t alloc_sched_pdcch; ///< PDCCH scheduling info
};
/* forward declaration to use in nr_pp_impl_dl */
struct gNB_MAC_INST_s;
typedef struct gNB_MAC_INST_s gNB_MAC_INST;
typedef void (*nr_pp_impl_dl)(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch);
typedef void (*nr_pp_impl_ul)(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch);
/// RI/PMI selection: sets nrOfLayers and pm_index per candidate from CSI feedback.
/// For retransmissions, nrOfLayers must match the original transmission.
/// Custom implementations may use SRS reciprocity to override the UE's reported RI/PMI.
typedef void (*nr_dl_ri_pmi_select_fn)(const gNB_MAC_INST *mac, nr_dl_candidate_t *candidates, int n_candidates);
/// MCS adaptation: sets sched_pdsch.mcs from BLER state for every candidate.
/// Called for all candidates (including those that won't get scheduled) so
/// BLER-based MCS ramps even for UEs that fail CCE. Also persists the
/// decision to dl_bler_stats.mcs for continuity across slots.
typedef void (*nr_dl_mcs_select_fn)(const gNB_MAC_INST *mac, nr_dl_candidate_t *candidates, int n_candidates);
/// Beam allocation: assigns beam structure index to each candidate.
/// beam_index_list maps SSB id -> beam index (same as mac->beam_index_list);
/// custom implementations can use it with cand->beam_rsrp[] to pick the best beam.
typedef int (*nr_dl_beam_select_fn)(NR_beam_info_t *beam_info,
const int16_t *beam_index_list,
nr_dl_candidate_t *candidates,
int n_candidates,
frame_t frame,
slot_t slot,
int slots_per_frame);
/// TDA selection: assigns tda/tda_info/slbitmap per candidate.
/// Returns the number of candidates with a valid TDA (compacts invalids out).
typedef int (
*nr_dl_tda_select_fn)(const gNB_MAC_INST *mac, nr_dl_candidate_t *candidates, int n_candidates, frame_t frame, slot_t slot);
/// Scheduling policy: decides PRB + MCS for candidates across all beams.
/// The beam loop is inside the policy so it can do cross-beam scheduling (e.g. MU-MIMO).
/// Writes sched_pdsch.rbStart/rbSize/mcs and cce/pucch fields on scheduled candidates.
/// Sets candidate->scheduled = true for each accepted UE; returns the count.
typedef int (*nr_dl_rb_alloc_fn)(const nr_dl_sched_params_t *params, nr_dl_candidate_t *candidates, int n_candidates);
/// Per-LCID byte allocation: decides how many bytes each LCID gets within
/// the available TBS for an initial transmission. Called during MAC PDU
/// generation. Writes lcid_alloc[lcid] = max data bytes for that LCID.
/// The execution loop caps actual RLC requests to these budgets.
typedef void (*nr_dl_lcid_alloc_fn)(const gNB_MAC_INST *mac,
const nr_dl_candidate_t *candidate,
int tbs_available,
int lcid_alloc[NR_MAX_NUM_LCID]);
/* UL scheduling refactored data structures */
struct nr_ul_sched_params;
typedef struct nr_ul_candidate nr_ul_candidate_t;
typedef struct nr_ul_sched_params {
struct gNB_MAC_INST_s *mac;
int CC_id;
frame_t dci_frame; ///< DCI slot frame (current DL slot)
slot_t dci_slot; ///< DCI slot (current DL slot)
frame_t frame; ///< scheduled PUSCH frame (future UL slot)
slot_t slot; ///< scheduled PUSCH slot (future UL slot)
int num_beams;
int max_num_ue;
uint16_t *vrb_map_UL[MAX_NUM_BEAM_PERIODS]; ///< per-beam VRB maps, mutable
int n_rb_avail[MAX_NUM_BEAM_PERIODS]; ///< available RBs per beam
int min_rb;
int min_mcs;
float bler_lower;
float bler_upper;
const NR_ServingCellConfigCommon_t *scc;
const NR_bler_options_t *bler_opts; ///< UL BLER options (for adapt_ul_mcs)
} nr_ul_sched_params_t;
struct nr_ul_candidate {
/* ── UE identity / scheduling state (set by collect, never modified after) ── */
NR_UE_info_t *UE;
uint16_t rnti; ///< UE RNTI (convenience)
bool is_retx;
int8_t retx_harq_pid;
int retx_rbSize;
bool sched_inactive;
uint32_t pending_bytes;
float avg_throughput;
float bler;
int current_mcs;
int max_mcs;
int last_num_sched; ///< scheduling count at last BLER update (activity guard)
bool bler_updated; ///< true if BLER was refreshed this frame
int mcs_table;
int bwp_start;
int bwp_size;
uint64_t fiveQI; ///< 5QI from first DRB's QoS config (0 if none)
int priority; ///< LC priority from first DRB (0 if none)
nssai_t nssai; ///< slice/service type/differentiator from first DRB
int beam_index;
/* ── Power control (set by collect, read-only after) ─────────────────────── */
int ph; ///< power headroom
int pcmax; ///< configured max TX power
int snrx10; ///< PUSCH SINR × 10 (for SINR-based MCS in harq_round_max==1)
bool skipped; ///< true if dropped by TDA/beam select (skip in downstream stages)
bool scheduled; ///< true if accepted by the RB-allocation policy
/* ── UE CSI observations (set by collect, read-only after) ─────────────── */
uint16_t cqi; ///< wideband CQI (from CSI report)
const int16_t *beam_rsrp; ///< per-SSB L1-RSRP; points into NR_UE_info_t::beam_rsrp. INT16_MIN = no data.
const int16_t *beam_sinr; ///< per-SSB L1-SINR×10; same indexing. INT16_MIN = no data.
/* ── gNB decisions (written by the named pipeline stage) ───────────────── */
/* Use NR_sched_pusch_t for fields shared with HARQ/dispatch (mcs, rbStart,
* rbSize, nrOfLayers, tpmi, tda, tda_info).
* Remaining dispatch-only fields (R, Qm, tb_size, dmrs_info, bwp_info) are
* filled at dispatch time. Mirrors DL sched_pdsch pattern. */
NR_sched_pusch_t sched_pusch;
uint16_t alloc_slbitmap; ///< symbol bitmap derived from sched_pusch.tda_info
/* ul_beam_select: beam assignment (DCI slot + PUSCH slot) */
int alloc_dci_beam_idx; ///< beam idx for the DCI slot; -1 = failed
int alloc_beam_idx; ///< beam idx for the scheduled PUSCH slot; -1 = failed
bool alloc_dci_beam_new; ///< true if dci_beam was newly allocated
bool alloc_sched_beam_new; ///< true if sched_beam was newly allocated
/* commit_ul_alloc: CCE validation */
int alloc_cce_index;
int alloc_aggregation_level;
NR_sched_pdcch_t alloc_sched_pdcch;
};
typedef struct {
uint16_t rbSize;
uint8_t mcs;
bool valid;
} nr_ul_phr_suggestion_t;
typedef struct {
nr_ul_phr_suggestion_t max_mcs_min_rb;
nr_ul_phr_suggestion_t same_rb_min_mcs;
} nr_ul_phr_advice_t;
typedef int (*nr_ul_beam_select_fn)(NR_beam_info_t *beam_info,
const int16_t *beam_index_list,
nr_ul_candidate_t *candidates,
int n_candidates,
frame_t frame,
slot_t slot,
frame_t sched_frame,
slot_t sched_slot,
int slots_per_frame);
/// UL RI/TPMI selection: sets sched_pusch.nrOfLayers and tpmi per candidate from SRS feedback.
/// Default: reads from srs_feedback (current OAI behavior).
/// Custom: joint rank/TPMI search from H matrix, ML-based, etc.
typedef void (*nr_ul_ri_tpmi_select_fn)(gNB_MAC_INST *mac, nr_ul_candidate_t *cands, int n_cand);
/// UL TDA selection: picks TDA per candidate (default: same TDA for all), validates retx
/// feasibility, drops infeasible cands (compact). Returns surviving cand count.
/// Each surviving cand has sched_pusch.time_domain_allocation/tda_info and alloc_slbitmap populated. Retx cands have retx_rbSize
/// set.
typedef int (
*nr_ul_tda_select_fn)(gNB_MAC_INST *mac, nr_ul_candidate_t *cands, int n_cand, frame_t sched_frame, slot_t sched_slot, int k2);
/// MCS selection: sets sched_pusch.mcs from BLER/SINR state for every candidate.
/// Runs after beam_select so sched_pusch.nrOfLayers (for SINR lookup) and beam info are available.
/// Also persists the decision to ul_bler_stats.mcs for continuity across slots.
typedef void (*nr_ul_mcs_select_fn)(const gNB_MAC_INST *mac, nr_ul_candidate_t *candidates, int n_candidates);
/// UL scheduling policy: beam loop is inside the policy for cross-beam scheduling.
/// Sets candidate->scheduled = true for each accepted UE; returns the count.
typedef int (*nr_ul_rb_alloc_fn)(const nr_ul_sched_params_t *params, nr_ul_candidate_t *candidates, int n_candidates);
typedef struct f1_config_t {
f1ap_setup_req_t *setup_req;
f1ap_setup_resp_t *setup_resp;
uint32_t gnb_id; // associated gNB's ID, not used in DU itself
} f1_config_t;
typedef struct {
char *nvipc_shm_prefix;
int8_t nvipc_poll_core;
} nvipc_params_t;
typedef struct {
uint64_t total_prb_aggregate;
uint64_t used_prb_aggregate;
} mac_stats_t;
typedef struct dlul_mac_stats {
mac_stats_t dl;
mac_stats_t ul;
} dlul_mac_stats_t;
typedef struct {
NR_SearchSpace_t search_space[MAX_NUM_OF_SSB];
NR_ControlResourceSet_t coreset;
} NR_sched_ctrl_sib1_t;
typedef struct NR_du_stats {
/// cell-wide wide-band CQI distribution, see 28.552 5.1.1.11.1;
/// 0-15 CQI, 1-8 RI, 1-3 CQI table
uint32_t wb_cqi_dist[16][8][3];
/// cell-wide MCS distribution in PDSCH, see 28.552 5.1.1.12.1
/// 1-8 RI, 1-3 MCS table, 0-31 MCS value
uint32_t pdsch_mcs_dist[8][3][32];
/// cell-wide MCS distribution in PUSCH, see 28.552 5.1.1.12.1
/// 1-8 RI, 1-2 MCS table, 0-31 MCS value
uint32_t pusch_mcs_dist[8][2][32];
} NR_du_stats_t;
/*! \brief top level eNB MAC structure */
typedef struct gNB_MAC_INST_s {
/// Ethernet parameters for northbound midhaul interface
eth_params_t eth_params_n;
/// address for F1U to bind, ports in eth_params_n
char *f1u_addr;
/// Nvipc parameters for FAPI interface with Aerial
nvipc_params_t nvipc_params_s;
/// Module
module_id_t Mod_id;
/// timing advance group
NR_TAG_t *tag;
/// Pointer to IF module instance for PHY
NR_IF_Module_t *if_inst;
pthread_t stats_thread;
/// Subcarrier Offset
int ssb_SubcarrierOffset;
int ssb_OffsetPointA;
/// Common cell resources
NR_COMMON_channels_t common_channels[NFAPI_CC_MAX];
/// current PDU index (BCH,DLSCH)
uint16_t pdu_index[NFAPI_CC_MAX];
/// UL PRBs blacklist
uint16_t ulprbbl[MAX_BWP_SIZE];
/// NFAPI Config Request Structure
nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX];
/// a PDCCH PDU groups DCIs per BWP and CORESET. The following structure
/// keeps pointers to PDCCH PDUs within DL_req so that we can easily track
/// PDCCH PDUs per CC/BWP/CORESET
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_idx[NFAPI_CC_MAX][MAX_NUM_CORESET];
/// NFAPI UL TTI Request Structure for future TTIs, dynamically allocated
/// because length depends on number of slots
nfapi_nr_ul_tti_request_t *UL_tti_req_ahead[NFAPI_CC_MAX];
int UL_tti_req_ahead_size;
int vrb_map_UL_size;
NR_UEs_t UE_info;
// MAC function execution peformance profiler
/// processing time of gNB scheduler
time_stats_t gNB_scheduler;
/// processing time of gNB scheduler for Random access
time_stats_t schedule_ra;
/// processing time of gNB DLSCH scheduler
time_stats_t schedule_ulsch; // include preprocessor
/// processing time of gNB DLSCH scheduler
time_stats_t schedule_dlsch; // include rlc_data_req + MAC header + preprocessor
/// processing time of rlc_data_req
time_stats_t rlc_data_req;
/// processing time of nr_srs_ri_computation
time_stats_t nr_srs_ri_computation_timer;
/// processing time of nr_srs_tpmi_estimation
time_stats_t nr_srs_tpmi_computation_timer;
/// processing time of gNB ULSCH reception
time_stats_t rx_ulsch_sdu; // include rlc_data_ind
NR_beam_info_t beam_info;
/// maximum number of slots before a UE will be scheduled ULSCH automatically
uint32_t ulsch_max_frame_inactivity;
/// instance of the frame structure configuration
frame_structure_t frame_structure;
/// DL preprocessor for differentiated scheduling
nr_pp_impl_dl pre_processor_dl;
/// UL preprocessor for differentiated scheduling
nr_pp_impl_ul pre_processor_ul;
/// DL scheduling pipeline function pointers
nr_dl_ri_pmi_select_fn dl_ri_pmi_select;
nr_dl_tda_select_fn dl_tda_select;
nr_dl_beam_select_fn dl_beam_select;
nr_dl_mcs_select_fn dl_mcs_select;
nr_dl_rb_alloc_fn dl_rb_alloc;
nr_dl_lcid_alloc_fn dl_lcid_alloc;
/// UL RI/TPMI + TDA selection + beam selection + MCS selection + RB allocation
nr_ul_ri_tpmi_select_fn ul_ri_tpmi_select;
nr_ul_tda_select_fn ul_tda_select;
nr_ul_beam_select_fn ul_beam_select;
nr_ul_mcs_select_fn ul_mcs_select;
nr_ul_rb_alloc_fn ul_rb_alloc;
/// Optional state persistence for scheduling policies.
void *sched_stateful_data;
nr_mac_config_t radio_config;
nr_rlc_configuration_t rlc_config;
NR_sched_ctrl_sib1_t *sched_ctrlSIB1;
NR_sched_pdcch_t *sched_pdcch_otherSI;
uint16_t cset0_bwp_start;
uint16_t cset0_bwp_size;
NR_Type0_PDCCH_CSS_config_t type0_PDCCH_CSS_config[MAX_NUM_OF_SSB];
bool first_MIB;
NR_bler_options_t dl_bler;
NR_bler_options_t ul_bler;
uint16_t min_grant_prb;
bool identity_pm;
int precoding_matrix_size[NR_MAX_NB_LAYERS];
int16_t beam_index_list[MAX_NUM_OF_SSB];
NR_sched_pdsch_t sib1_pdsch[MAX_NUM_OF_SSB];
/// dedicate UL TDA, common for all UEs
seq_arr_t ul_tda;
/// next UL slot to schedule
fsn_t ul_next;
nr_mac_rrc_ul_if_t mac_rrc;
f1_config_t f1_config;
int16_t frame;
/// number of UEs to exceed to disable stats
int stats_max_ue;
/// if stats are currently enabled
bool print_ue_stats;
pthread_mutex_t sched_lock;
dlul_mac_stats_t mac_stats;
uint64_t num_scheduled_prach_rx;
NR_du_stats_t du_stats;
} gNB_MAC_INST;
#endif /*__LAYER2_NR_MAC_GNB_H__ */
/** @}*/