Commit cec6b892 authored by batuhan duyuler's avatar batuhan duyuler Committed by Robert Schmidt

Preparation of Neighbour Configuration & Measurement Configuration | Parsing the configuration

- neighbour_config.conf file includes neighbour and measurement related parameters
Neighbour List:
 - nr_cellid: the identity of existing cell who has neighbour
 - neighbour_cell_configuration(list): includes the identity parameters
   of the neighbour cell such:
    - gNBID (incase of N2 Handover / to be identified from AMF)
    - nr_cell_id (target gNB needs to consider)
    - physical_cellId (needed for measurement reporting)
    - absoluteFrequencySSB (needed for measurement reporting)
    - subcarrierSpacing (needed for measurement reporting)
    - plmn / tracking area code (incase of N2 Handover / needed for AMF
      to identify / allow HO)

NR Measurement Configuration
 - Periodical
    - enable (default is 0, 1 enables the reporting)
    - includeBeamMeasurements, maxNrOfRS_IndexesToReport (configurable
      reporting parameters)
 - A2
    - enable (default is 0, 1 enables the reporting)
    - threshold , timeToTrigger (configurable reporting parameters)
 - A3
    - cell_id (the nr_cellid of neighbour cell. So this A3 parameters
      will be used for the neighbour
        - [-1] means default. so it can be applied to any neighbour if
          there is no specific config
        - Neighbour specific A3 Threshold can be used or default can be
          selected depending to the neighbour planning
        - The neighbour-config.conf specifies, apply default A3 for
          neighbours 3 and 4 | apply specific one for neighbour 2

    - offset, hysteresis, timeToTrigger (configurable reporting parameters)

the neighbour_config.conf can be included in the gNB.conf file. Example
is given: gnb.sa.band78.106prb.rfsim.neighbour.conf

A sequence array container is used for neighbour cell configuration. RRC
structure has this container.  A Measurement configuration structure is
defined. This structure has Periodical / A2 Event structures and also a
sequence container for A3 Event List.

These structures are filled during the initialization. While F1 Setup
Response is coming from DU to CU, the intra frequency / inter frequency
neighbour decision is given for the existing cell. Also new neighbours
could be added here if needed.
parent e5afdcdd
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; sd = 0x1; }) });
@include "neighbour-config.conf"
nr_cellid = 1;
////////// Physical parameters:
do_CSIRS = 0;
do_SRS = 0;
min_rxtxtime = 6;
pdcch_ConfigSIB1 = (
{
controlResourceSetZero = 12;
searchSpaceZero = 0;
}
);
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# downlinkConfigCommon
#frequencyInfoDL
# this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
absoluteFrequencySSB = 641280;
dl_frequencyBand = 78;
# this is 3600 MHz
dl_absoluteFrequencyPointA = 640008;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 12;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 78;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 20;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 98;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 13;
preambleReceivedTargetPower = -96;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 6;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 1;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#oneHalf (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
msg3_DeltaPreamble = 1;
p0_NominalWithGrant =-90;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 40;
p0_nominal = -90;
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR = 2;
ssb_PositionsInBurst_Bitmap = 1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = -25;
}
);
# Dedicated Serving Cell Configuration
servingCellConfigDedicated = ({
# BWP-Downlink
# BWP 1 Configuration
dl_bwp-Id_1 = 1;
dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_bwp1_subcarrierSpacing = 1;
# BWP 2 Configuration
dl_bwp-Id_2 = 2;
dl_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_bwp2_subcarrierSpacing = 1;
# BWP 3 Configuration
dl_bwp-Id_3 = 3;
dl_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_bwp3_subcarrierSpacing = 1;
firstActiveDownlinkBWP-Id = 1; #BWP-Id
defaultDownlinkBWP-Id = 1; #BWP-Id
# bwp-InactivityTimer ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30,
# ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500,
# ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8,
# spare7, spare6, spare5, spare4, spare3, spare2, spare1 }
# UplinkConfig
# BWP-Uplink
# BWP 1 Configuration
ul_bwp-Id_1 = 1;
ul_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_bwp1_subcarrierSpacing = 1;
# BWP 2 Configuration
ul_bwp-Id_2 = 2;
ul_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_bwp2_subcarrierSpacing = 1;
# BWP 3 Configuration
ul_bwp-Id_3 = 3;
ul_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW)
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_bwp3_subcarrierSpacing = 1;
firstActiveUplinkBWP-Id = 1; #BWP-Id
}
);
# ------- SCTP definitions
SCTP : {
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ( { ipv4 = "192.168.70.132"; });
NETWORK_INTERFACES : {
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129";
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 250;
pucch_TargetSNRx10 = 200;
ulsch_max_frame_inactivity = 0;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 120;
pucch0_dtx_threshold = 100;
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
}
);
RUs = ({
local_rf = "yes";
nb_tx = 1;
nb_rx = 1;
att_tx = 0;
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
eNB_instances = [0];
#beamforming 1x4 matrix:
bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
clock_src = "internal";
});
THREAD_STRUCT = (
{
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
parallel_config = "PARALLEL_SINGLE_THREAD";
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
worker_config = "WORKER_ENABLE";
}
);
rfsimulator: {
serveraddr = "server";
serverport = 4043;
options = (); #("saviq"); or/and "chanmod"
modelname = "AWGN";
IQfile = "/tmp/rfsimulator.iqs"
}
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config : {
global_log_level ="info";
hw_log_level ="info";
phy_log_level ="info";
mac_log_level ="info";
rlc_log_level ="info";
pdcp_log_level ="info";
nr_rrc_log_level ="info";
rrc_log_level ="info";
ngap_log_level ="debug";
f1ap_log_level ="debug";
};
neighbour_list = (
{
nr_cellid = 1;
neighbour_cell_configuration = (
{
gNB_ID = 0xb00;
nr_cellid = 2;
physical_cellId = 0x002;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 216; mnc = 03; mnc_length = 2};
tracking_area_code = 2;
},
{
gNB_ID = 0xa00;
nr_cellid = 3;
physical_cellId = 0x003;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 999; mnc = 99; mnc_length = 2};
tracking_area_code = 3;
},
{
gNB_ID = 0xc00;
nr_cellid = 4;
physical_cellId = 0x004;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 999; mnc = 99; mnc_length = 2};
tracking_area_code = 4;
}
)
},
{
nr_cellid = 2;
neighbour_cell_configuration = (
{
gNB_ID = 0xe00;
nr_cellid = 1;
physical_cellId = 0x000;
absoluteFrequencySSB = 641280 ;
subcarrierSpacing = 1; #30 KHz
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
tracking_area_code = 1;
}
)
}
);
nr_measurement_configuration = {
Periodical = {
enable = 1;
includeBeamMeasurements = 1;
maxNrofRS_IndexesToReport = 4;
};
A2 = {
enable = 1;
threshold = 60;
timeToTrigger = 1;
};
A3 = ({
cell_id = -1; #Default
offset = 10;
hysteresis = 0;
timeToTrigger = 1
}, {
cell_id = 2;
offset = 5;
hysteresis = 1;
timeToTrigger = 2
})
};
...@@ -85,6 +85,7 @@ ...@@ -85,6 +85,7 @@
#include "NR_EUTRA-MBSFN-SubframeConfig.h" #include "NR_EUTRA-MBSFN-SubframeConfig.h"
#include "uper_decoder.h" #include "uper_decoder.h"
#include "uper_encoder.h" #include "uper_encoder.h"
#include "common/utils/ds/seq_arr.h"
#include "RRC/NR/MESSAGES/asn1_msg.h" #include "RRC/NR/MESSAGES/asn1_msg.h"
#include "RRC/NR/nr_rrc_extern.h" #include "RRC/NR/nr_rrc_extern.h"
...@@ -1593,6 +1594,155 @@ static void check_ssb_raster(uint64_t freq, int band, int scs) ...@@ -1593,6 +1594,155 @@ static void check_ssb_raster(uint64_t freq, int band, int scs)
gscn, freq, band); gscn, freq, band);
} }
static int sort_neighbour_cell_config_by_cell_id(const void *a, const void *b)
{
const neighbour_cell_configuration_t *config_a = (const neighbour_cell_configuration_t *)a;
const neighbour_cell_configuration_t *config_b = (const neighbour_cell_configuration_t *)b;
if (config_a->nr_cell_id < config_b->nr_cell_id) {
return -1;
} else if (config_a->nr_cell_id > config_b->nr_cell_id) {
return 1;
}
return 0;
}
static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
{
char gnbpath[MAX_OPTNAME_SIZE + 8];
sprintf(gnbpath, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx);
paramdef_t neighbour_list_params[] = GNB_NEIGHBOUR_LIST_PARAM_LIST;
paramlist_def_t neighbour_list_param_list = {GNB_CONFIG_STRING_NEIGHBOUR_LIST, NULL, 0};
config_getlist(config_get_if(), &neighbour_list_param_list, neighbour_list_params, sizeofArray(neighbour_list_params), gnbpath);
if (neighbour_list_param_list.numelt < 1)
return;
rrc->neighbour_cell_configuration = malloc(sizeof(seq_arr_t));
seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t));
for (int elm = 0; elm < neighbour_list_param_list.numelt; ++elm) {
neighbour_cell_configuration_t *cell = calloc(1, sizeof(neighbour_cell_configuration_t));
AssertFatal(cell != NULL, "out of memory\n");
cell->nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr;
char neighbourpath[MAX_OPTNAME_SIZE + 8];
sprintf(neighbourpath, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm);
paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC;
paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0};
config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath);
LOG_D(GNB_APP, "HO LOG: For the Cell: %d Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt);
if (NeighbourCellParamList.numelt < 1)
continue;
cell->neighbour_cells = malloc(sizeof(seq_arr_t));
AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!");
seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t));
for (int l = 0; l < NeighbourCellParamList.numelt; ++l) {
nr_neighbour_gnb_configuration_t *neighbourCell = calloc(1, sizeof(nr_neighbour_gnb_configuration_t));
AssertFatal(neighbourCell != NULL, "out of memory\n");
neighbourCell->gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr);
neighbourCell->nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr);
neighbourCell->physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr;
neighbourCell->subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr;
neighbourCell->absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr;
neighbourCell->tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr;
char neighbour_plmn_path[CONFIG_MAXOPTLENGTH];
sprintf(neighbour_plmn_path,
"%s.%s.[%i].%s",
neighbourpath,
GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST,
l,
GNB_CONFIG_STRING_NEIGHBOUR_PLMN);
paramdef_t NeighbourPlmn[] = GNBPLMNPARAMS_DESC;
config_get(config_get_if(), NeighbourPlmn, sizeofArray(NeighbourPlmn), neighbour_plmn_path);
neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr;
neighbourCell->plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr;
seq_arr_push_back(cell->neighbour_cells, neighbourCell, sizeof(nr_neighbour_gnb_configuration_t));
}
seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t));
}
void *base = seq_arr_front(rrc->neighbour_cell_configuration);
size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration);
size_t element_size = sizeof(neighbour_cell_configuration_t);
qsort(base, nmemb, element_size, sort_neighbour_cell_config_by_cell_id);
}
static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
{
char measurement_path[MAX_OPTNAME_SIZE + 8];
sprintf(measurement_path, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION);
nr_measurement_configuration_t *measurementConfig = &rrc->measurementConfiguration;
// Periodical Event Configuration
char periodic_event_path[MAX_OPTNAME_SIZE + 8];
sprintf(periodic_event_path,
"%s.[%i].%s.%s",
GNB_CONFIG_STRING_GNB_LIST,
gnb_idx,
GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION,
MEASUREMENT_EVENTS_PERIODICAL);
paramdef_t Periodical_EventParams[] = MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC;
config_get(config_get_if(), Periodical_EventParams, sizeofArray(Periodical_EventParams), periodic_event_path);
if (*Periodical_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) {
nr_per_event_t *periodic_event = (nr_per_event_t *)calloc(1, sizeof(nr_per_event_t));
periodic_event->includeBeamMeasurements = *Periodical_EventParams[MEASUREMENT_EVENTS_INCLUDE_BEAM_MEAS_IDX].i64ptr;
periodic_event->maxReportCells = *Periodical_EventParams[MEASUREMENT_EVENTS_MAX_RS_INDEX_TO_REPORT].i64ptr;
measurementConfig->per_event = periodic_event;
}
// A2 Event Configuration
char a2_path[MAX_OPTNAME_SIZE + 8];
sprintf(a2_path,
"%s.[%i].%s.%s",
GNB_CONFIG_STRING_GNB_LIST,
gnb_idx,
GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION,
MEASUREMENT_EVENTS_A2);
paramdef_t A2_EventParams[] = MEASUREMENT_A2_GLOBALPARAMS_DESC;
config_get(config_get_if(), A2_EventParams, sizeofArray(A2_EventParams), a2_path);
if (*A2_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) {
nr_a2_event_t *a2_event = (nr_a2_event_t *)calloc(1, sizeof(nr_a2_event_t));
a2_event->threshold_RSRP = *A2_EventParams[MEASUREMENT_EVENTS_A2_THRESHOLD_IDX].i64ptr;
a2_event->timeToTrigger = *A2_EventParams[MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr;
measurementConfig->a2_event = a2_event;
}
// A3 Event Configuration
paramlist_def_t A3_EventList = {MEASUREMENT_EVENTS_A3, NULL, 0};
paramdef_t A3_EventParams[] = MEASUREMENT_A3_GLOBALPARAMS_DESC;
config_getlist(config_get_if(), &A3_EventList, A3_EventParams, sizeofArray(A3_EventParams), measurement_path);
LOG_D(GNB_APP, "HO LOG: A3 Configuration Exists: %d\n", A3_EventList.numelt);
if (A3_EventList.numelt < 1)
return;
measurementConfig->a3_event_list = malloc(sizeof(seq_arr_t));
seq_arr_init(measurementConfig->a3_event_list, sizeof(nr_a3_event_t));
for (int i = 0; i < A3_EventList.numelt; i++) {
nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t));
AssertFatal(a3_event != NULL, "out of memory\n");
a3_event->cell_id = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_CELL_ID_IDX].i64ptr;
a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr;
a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr;
a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr;
if (a3_event->cell_id == -1)
measurementConfig->is_default_a3_configuration_exists = true;
seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t));
}
}
void RCconfig_NRRRC(gNB_RRC_INST *rrc) void RCconfig_NRRRC(gNB_RRC_INST *rrc)
{ {
...@@ -1682,7 +1832,10 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc) ...@@ -1682,7 +1832,10 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc)
char gnbpath[MAX_OPTNAME_SIZE + 8]; char gnbpath[MAX_OPTNAME_SIZE + 8];
sprintf(gnbpath,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); sprintf(gnbpath,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
fill_neighbour_cell_configuration(k, rrc);
fill_measurement_configuration(k, rrc);
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
......
...@@ -254,7 +254,92 @@ typedef enum { ...@@ -254,7 +254,92 @@ typedef enum {
} }
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------------------------------------*/
/* Neighbour Cell Configurations*/
#define GNB_CONFIG_STRING_NEIGHBOUR_LIST "neighbour_list"
// clang-format off
#define GNB_NEIGHBOUR_LIST_PARAM_LIST { \
/* optname helpstr paramflags XXXptr def val type numelt */ \
{GNB_CONFIG_STRING_NRCELLID, "cell nrCell Id which has neighbours", PARAMFLAG_MANDATORY, .u64ptr=NULL, .defint64val=0, TYPE_UINT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, "neighbour cell physical id", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
}
// clang-format on
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST "neighbour_cell_configuration"
#define GNB_CONFIG_STRING_NEIGHBOUR_GNB_ID "gNB_ID"
#define GNB_CONFIG_STRING_NEIGHBOUR_NR_CELLID "nr_cellid"
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID "physical_cellId"
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB "absoluteFrequencySSB"
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS "subcarrierSpacing"
#define GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE "tracking_area_code"
#define GNB_CONFIG_STRING_NEIGHBOUR_PLMN "plmn"
#define GNB_CONFIG_N_CELL_GNB_ID_IDX 0
#define GNB_CONFIG_N_CELL_NR_CELLID_IDX 1
#define GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX 2
#define GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX 3
#define GNB_CONFIG_N_CELL_SCS_IDX 4
#define GNB_CONFIG_N_CELL_TAC_IDX 5
// clang-format off
#define GNBNEIGHBOURCELLPARAMS_DESC { \
/* optname helpstr paramflags XXXptr def val type numelt */ \
{GNB_CONFIG_STRING_GNB_ID, "neighbour cell's gNB ID", PARAMFLAG_MANDATORY, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NRCELLID, "neighbour cell nrCell Id", PARAMFLAG_MANDATORY, .u64ptr=NULL, .defint64val=0, TYPE_UINT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, "neighbour cell physical id", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB, "neighbour cell abs freq ssb", PARAMFLAG_MANDATORY, .i64ptr=NULL, .defint64val=0, TYPE_INT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS, "neighbour cell scs", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE, "neighbour cell tracking area", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
}
// clang-format on
/* New Measurement Configurations*/
#define GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION "nr_measurement_configuration"
#define MEASUREMENT_EVENTS_PERIODICAL "Periodical"
#define MEASUREMENT_EVENTS_A2 "A2"
#define MEASUREMENT_EVENTS_A3 "A3"
#define MEASUREMENT_EVENTS_OFFSET "offset"
#define MEASUREMENT_EVENTS_HYSTERESIS "hysteresis"
#define MEASUREMENT_EVENTS_TIME_TO_TRIGGER "time_to_trigger"
#define MEASUREMENT_EVENTS_THRESHOLD "threshold"
#define MEASUREMENT_EVENTS_PERIODICAL_BEAM_MEASUREMENT "includeBeamMeasurements"
#define MEASUREMENT_EVENTS_PERIODICAL_NR_OF_RS_INDEXES "maxNrofRS_IndexesToReport"
#define MEASUREMENT_EVENTS_CELL_ID "cell_id"
#define MEASUREMENT_EVENT_ENABLE "enable"
// clang-format off
#define MEASUREMENT_A3_GLOBALPARAMS_DESC \
{ \
{MEASUREMENT_EVENTS_CELL_ID, "neighbour cellId for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_TIME_TO_TRIGGER, "a3 time to trigger", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_OFFSET, "a3 offset", 0, .i64ptr = NULL, .defint64val = 60, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_HYSTERESIS, "a3 hysteresis", 0, .i64ptr = NULL, .defint64val = 0, TYPE_INT64, 0}, \
}
#define MEASUREMENT_A2_GLOBALPARAMS_DESC \
{ \
{MEASUREMENT_EVENT_ENABLE, "enable the event", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_TIME_TO_TRIGGER, "a2 time to trigger", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_THRESHOLD, "a2 threshold", 0, .i64ptr = NULL, .defint64val = 60, TYPE_INT64, 0}, \
}
#define MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC \
{ \
{MEASUREMENT_EVENT_ENABLE, "enable the event", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_PERIODICAL_BEAM_MEASUREMENT, "includeBeamMeasurements", PARAMFLAG_BOOL, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_PERIODICAL_NR_OF_RS_INDEXES, "maxNrofRS_IndexesToReport", 0, .i64ptr = NULL, .defint64val = 4, TYPE_INT64, 0}, \
}
// clang-format on
#define MEASUREMENT_EVENTS_CELL_ID_IDX 0
#define MEASUREMENT_EVENTS_ENABLE_IDX 0
#define MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX 1
#define MEASUREMENT_EVENTS_A2_THRESHOLD_IDX 2
#define MEASUREMENT_EVENTS_OFFSET_IDX 2
#define MEASUREMENT_EVENTS_HYSTERESIS_IDX 3
#define MEASUREMENT_EVENTS_INCLUDE_BEAM_MEAS_IDX 1
#define MEASUREMENT_EVENTS_MAX_RS_INDEX_TO_REPORT 2
/* PLMN ID configuration */ /* PLMN ID configuration */
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "collection/tree.h" #include "collection/tree.h"
#include "collection/linear_alloc.h" #include "collection/linear_alloc.h"
#include "common/utils/ds/seq_arr.h"
#include "nr_rrc_common.h" #include "nr_rrc_common.h"
#include "ds/byte_array.h" #include "ds/byte_array.h"
...@@ -359,6 +360,46 @@ typedef struct { ...@@ -359,6 +360,46 @@ typedef struct {
int do_drb_integrity; int do_drb_integrity;
} nr_security_configuration_t; } nr_security_configuration_t;
typedef struct {
long maxReportCells;
bool includeBeamMeasurements;
} nr_per_event_t;
typedef struct {
long threshold_RSRP;
long timeToTrigger;
} nr_a2_event_t;
typedef struct {
int cell_id;
long a3_offset;
long hysteresis;
long timeToTrigger;
} nr_a3_event_t;
typedef struct {
nr_per_event_t *per_event;
nr_a2_event_t *a2_event;
seq_arr_t *a3_event_list;
bool is_default_a3_configuration_exists;
} nr_measurement_configuration_t;
typedef struct {
uint32_t gNB_ID;
uint64_t nrcell_id;
int physicalCellId;
int absoluteFrequencySSB;
int subcarrierSpacing;
plmn_identity_t plmn;
uint32_t tac;
bool isIntraFrequencyNeighbour;
} nr_neighbour_gnb_configuration_t;
typedef struct neighbour_cell_configuration_s {
int nr_cell_id;
seq_arr_t *neighbour_cells;
} neighbour_cell_configuration_t;
typedef struct nr_mac_rrc_dl_if_s { typedef struct nr_mac_rrc_dl_if_s {
f1_setup_response_func_t f1_setup_response; f1_setup_response_func_t f1_setup_response;
f1_setup_failure_func_t f1_setup_failure; f1_setup_failure_func_t f1_setup_failure;
...@@ -423,6 +464,8 @@ typedef struct gNB_RRC_INST_s { ...@@ -423,6 +464,8 @@ typedef struct gNB_RRC_INST_s {
nr_mac_rrc_dl_if_t mac_rrc; nr_mac_rrc_dl_if_t mac_rrc;
cucp_cuup_if_t cucp_cuup; cucp_cuup_if_t cucp_cuup;
seq_arr_t *neighbour_cell_configuration;
nr_measurement_configuration_t measurementConfiguration;
RB_HEAD(rrc_du_tree, nr_rrc_du_container_t) dus; // DUs, indexed by assoc_id RB_HEAD(rrc_du_tree, nr_rrc_du_container_t) dus; // DUs, indexed by assoc_id
size_t num_dus; size_t num_dus;
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "openair2/F1AP/f1ap_common.h" #include "openair2/F1AP/f1ap_common.h"
#include "openair2/F1AP/f1ap_ids.h" #include "openair2/F1AP/f1ap_ids.h"
#include "executables/softmodem-common.h" #include "executables/softmodem-common.h"
#include "common/utils/ds/seq_arr.h"
#include "common/utils/alg/foreach.h"
int get_dl_band(const struct f1ap_served_cell_info_t *cell_info) int get_dl_band(const struct f1ap_served_cell_info_t *cell_info)
{ {
...@@ -121,6 +123,80 @@ static NR_MeasurementTimingConfiguration_t *extract_mtc(uint8_t *buf, int buf_le ...@@ -121,6 +123,80 @@ static NR_MeasurementTimingConfiguration_t *extract_mtc(uint8_t *buf, int buf_le
return mtc; return mtc;
} }
static int nr_cell_id_match(const void *key, const void *element)
{
const int *key_id = (const int *)key;
const neighbour_cell_configuration_t *config_element = (const neighbour_cell_configuration_t *)element;
if (*key_id < config_element->nr_cell_id) {
return -1;
} else if (*key_id == config_element->nr_cell_id) {
return 0;
}
return 1;
}
static neighbour_cell_configuration_t *get_cell_neighbour_list(const gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *cell_info)
{
void *base = seq_arr_front(rrc->neighbour_cell_configuration);
size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration);
size_t size = sizeof(neighbour_cell_configuration_t);
void *it = bsearch((void *)&cell_info->nr_cellid, base, nmemb, size, nr_cell_id_match);
return (neighbour_cell_configuration_t *)it;
}
const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyCellId)
{
gNB_RRC_INST *rrc = RC.nrrrc[0];
nr_rrc_du_container_t *it = NULL;
RB_FOREACH (it, rrc_du_tree, &rrc->dus) {
for (int cellIdx = 0; cellIdx < it->setup_req->num_cells_available; cellIdx++) {
const f1ap_served_cell_info_t *cell_info = &(it->setup_req->cell[cellIdx].info);
if (cell_info->nr_pci == phyCellId) {
LOG_D(NR_RRC, "HO LOG: Found cell with phyCellId %d\n", phyCellId);
return cell_info;
}
}
}
return NULL;
}
static void is_intra_frequency_neighbour(void *ssb_arfcn, void *neighbour_cell)
{
uint32_t *ssb_arfcn_ptr = (uint32_t *)ssb_arfcn;
nr_neighbour_gnb_configuration_t *neighbour_cell_ptr = (nr_neighbour_gnb_configuration_t *)neighbour_cell;
if (*ssb_arfcn_ptr == neighbour_cell_ptr->absoluteFrequencySSB) {
LOG_D(NR_RRC, "HO LOG: found intra frequency neighbour %lu!\n", neighbour_cell_ptr->nrcell_id);
neighbour_cell_ptr->isIntraFrequencyNeighbour = true;
}
}
/**
* @brief Labels neighbour cells if they are intra frequency to prepare meas config only for intra frequency ho
* @param[in] rrc Pointer to RRC instance
* @param[in] cell_info Pointer to cell information
*/
static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc,
const nr_rrc_du_container_t *du,
const f1ap_served_cell_info_t *cell_info)
{
if (!rrc->neighbour_cell_configuration)
return;
neighbour_cell_configuration_t *neighbour_cell_config = get_cell_neighbour_list(rrc, cell_info);
if (!neighbour_cell_config)
return;
LOG_D(NR_RRC, "HO LOG: Cell: %lu has neighbour cell configuration!\n", cell_info->nr_cellid);
uint32_t ssb_arfcn = get_ssb_arfcn(du);
seq_arr_t *cell_neighbour_list = neighbour_cell_config->neighbour_cells;
for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour);
}
void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
{ {
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n"); AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
...@@ -229,6 +305,9 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) ...@@ -229,6 +305,9 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
.num_SI = 0, .num_SI = 0,
}; };
if (du->mib != NULL && du->sib1 != NULL)
label_intra_frequency_neighbours(rrc, du, cell_info);
f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id, f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id,
.num_cells_to_activate = 1, .num_cells_to_activate = 1,
.cells_to_activate[0] = cell}; .cells_to_activate[0] = cell};
...@@ -350,6 +429,10 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update ...@@ -350,6 +429,10 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
LOG_I(RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id); LOG_I(RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id);
} }
} }
if (du->mib != NULL && du->sib1 != NULL) {
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
label_intra_frequency_neighbours(rrc, du, cell_info);
}
} }
if (conf_up->num_cells_to_delete > 0) { if (conf_up->num_cells_to_delete > 0) {
......
...@@ -32,6 +32,7 @@ struct f1ap_lost_connection_t; ...@@ -32,6 +32,7 @@ struct f1ap_lost_connection_t;
struct gNB_RRC_INST_s; struct gNB_RRC_INST_s;
struct nr_rrc_du_container_t; struct nr_rrc_du_container_t;
struct f1ap_gnb_du_configuration_update_s; struct f1ap_gnb_du_configuration_update_s;
struct f1ap_served_cell_info_t;
void rrc_gNB_process_f1_setup_req(struct f1ap_setup_req_s *req, sctp_assoc_t assoc_id); void rrc_gNB_process_f1_setup_req(struct f1ap_setup_req_s *req, sctp_assoc_t assoc_id);
void rrc_CU_process_f1_lost_connection(struct gNB_RRC_INST_s *rrc, struct f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id); void rrc_CU_process_f1_lost_connection(struct gNB_RRC_INST_s *rrc, struct f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id);
...@@ -39,6 +40,7 @@ void rrc_gNB_process_f1_du_configuration_update(struct f1ap_gnb_du_configuration ...@@ -39,6 +40,7 @@ void rrc_gNB_process_f1_du_configuration_update(struct f1ap_gnb_du_configuration
struct nr_rrc_du_container_t *get_du_for_ue(struct gNB_RRC_INST_s *rrc, uint32_t ue_id); struct nr_rrc_du_container_t *get_du_for_ue(struct gNB_RRC_INST_s *rrc, uint32_t ue_id);
struct nr_rrc_du_container_t *get_du_by_assoc_id(struct gNB_RRC_INST_s *rrc, sctp_assoc_t assoc_id); struct nr_rrc_du_container_t *get_du_by_assoc_id(struct gNB_RRC_INST_s *rrc, sctp_assoc_t assoc_id);
const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyCellId);
void dump_du_info(const struct gNB_RRC_INST_s *rrc, FILE *f); void dump_du_info(const struct gNB_RRC_INST_s *rrc, FILE *f);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment