Merge branch 'integration_2025_w16' into 'develop'
Integration: `2025.w16` Closes #949, #929, and #941 See merge request oai/openairinterface5g!3392 * !3207 Create nrUE network interface from SDAP (rebased) * !3293 Cleanup and refactor initial gNB configuration * !3326 Enable SSB-SINR based CSI reporting * !3330 NR UE: consider the ratio of PUSCH EPRE to DMRS EPRE when calculating PUSCH DMRS power scaling * !3376 Correct block_length to Kprime for LDPC decoder * !3390 fix IP address in 4G UE * !3071 time management module * !3254 Follow up on NAS Registration Accept lib * !3121 Bugfix for number of PRBs in PUCCH format 2 * !3387 fix NTN LEO scenario * !3393 rejecting DRB if not configured in PDCP-Config * !3372 Add Delay Mechanism for Initial MIB/SIB Transmission in gNB Scheduler
This commit is contained in:
@@ -1835,6 +1835,7 @@ target_link_libraries(nr-softmodem PRIVATE
|
||||
ITTI ${NAS_UE_LIB} lte_rrc nr_rrc
|
||||
ngap s1ap L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU
|
||||
x2ap f1ap m2ap m3ap e1ap shlib_loader
|
||||
time_management
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt sctp)
|
||||
@@ -1867,6 +1868,7 @@ add_executable(nr-cuup
|
||||
target_link_libraries(nr-cuup PRIVATE
|
||||
CONFIG_LIB ITTI SCTP_CLIENT
|
||||
GTPV1U e1ap f1ap
|
||||
time_management
|
||||
z sctp dl pthread shlib_loader ${T_LIB})
|
||||
target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(E2_AGENT)
|
||||
@@ -1898,6 +1900,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE
|
||||
nr_rrc SECURITY UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB
|
||||
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB
|
||||
ITTI SIMU shlib_loader
|
||||
time_management
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas)
|
||||
|
||||
@@ -51,7 +51,7 @@ gNBs =
|
||||
initialDLBWPsubcarrierSpacing = 0;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 2;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
initialDLBWPsearchSpaceZero = 2;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
@@ -151,7 +151,7 @@ gNBs =
|
||||
#ext2
|
||||
#ntn_Config_r17
|
||||
cellSpecificKoffset_r17 = 40;
|
||||
ta-Common-r17 = 4634000; # 18.87 ms
|
||||
ta-Common-r17 = 4627000; # 18.84 ms
|
||||
ta-CommonDrift-r17 = -230000; # -46 µs/s
|
||||
positionX-r17 = 0;
|
||||
positionY-r17 = -2166908; # -2816980.4 m
|
||||
|
||||
@@ -235,15 +235,6 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_DISABLE";
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
@@ -279,6 +270,4 @@ log_config :
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="debug";
|
||||
f1ap_log_level ="debug";
|
||||
};
|
||||
|
||||
@@ -117,6 +117,7 @@ services:
|
||||
--time-sync-I 0.1 --ntn-initial-time-drift -46
|
||||
--autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
--log_config.global_log_options level,nocolor,time
|
||||
--num-ul-actors 1
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct plmn_id_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
} plmn_id_t;
|
||||
|
||||
typedef struct nssai_s {
|
||||
uint8_t sst;
|
||||
uint32_t sd;
|
||||
|
||||
@@ -167,4 +167,20 @@ typedef struct paramlist_def {
|
||||
int numelt ;
|
||||
} paramlist_def_t;
|
||||
|
||||
/* Macros to get parameters with the config module API */
|
||||
#define GET_PARAMS(param_def, param_desc, prefix) \
|
||||
printf("Reading '%s' section from the config file\n", #param_def); \
|
||||
paramdef_t param_def[] = param_desc; \
|
||||
config_get(config_get_if(), param_def, sizeofArray(param_def), prefix);
|
||||
|
||||
/* Macros to get params lists with the config module API */
|
||||
#define GET_PARAMS_LIST(param_list, param_def, param_desc, list_name, prefix, ...) \
|
||||
paramdef_t param_def[] = param_desc; \
|
||||
paramlist_def_t param_list = {list_name, NULL, 0}; \
|
||||
__VA_OPT__(checkedparam_t config_check_##param_def[] = __VA_ARGS__; \
|
||||
static_assert(sizeofArray(config_check_##param_def) == sizeofArray(param_def), \
|
||||
"param_def_t array and corresponding checkedparam_t array should have the same size"); \
|
||||
for (int i = 0; i < sizeofArray(param_def); ++i) param_def[i].chkPptr = &(config_check_##param_def[i]);) \
|
||||
config_getlist(config_get_if(), ¶m_list, param_def, sizeofArray(param_def), prefix);
|
||||
|
||||
#endif /* INCLUDE_CONFIG_PARAMDESC_H */
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
#define NB_RAB_MAX 11 /* from LTE_maxDRB in LTE_asn_constant.h */
|
||||
#define RAB_OFFSET 0x000F
|
||||
|
||||
#define MAX_NUM_SLICES 1024
|
||||
|
||||
// RLC Entity
|
||||
#define RLC_TX_MAXSIZE 10000000
|
||||
#define RLC_RX_MAXSIZE 10000000
|
||||
@@ -93,5 +95,6 @@
|
||||
#define RETURNerror (-1)
|
||||
#define DEFAULT_NAS_PATH "PWD"
|
||||
#define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE)
|
||||
#define NUM_PRACH_RX_FOR_NOISE_ESTIMATE 100
|
||||
|
||||
#endif /* __PLATFORM_CONSTANTS_H__ */
|
||||
|
||||
@@ -13,6 +13,7 @@ add_subdirectory(T)
|
||||
add_subdirectory(nr)
|
||||
add_subdirectory(LOG)
|
||||
add_subdirectory(threadPool)
|
||||
add_subdirectory(time_manager)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c)
|
||||
target_include_directories(utils PUBLIC .)
|
||||
target_link_libraries(utils PRIVATE ${T_LIB})
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "nr_common.h"
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#define C_SRS_NUMBER (64)
|
||||
#define B_SRS_NUMBER (4)
|
||||
@@ -1427,3 +1428,15 @@ frequency_range_t get_freq_range_from_band(uint16_t band)
|
||||
{
|
||||
return band <= 256 ? FR1 : FR2;
|
||||
}
|
||||
|
||||
float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type)
|
||||
{
|
||||
float beta_dmrs_pusch = 1.0;
|
||||
if (num_cdm_groups_no_data == 2) {
|
||||
beta_dmrs_pusch = powf(10.0, 3.0 / 20.0);
|
||||
} else if (num_cdm_groups_no_data == 3) {
|
||||
if (dmrs_type == pusch_dmrs_type2)
|
||||
beta_dmrs_pusch = powf(10.0, 4.77 / 20.0);
|
||||
}
|
||||
return beta_dmrs_pusch;
|
||||
}
|
||||
|
||||
@@ -130,6 +130,11 @@ typedef enum frequency_range_e {
|
||||
FR2
|
||||
} frequency_range_t;
|
||||
|
||||
typedef enum {
|
||||
pusch_dmrs_type1 = 0,
|
||||
pusch_dmrs_type2 = 1
|
||||
} pusch_dmrs_type_t;
|
||||
|
||||
#define MAX_NUM_SLOTS_ALLOWED 80 // up to numerology 3 (120 KHz SCS) is supported
|
||||
enum slot_type { TDD_NR_DOWNLINK_SLOT, TDD_NR_UPLINK_SLOT, TDD_NR_MIXED_SLOT };
|
||||
|
||||
@@ -302,6 +307,17 @@ frequency_range_t get_freq_range_from_freq(uint64_t freq);
|
||||
frequency_range_t get_freq_range_from_arfcn(uint32_t arfcn);
|
||||
frequency_range_t get_freq_range_from_band(uint16_t band);
|
||||
|
||||
/**
|
||||
* @brief Calculates the scaling factor for the ratio of PUSCH EPRE to DMRS EPRE.
|
||||
*
|
||||
* @param num_cdm_groups_no_data The number of CDM groups without data.
|
||||
* @param dmrs_type The DMRS type.
|
||||
* @return The calculated beta scaling factor for the ratio of PUSCH EPRE to DMRS EPRE.
|
||||
*
|
||||
* @note The values are derived from TS 38.214 Table 6.2.2-1.
|
||||
*/
|
||||
float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type);
|
||||
|
||||
#define CEILIDIV(a,b) ((a+b-1)/b)
|
||||
#define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1))
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
add_library(time_management STATIC
|
||||
time_manager.c)
|
||||
|
||||
add_library(time_management_core OBJECT
|
||||
time_source.c
|
||||
time_server.c
|
||||
time_client.c)
|
||||
|
||||
target_link_libraries(time_management PUBLIC time_management_core)
|
||||
target_link_libraries(time_management_core PRIVATE ${T_LIB})
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
@@ -0,0 +1,11 @@
|
||||
add_executable(test_time_manager_manual test_manual.c)
|
||||
target_link_libraries(test_time_manager_manual time_management_core)
|
||||
target_link_libraries(test_time_manager_manual LOG CONFIG_LIB)
|
||||
|
||||
add_executable(test_time_manager_auto test_auto.c)
|
||||
target_link_libraries(test_time_manager_auto time_management)
|
||||
target_link_libraries(test_time_manager_auto LOG CONFIG_LIB)
|
||||
|
||||
add_dependencies(tests test_time_manager_auto)
|
||||
add_test(NAME time_management_tests
|
||||
COMMAND ./test_time_manager_auto)
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
if (s != NULL) {
|
||||
printf("%s:%d %s() Exiting OAI softmodem: %s\n", file, line, function, s);
|
||||
}
|
||||
if (assert)
|
||||
abort();
|
||||
else
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int rlc_tick_count = 0;
|
||||
static int pdcp_tick_count = 0;
|
||||
static int x2ap_tick_count = 0;
|
||||
|
||||
void nr_rlc_ms_tick(void)
|
||||
{
|
||||
rlc_tick_count++;
|
||||
}
|
||||
|
||||
void nr_pdcp_ms_tick(void)
|
||||
{
|
||||
pdcp_tick_count++;
|
||||
}
|
||||
|
||||
void x2ap_ms_tick(void)
|
||||
{
|
||||
x2ap_tick_count++;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int standalone_realtime(void)
|
||||
{
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick,
|
||||
x2ap_ms_tick
|
||||
};
|
||||
int tick_functions_count = sizeofArray(tick_functions);
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME);
|
||||
|
||||
sleep(1);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
LOG_I(UTIL,
|
||||
"standalone realtime: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n",
|
||||
rlc_tick_count,
|
||||
pdcp_tick_count,
|
||||
x2ap_tick_count);
|
||||
|
||||
/* let's accept 1% deviation from the 1000 counts we expect */
|
||||
return abs(rlc_tick_count-1000) < 10
|
||||
&& abs(pdcp_tick_count - 1000) < 10
|
||||
&& abs(x2ap_tick_count - 1000) < 10;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int standalone_iq_samples(void)
|
||||
{
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick,
|
||||
x2ap_ms_tick
|
||||
};
|
||||
int tick_functions_count = sizeofArray(tick_functions);
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_IQ_SAMPLES);
|
||||
|
||||
/* let's pretend we have 2000 samples per second */
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
LOG_I(UTIL,
|
||||
"standalone iq-samples: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n",
|
||||
rlc_tick_count,
|
||||
pdcp_tick_count,
|
||||
x2ap_tick_count);
|
||||
|
||||
/* exact count is required */
|
||||
return rlc_tick_count == 1000
|
||||
&& pdcp_tick_count == 1000
|
||||
&& x2ap_tick_count == 1000;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int client_server(char *program_name, bool iq_samples_time_source)
|
||||
{
|
||||
LOG_I(UTIL, "client/server %s: launch sub-processes\n", iq_samples_time_source ? "iq-samples" : "realtime");
|
||||
|
||||
pid_t server;
|
||||
pid_t client;
|
||||
|
||||
/* start server */
|
||||
server = fork();
|
||||
DevAssert(server >= 0);
|
||||
if (server == 0) {
|
||||
/* run as server */
|
||||
if (iq_samples_time_source)
|
||||
execl(program_name, program_name, "--time_management.mode", "server", "--time_management.time_source", "iq_samples", NULL);
|
||||
else
|
||||
execl(program_name, program_name, "--time_management.mode", "server", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* wait a little bit so that server is ready to accept clients
|
||||
* (this is hackish)
|
||||
*/
|
||||
usleep(100);
|
||||
|
||||
/* start client */
|
||||
client = fork();
|
||||
DevAssert(client >= 0);
|
||||
if (client == 0) {
|
||||
/* run as client */
|
||||
execl(program_name, program_name, "--time_management.mode", "client", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* wait for completion */
|
||||
int ret = 1;
|
||||
|
||||
int status;
|
||||
pid_t r = waitpid(server, &status, 0);
|
||||
DevAssert(r == server);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
ret = 0;
|
||||
|
||||
r = waitpid(client, &status, 0);
|
||||
DevAssert(r == client);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int run_sub_client_server(bool iq_samples_time_source)
|
||||
{
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick,
|
||||
x2ap_ms_tick
|
||||
};
|
||||
int tick_functions_count = sizeofArray(tick_functions);
|
||||
/* last argument doesn't matter, overwritten by args of execl in client_server() */
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME);
|
||||
|
||||
if (iq_samples_time_source) {
|
||||
/* 'iq_samples_time_source' is true only for server
|
||||
* wait a bit for client to be there otherwise server
|
||||
* may finish too early
|
||||
*/
|
||||
usleep(100);
|
||||
|
||||
/* let's pretend we have 2000 samples per second */
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
}
|
||||
} else {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
LOG_I(UTIL, "client/server: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n", rlc_tick_count, pdcp_tick_count, x2ap_tick_count);
|
||||
|
||||
if (iq_samples_time_source)
|
||||
return rlc_tick_count == 1000
|
||||
&& pdcp_tick_count == 1000
|
||||
&& x2ap_tick_count == 1000;
|
||||
else
|
||||
/* let's accept 1% deviation from the 1000 counts we expect */
|
||||
return abs(rlc_tick_count-1000) < 10
|
||||
&& abs(pdcp_tick_count - 1000) < 10
|
||||
&& abs(x2ap_tick_count - 1000) < 10;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == NULL) {
|
||||
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
|
||||
}
|
||||
logInit();
|
||||
|
||||
/* for client/server tests, we use sub-processes with command line parameters */
|
||||
if (argc > 1) {
|
||||
/* if there are command line parameters then it's a sub-process */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
/* return value to the main test program
|
||||
* let's do as for the shell: 0 means success and 1 means error
|
||||
*/
|
||||
/* we know we are in iq-samples time source mode if the last argument is "iq_samples" */
|
||||
int success = run_sub_client_server(!strcmp(argv[argc - 1], "iq_samples")) == 1;
|
||||
return 1 - success;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
|
||||
/* test standalone realtime */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
int ret = standalone_realtime();
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "standalone realtime: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "standalone realtime: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* test standalone iq-samples */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
ret = standalone_iq_samples();
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "standalone iq-samples: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "standalone iq-samples: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* client/server tests are not written in a robust way
|
||||
* they may fail depending on realtime on the machine
|
||||
* de-activate if needed (if CI fails)
|
||||
*/
|
||||
/* test client/server realtime */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
ret = client_server(argv[0], false);
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "client-server realtime: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "client-server realtime: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* test client/server iq-samples */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
ret = client_server(argv[0], true);
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "client-server iq-samples: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "client-server iq-samples: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
logTerm();
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "../time_source.h"
|
||||
#include "../time_server.h"
|
||||
#include "../time_client.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
printf("%s:%d:%s: %s\n", file, line, function, s);
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_Atomic bool test_exit;
|
||||
|
||||
static void *iq_generate_thread(void *ts)
|
||||
{
|
||||
time_source_t *time_source = ts;
|
||||
|
||||
while (!test_exit) {
|
||||
printf("iq_generate_thread calls time_source_iq_add(time_source, 100, 10000)\n");
|
||||
time_source_iq_add(time_source, 100, 10000);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define STANDALONE 0
|
||||
#define SERVER 1
|
||||
#define CLIENT 2
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("options:\n");
|
||||
printf(" -client\n");
|
||||
printf(" run as client (default is standalone)\n");
|
||||
printf(" -server\n");
|
||||
printf(" run as server (default is standalone)\n");
|
||||
printf(" -ip <ip address (default 127.0.0.1)>\n");
|
||||
printf(" use this ip address for server\n");
|
||||
printf(" -port <port (default 7473)\n");
|
||||
printf(" use this port for server\n");
|
||||
printf(" -realtime\n");
|
||||
printf(" run with realtime clock (default is simulated iq samples)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void server_callback(void *callback_data)
|
||||
{
|
||||
printf("server_callback called (callback_data %p)\n", callback_data);
|
||||
DevAssert(callback_data == (void *)1);
|
||||
}
|
||||
|
||||
static void client_callback(void *callback_data)
|
||||
{
|
||||
printf("client_callback called (callback_data %p)\n", callback_data);
|
||||
DevAssert(callback_data == (void *)2);
|
||||
}
|
||||
|
||||
/* dummy sig handler to quit immediately when pressing enter
|
||||
* (we send a signal to iq_generate_thread to interrupt sleep())
|
||||
*/
|
||||
static void sig_handle(int n)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
time_source_t *ts = NULL;
|
||||
time_server_t *server = NULL;
|
||||
time_client_t *client = NULL;
|
||||
int mode = STANDALONE;
|
||||
char *server_ip = "127.0.0.1";
|
||||
int server_port = 7473;
|
||||
time_source_type_t time_source_type = TIME_SOURCE_IQ_SAMPLES;
|
||||
pthread_t iq_thread;
|
||||
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-client")) { mode = CLIENT; continue; }
|
||||
if (!strcmp(v[i], "-server")) { mode = SERVER; continue; }
|
||||
if (!strcmp(v[i], "-ip")) { if (i>n-2) usage(); server_ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-port")) { if (i>n-2) usage(); server_port = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-realtime")) { time_source_type = TIME_SOURCE_REALTIME; continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
logInit();
|
||||
/* hack: set log to info (logInit doesn't do it because we don't call load_configmodule()) */
|
||||
for (int i = 0; i < MAX_LOG_COMPONENTS; i++)
|
||||
g_log->log_component[i].level = OAILOG_INFO;
|
||||
|
||||
if (mode != CLIENT) {
|
||||
ts = new_time_source(time_source_type);
|
||||
if (time_source_type == TIME_SOURCE_IQ_SAMPLES) {
|
||||
void *ret = signal(SIGHUP, sig_handle);
|
||||
DevAssert(ret != SIG_ERR);
|
||||
threadCreate(&iq_thread, iq_generate_thread, ts, "iq samples generator", -1, SCHED_OAI);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == SERVER) {
|
||||
/* (void*)1 to check if callback data is passed correctly */
|
||||
server = new_time_server(server_ip, server_port, server_callback, (void *)1);
|
||||
time_server_attach_time_source(server, ts);
|
||||
}
|
||||
|
||||
if (mode == CLIENT) {
|
||||
/* (void*)2 to check if callback data is passed correctly */
|
||||
client = new_time_client(server_ip, server_port, client_callback, (void *)2);
|
||||
}
|
||||
|
||||
printf("main: press enter to quit\n");
|
||||
getchar();
|
||||
|
||||
test_exit = true;
|
||||
|
||||
if (mode != CLIENT)
|
||||
if (time_source_type == TIME_SOURCE_IQ_SAMPLES) {
|
||||
(void)pthread_kill(iq_thread, SIGHUP);
|
||||
int ret = pthread_join(iq_thread, NULL);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
if (mode != CLIENT) {
|
||||
free_time_source(ts);
|
||||
}
|
||||
|
||||
if (mode == SERVER) {
|
||||
free_time_server(server);
|
||||
}
|
||||
|
||||
if (mode == CLIENT) {
|
||||
free_time_client(client);
|
||||
}
|
||||
|
||||
logTerm();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "time_client.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/system.h"
|
||||
|
||||
typedef struct {
|
||||
pthread_t thread_id;
|
||||
int exit_fd;
|
||||
struct sockaddr_in server_ip;
|
||||
int server_port;
|
||||
void (*callback)(void *);
|
||||
void *callback_data;
|
||||
} time_client_private_t;
|
||||
|
||||
static int connect_to_server(time_client_private_t *time_client)
|
||||
{
|
||||
int sock = -1;
|
||||
int opts;
|
||||
int r;
|
||||
struct pollfd fds[2];
|
||||
|
||||
/* try forever (or exit requested) until we succeed */
|
||||
while (1) {
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
AssertFatal(sock != -1, "socket() failed: %s\n", strerror(errno));
|
||||
int v = 1;
|
||||
r = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
|
||||
AssertFatal(r == 0, "setsockopt() failed: %s\n", strerror(errno));
|
||||
/* unblock socket */
|
||||
opts = fcntl(sock, F_GETFL);
|
||||
AssertFatal(opts >= 0, "fcntl() failed: %s\n", strerror(errno));
|
||||
opts |= O_NONBLOCK;
|
||||
r = fcntl(sock, F_SETFL, opts);
|
||||
AssertFatal(r == 0, "fctnl() failed: %s\n", strerror(errno));
|
||||
if (connect(sock, (struct sockaddr *)&time_client->server_ip, sizeof(time_client->server_ip)) == 0)
|
||||
break;
|
||||
if (errno == EINPROGRESS) {
|
||||
/* connection not completed yet, we need to wait */
|
||||
fds[0].fd = sock;
|
||||
fds[0].events = POLLOUT;
|
||||
fds[1].fd = time_client->exit_fd;
|
||||
fds[1].events = POLLIN;
|
||||
r = poll(fds, 2, -1);
|
||||
AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno));
|
||||
/* do we need to exit? */
|
||||
if (fds[1].revents) {
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
}
|
||||
/* check if connection is successful */
|
||||
if (fds[0].revents & POLLOUT) {
|
||||
int so_error;
|
||||
socklen_t so_error_len = sizeof(so_error);
|
||||
r = getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
|
||||
AssertFatal(r == 0 && so_error_len == sizeof(so_error),
|
||||
"getsockopt() failed (r = %d) or so_error_len (= %d) is not %ld\n",
|
||||
r, so_error_len, sizeof(so_error));
|
||||
if (so_error == 0)
|
||||
/* success */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* connection failed, try again in 1s (or stop if exit requested) */
|
||||
close(sock);
|
||||
sock = -1;
|
||||
char server_address[256];
|
||||
const char *ret = inet_ntop(AF_INET, &time_client->server_ip.sin_addr, server_address, sizeof(server_address));
|
||||
AssertFatal(ret != NULL, "inet_ntop() failed: %s\n", strerror(errno));
|
||||
LOG_W(UTIL, "time client: connection to %s:%d failed, try again in 1s\n", server_address, time_client->server_port);
|
||||
/* sleep 1s (or exit requested) */
|
||||
fds[0].fd = time_client->exit_fd;
|
||||
fds[0].events = POLLIN;
|
||||
r = poll(fds, 1, 1000);
|
||||
AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno));
|
||||
/* exit requested? */
|
||||
if (fds[0].revents) {
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sock != -1) {
|
||||
/* reblock socket */
|
||||
opts &= ~O_NONBLOCK;
|
||||
r = fcntl(sock, F_SETFL, opts);
|
||||
AssertFatal(r == 0, "fcntl() failed: %s\n", strerror(errno));
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void *time_client_thread(void *tc)
|
||||
{
|
||||
time_client_private_t *time_client = tc;
|
||||
int ret;
|
||||
int socket = connect_to_server(time_client);
|
||||
/* if socket is -1 at this point, it means that exit was requested */
|
||||
if (socket == -1)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
struct pollfd polls[2];
|
||||
/* polls[0] is for the socket */
|
||||
polls[0].fd = socket;
|
||||
polls[0].events = POLLIN;
|
||||
|
||||
/* polls[1] is for exit_fd */
|
||||
polls[1].fd = time_client->exit_fd;
|
||||
polls[1].events = POLLIN;
|
||||
|
||||
ret = poll(polls, 2, -1);
|
||||
AssertFatal(ret >= 0, "poll() failed: %s\n", strerror(errno));
|
||||
|
||||
/* whatever is in revents for exit_fd means exit */
|
||||
if (polls[1].revents)
|
||||
break;
|
||||
|
||||
/* is socket fine? */
|
||||
if (polls[0].revents & (POLLERR | POLLHUP)) {
|
||||
reconnect:
|
||||
/* socket not fine, reconnect */
|
||||
shutdown(socket, SHUT_RDWR);
|
||||
close(socket);
|
||||
socket = connect_to_server(time_client);
|
||||
/* connect only fails if exit requested, we can safely 'continue' */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* here we only accept POLLIN */
|
||||
AssertFatal(polls[0].revents == POLLIN, "poll() did not return expected POLLIN\n");
|
||||
|
||||
/* get the ticks from server */
|
||||
uint8_t tick_count;
|
||||
ret = read(socket, &tick_count, 1);
|
||||
/* any error => reconnect */
|
||||
if (ret == -1) {
|
||||
LOG_E(UTIL, "time client: error %s, reconnect\n", strerror(errno));
|
||||
goto reconnect;
|
||||
}
|
||||
/* if 0 is returned, it means socket has been closed by other end */
|
||||
if (ret == 0) {
|
||||
LOG_E(UTIL, "time client: socket closed by other end, reconnect\n");
|
||||
goto reconnect;
|
||||
}
|
||||
DevAssert(ret == 1);
|
||||
|
||||
/* call callback once for each tick */
|
||||
for (int i = 0; i < tick_count; i++)
|
||||
time_client->callback(time_client->callback_data);
|
||||
}
|
||||
|
||||
shutdown(socket, SHUT_RDWR);
|
||||
close(socket);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_client_t *new_time_client(const char *server_ip,
|
||||
int server_port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
time_client_private_t *tc;
|
||||
int ret;
|
||||
|
||||
tc = calloc_or_fail(1, sizeof(*tc));
|
||||
|
||||
tc->exit_fd = eventfd(0, 0);
|
||||
AssertFatal(tc->exit_fd != -1, "eventfd() failed: %s\n", strerror(errno));
|
||||
|
||||
ret = inet_aton(server_ip, &tc->server_ip.sin_addr);
|
||||
AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno));
|
||||
tc->server_ip.sin_family = AF_INET;
|
||||
tc->server_ip.sin_port = htons(server_port);
|
||||
tc->server_port = server_port;
|
||||
tc->callback = callback;
|
||||
tc->callback_data = callback_data;
|
||||
|
||||
threadCreate(&tc->thread_id, time_client_thread, tc, "time client", -1, SCHED_OAI);
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
void free_time_client(time_client_t *tc)
|
||||
{
|
||||
time_client_private_t *time_client = tc;
|
||||
|
||||
uint64_t v = 1;
|
||||
int ret = write(time_client->exit_fd, &v, 8);
|
||||
DevAssert(ret == 8);
|
||||
|
||||
ret = pthread_join(time_client->thread_id, NULL);
|
||||
DevAssert(ret == 0);
|
||||
|
||||
close(time_client->exit_fd);
|
||||
free(time_client);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef COMMON_UTIL_TIME_MANAGER_TIME_CLIENT
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_CLIENT
|
||||
|
||||
/* opaque data type */
|
||||
typedef void time_client_t;
|
||||
|
||||
time_client_t *new_time_client(const char *server_ip,
|
||||
int server_port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
|
||||
void free_time_client(time_client_t *time_client);
|
||||
|
||||
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_CLIENT */
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "time_manager.h"
|
||||
|
||||
#include "time_source.h"
|
||||
#include "time_server.h"
|
||||
#include "time_client.h"
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
/* global variables (some may be ununsed, depends on configuration) */
|
||||
static time_source_t *time_source = NULL;
|
||||
static time_server_t *time_server = NULL;
|
||||
static time_client_t *time_client = NULL;
|
||||
|
||||
/* tick functions registered at initialization of the time manager */
|
||||
static time_manager_tick_function_t *tick_functions;
|
||||
static int tick_functions_count;
|
||||
|
||||
/* tick callback, called by time_source every 'millisecond' (can be
|
||||
* actual millisecond or simulated millisecond)
|
||||
*/
|
||||
static void tick(void *unused)
|
||||
{
|
||||
for (int i = 0; i < tick_functions_count; i++)
|
||||
tick_functions[i]();
|
||||
}
|
||||
|
||||
#define TIME_SOURCE "time_source"
|
||||
#define MODE "mode"
|
||||
#define SERVER_IP "server_ip"
|
||||
#define SERVER_PORT "server_port"
|
||||
|
||||
static paramdef_t config_parameters[] = {
|
||||
{TIME_SOURCE, "time source", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{MODE, "time mode", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{SERVER_IP, "server ip", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{SERVER_PORT, "server port", 0, .iptr = NULL, .defintval = -1, TYPE_INT, 0},
|
||||
};
|
||||
|
||||
static char *get_param_str(char *name)
|
||||
{
|
||||
int idx = config_paramidx_fromname(config_parameters, sizeofArray(config_parameters), name);
|
||||
|
||||
char *param;
|
||||
if (config_parameters[idx].strptr != NULL)
|
||||
param = *config_parameters[idx].strptr;
|
||||
else
|
||||
param = NULL;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
static int get_param_int(char *name)
|
||||
{
|
||||
int idx = config_paramidx_fromname(config_parameters, sizeofArray(config_parameters), name);
|
||||
|
||||
return *config_parameters[idx].iptr;
|
||||
}
|
||||
|
||||
void time_manager_start(time_manager_tick_function_t *_tick_functions,
|
||||
int _tick_functions_count,
|
||||
time_source_type_t time_source_type)
|
||||
{
|
||||
bool has_time_server = false;
|
||||
bool has_time_client = false;
|
||||
char *default_server_ip = "127.0.0.1";
|
||||
int default_server_port = 7374;
|
||||
char *server_ip = NULL;
|
||||
int server_port = -1;
|
||||
|
||||
tick_functions_count = _tick_functions_count;
|
||||
tick_functions = calloc_or_fail(tick_functions_count, sizeof(*tick_functions));
|
||||
memcpy(tick_functions, _tick_functions, tick_functions_count * sizeof(*tick_functions));
|
||||
|
||||
/* retrieve configuration */
|
||||
int ret = config_get(config_get_if(), config_parameters, sizeofArray(config_parameters), "time_management");
|
||||
if (ret >= 0) {
|
||||
char *param;
|
||||
|
||||
/* time source */
|
||||
param = get_param_str(TIME_SOURCE);
|
||||
if (param != NULL) {
|
||||
if (!strcmp(param, "realtime")) {
|
||||
time_source_type = TIME_SOURCE_REALTIME;
|
||||
} else if (!strcmp(param, "iq_samples")) {
|
||||
time_source_type = TIME_SOURCE_IQ_SAMPLES;
|
||||
} else {
|
||||
AssertFatal(0, "bad parameter 'time_source' in section 'time_management', unknown value \"%s\". Valid values are \"realtime\" and \"iq_samples\"\n", param);
|
||||
}
|
||||
}
|
||||
|
||||
/* mode */
|
||||
param = get_param_str(MODE);
|
||||
if (param != NULL) {
|
||||
if (!strcmp(param, "standalone")) {
|
||||
has_time_server = false;
|
||||
has_time_client = false;
|
||||
} else if (!strcmp(param, "server")) {
|
||||
has_time_server = true;
|
||||
has_time_client = false;
|
||||
} else if (!strcmp(param, "client")) {
|
||||
has_time_server = false;
|
||||
has_time_client = true;
|
||||
} else {
|
||||
AssertFatal(0, "bad parameter 'mode' in section 'time_management', unknown value \"%s\". Valid values are \"standalone\", \"server\" and \"client\"\n", param);
|
||||
}
|
||||
}
|
||||
|
||||
/* server ip */
|
||||
param = get_param_str(SERVER_IP);
|
||||
if (param != NULL) {
|
||||
server_ip = param;
|
||||
}
|
||||
|
||||
/* server port */
|
||||
int port = get_param_int(SERVER_PORT);
|
||||
if (port != -1) {
|
||||
server_port = port;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_ip == NULL)
|
||||
server_ip = default_server_ip;
|
||||
|
||||
if (server_port == -1)
|
||||
server_port = default_server_port;
|
||||
|
||||
/* create entities, according to selected configuration */
|
||||
if (!has_time_client) {
|
||||
time_source = new_time_source(time_source_type);
|
||||
time_source_set_callback(time_source, tick, NULL);
|
||||
}
|
||||
|
||||
if (has_time_server) {
|
||||
time_server = new_time_server(server_ip, server_port, tick, NULL);
|
||||
time_server_attach_time_source(time_server, time_source);
|
||||
}
|
||||
|
||||
if (has_time_client) {
|
||||
time_client = new_time_client(server_ip, server_port, tick, NULL);
|
||||
/* for the log below, there is no time source, we want to print 'server' as time source */
|
||||
time_source_type = 2;
|
||||
}
|
||||
|
||||
LOG_I(UTIL,
|
||||
"time manager configuration: [time source: %s] [mode: %s] [server IP: %s} [server port: %d]%s\n",
|
||||
(char *[]){"reatime", "iq_samples", "server"}[time_source_type],
|
||||
has_time_server ? "server"
|
||||
: has_time_client ? "client"
|
||||
: "standalone",
|
||||
server_ip,
|
||||
server_port,
|
||||
has_time_server || has_time_client ? "" : " (server IP/port not used)");
|
||||
}
|
||||
|
||||
void time_manager_iq_samples(uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
{
|
||||
time_source_iq_add(time_source, iq_samples_count, iq_samples_per_second);
|
||||
}
|
||||
|
||||
void time_manager_finish(void)
|
||||
{
|
||||
/* time source has to be shutdown first */
|
||||
if (time_source != NULL) {
|
||||
free_time_source(time_source);
|
||||
time_source = NULL;
|
||||
}
|
||||
|
||||
if (time_server != NULL) {
|
||||
free_time_server(time_server);
|
||||
time_server = NULL;
|
||||
}
|
||||
|
||||
if (time_client != NULL) {
|
||||
free_time_client(time_client);
|
||||
time_client = NULL;
|
||||
}
|
||||
|
||||
free(tick_functions);
|
||||
tick_functions = NULL;
|
||||
tick_functions_count = 0;
|
||||
}
|
||||
+11
-31
@@ -19,40 +19,20 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file FGSRegistrationResult.c
|
||||
#ifndef COMMON_UTIL_TIME_MANAGER_TIME_MANAGER
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_MANAGER
|
||||
|
||||
\brief 5GS Registration result for registration request procedures
|
||||
\author Yoshio INOUE, Masayuki HARADA
|
||||
\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
|
||||
\date 2020
|
||||
\version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "TLVEncoder.h"
|
||||
#include "TLVDecoder.h"
|
||||
#include "FGSRegistrationResult.h"
|
||||
#include "time_source.h"
|
||||
|
||||
int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len)
|
||||
{
|
||||
int decoded = 0;
|
||||
uint16_t *buffer = &value;
|
||||
fgsregistrationresult->registrationresult = *buffer & 0x7;
|
||||
fgsregistrationresult->smsallowed = *buffer & 0x8;
|
||||
decoded = decoded + 2;
|
||||
return decoded;
|
||||
}
|
||||
typedef void (*time_manager_tick_function_t)(void);
|
||||
|
||||
uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult)
|
||||
{
|
||||
uint16_t bufferReturn;
|
||||
uint16_t *buffer = &bufferReturn;
|
||||
uint8_t encoded = 0;
|
||||
*(buffer + encoded) = 0x00 | (fgsregistrationresult->smsallowed & 0x8) | (fgsregistrationresult->registrationresult & 0x7);
|
||||
encoded = encoded + 2;
|
||||
void time_manager_start(time_manager_tick_function_t *tick_functions,
|
||||
int tick_functions_count,
|
||||
time_source_type_t time_source);
|
||||
void time_manager_iq_samples(uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second);
|
||||
void time_manager_finish(void);
|
||||
|
||||
return bufferReturn;
|
||||
}
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_MANAGER */
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "time_server.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
typedef struct {
|
||||
pthread_t thread_id;
|
||||
_Atomic bool exit;
|
||||
int server_socket;
|
||||
int tick_fd;
|
||||
void (*callback)(void *);
|
||||
void *callback_data;
|
||||
} time_server_private_t;
|
||||
|
||||
static void *time_server_thread(void *ts)
|
||||
{
|
||||
time_server_private_t *time_server = ts;
|
||||
struct pollfd *polls = NULL;
|
||||
int *socket_fds = NULL;
|
||||
int client_count = 0;
|
||||
|
||||
polls = calloc_or_fail(2, sizeof(struct pollfd));
|
||||
|
||||
while (!time_server->exit) {
|
||||
/* polls[0] is to receive ticks */
|
||||
polls[0].fd = time_server->tick_fd;
|
||||
polls[0].events = POLLIN;
|
||||
/* polls[1] is to accept connections from clients */
|
||||
polls[1].fd = time_server->server_socket;
|
||||
polls[1].events = POLLIN;
|
||||
|
||||
/* add clients */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
polls[i + 2].fd = socket_fds[i];
|
||||
polls[i + 2].events = POLLIN;
|
||||
}
|
||||
|
||||
int ret = poll(polls, client_count + 2, -1);
|
||||
AssertFatal(ret >= 1 || (ret == -1 && errno == EINTR), "poll() failed\n");
|
||||
|
||||
if (time_server->exit)
|
||||
break;
|
||||
|
||||
/* check tick */
|
||||
if (polls[0].revents) {
|
||||
/* do not accept errors */
|
||||
AssertFatal(polls[0].revents == POLLIN, "poll() failed\n");
|
||||
uint64_t ticks;
|
||||
int ret = read(time_server->tick_fd, &ticks, 8);
|
||||
DevAssert(ret == 8);
|
||||
/* call the callback ticks time */
|
||||
for (int i = 0; i < ticks; i++)
|
||||
time_server->callback(time_server->callback_data);
|
||||
/* send ticks by blocks of 255 max (what fits in a uint8_t) */
|
||||
while (ticks) {
|
||||
/* get min(ticks, 255) */
|
||||
uint8_t count = ticks < 255 ? ticks : 255;
|
||||
/* send to all clients */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
if (write(socket_fds[i], &count, 1) == 1)
|
||||
continue;
|
||||
|
||||
/* error writing - remove client */
|
||||
LOG_W(UTIL, "time server: client disconnects\n");
|
||||
shutdown(socket_fds[i], SHUT_RDWR);
|
||||
close(socket_fds[i]);
|
||||
client_count--;
|
||||
i--;
|
||||
if (client_count == 0) {
|
||||
free(socket_fds);
|
||||
socket_fds = NULL;
|
||||
} else {
|
||||
memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1));
|
||||
socket_fds = realloc(socket_fds, sizeof(int) * client_count);
|
||||
}
|
||||
polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2));
|
||||
AssertFatal(polls != NULL, "realloc() failed\n");
|
||||
}
|
||||
ticks -= count;
|
||||
}
|
||||
}
|
||||
|
||||
/* check new client */
|
||||
if (polls[1].revents) {
|
||||
/* do not accept errors */
|
||||
AssertFatal(polls[1].revents == POLLIN, "poll() failed\n");
|
||||
|
||||
int new_socket = accept(time_server->server_socket, NULL, NULL);
|
||||
AssertFatal(new_socket != -1, "accept() failed: %s\n", strerror(errno));
|
||||
|
||||
/* add client */
|
||||
client_count++;
|
||||
socket_fds = realloc(socket_fds, sizeof(int) * client_count);
|
||||
AssertFatal(socket_fds != NULL, "realloc() failed\n");
|
||||
socket_fds[client_count - 1] = new_socket;
|
||||
polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2));
|
||||
AssertFatal(polls != NULL, "realloc() failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* any event on a client socket is to be considered as an error */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
if (polls[i + 2].revents == 0)
|
||||
continue;
|
||||
|
||||
LOG_W(UTIL,
|
||||
"time server: error on client's socket, removing client (revents is %d, fd is %d i is %d)\n",
|
||||
polls[i + 2].revents,
|
||||
polls[i + 2].fd,
|
||||
i);
|
||||
shutdown(socket_fds[i], SHUT_RDWR);
|
||||
close(socket_fds[i]);
|
||||
client_count--;
|
||||
i--;
|
||||
if (client_count == 0) {
|
||||
free(socket_fds);
|
||||
socket_fds = NULL;
|
||||
} else {
|
||||
memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1));
|
||||
socket_fds = realloc(socket_fds, sizeof(int) * client_count);
|
||||
AssertFatal(socket_fds != NULL, "realloco() failed\n");
|
||||
}
|
||||
if (client_count)
|
||||
memmove(&polls[i + 2 + 1], &polls[i + 2 + 2], sizeof(struct pollfd) * (client_count - i - 1));
|
||||
polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2));
|
||||
AssertFatal(polls != NULL, "realloc() failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* close all clients' sockets */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
shutdown(socket_fds[i], SHUT_RDWR);
|
||||
close(socket_fds[i]);
|
||||
}
|
||||
|
||||
free(polls);
|
||||
free(socket_fds);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_server_t *new_time_server(const char *ip,
|
||||
int port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
time_server_private_t *ts;
|
||||
int ret;
|
||||
|
||||
ts = calloc_or_fail(1, sizeof(*ts));
|
||||
|
||||
ts->server_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
AssertFatal(ts->server_socket != -1, "socket() failed: %s\n", strerror(errno));
|
||||
|
||||
int v = 1;
|
||||
ret = setsockopt(ts->server_socket, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
|
||||
AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno));
|
||||
v = 1;
|
||||
ret = setsockopt(ts->server_socket, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
|
||||
AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno));
|
||||
ts->tick_fd = eventfd(0, 0);
|
||||
AssertFatal(ts->tick_fd != -1, "eventfd() failed: %s\n", strerror(errno));
|
||||
|
||||
struct sockaddr_in ip_addr;
|
||||
ip_addr.sin_family = AF_INET;
|
||||
ip_addr.sin_port = htons(port);
|
||||
ret = inet_aton(ip, &ip_addr.sin_addr);
|
||||
AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno));
|
||||
ret = bind(ts->server_socket, (struct sockaddr *)&ip_addr, sizeof(ip_addr));
|
||||
AssertFatal(ret == 0, "bind() failed: %s\n", strerror(errno));
|
||||
|
||||
ret = listen(ts->server_socket, 10); /* 10: arbitrary value */
|
||||
AssertFatal(ret == 0, "listen() failed: %s\n", strerror(errno));
|
||||
|
||||
ts->callback = callback;
|
||||
ts->callback_data = callback_data;
|
||||
|
||||
threadCreate(&ts->thread_id, time_server_thread, ts, "time server", -1, SCHED_OAI);
|
||||
return ts;
|
||||
}
|
||||
|
||||
void free_time_server(time_server_t *ts)
|
||||
{
|
||||
time_server_private_t *time_server = ts;
|
||||
|
||||
/* flag exit */
|
||||
time_server->exit = true;
|
||||
|
||||
/* send a fake tick to wake up the server thread */
|
||||
uint64_t v = 1;
|
||||
int ret = write(time_server->tick_fd, &v, 8);
|
||||
DevAssert(ret == 8);
|
||||
|
||||
/* wait for thread termination */
|
||||
void *retval;
|
||||
ret = pthread_join(time_server->thread_id, &retval);
|
||||
|
||||
/* free memory */
|
||||
shutdown(time_server->server_socket, SHUT_RDWR);
|
||||
close(time_server->server_socket);
|
||||
close(time_server->tick_fd);
|
||||
free(time_server);
|
||||
}
|
||||
|
||||
static void time_server_tick_callback(void *ts)
|
||||
{
|
||||
time_server_private_t *time_server = ts;
|
||||
uint64_t v = 1;
|
||||
int ret = write(time_server->tick_fd, &v, 8);
|
||||
DevAssert(ret == 8);
|
||||
}
|
||||
|
||||
void time_server_attach_time_source(time_server_t *time_server,
|
||||
time_source_t *time_source)
|
||||
{
|
||||
time_source_set_callback(time_source, time_server_tick_callback, time_server);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef COMMON_UTIL_TIME_MANAGER_TIME_SERVER
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_SERVER
|
||||
|
||||
#include "time_source.h"
|
||||
|
||||
/* opaque data type */
|
||||
typedef void time_server_t;
|
||||
|
||||
time_server_t *new_time_server(const char *ip,
|
||||
int port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
void free_time_server(time_server_t *time_server);
|
||||
|
||||
void time_server_attach_time_source(time_server_t *time_server,
|
||||
time_source_t *time_source);
|
||||
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_SERVER */
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "time_source.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/utils.h"
|
||||
|
||||
typedef void (*callback_function_t)(void *callback_data);
|
||||
typedef void * callback_data_t;
|
||||
|
||||
typedef struct {
|
||||
time_source_type_t type;
|
||||
volatile callback_function_t callback;
|
||||
volatile callback_data_t callback_data;
|
||||
_Atomic bool exit;
|
||||
void (*terminate)(void *this);
|
||||
pthread_t thread_id;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
} time_source_common_t;
|
||||
|
||||
typedef struct {
|
||||
time_source_common_t common;
|
||||
} time_source_realtime_t;
|
||||
|
||||
typedef struct {
|
||||
time_source_common_t common;
|
||||
volatile uint64_t iq_samples_count;
|
||||
volatile uint64_t iq_samples_per_second;
|
||||
} time_source_iq_t;
|
||||
|
||||
static void init_mutex(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_mutex_init(&t->mutex, NULL);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void init_cond(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_cond_init(&t->cond, NULL);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void lock(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_mutex_lock(&t->mutex);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void unlock(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_mutex_unlock(&t->mutex);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void condwait(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_cond_wait(&t->cond, &t->mutex);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void condsignal(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_cond_signal(&t->cond);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void wait_thread_termination(time_source_common_t *t)
|
||||
{
|
||||
void *retval;
|
||||
int ret = pthread_join(t->thread_id, &retval);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static struct timespec next_ms(struct timespec t)
|
||||
{
|
||||
/* go to next millisecond */
|
||||
t.tv_nsec += 1000000;
|
||||
if (t.tv_nsec > 999999999) {
|
||||
t.tv_nsec -= 1000000000;
|
||||
t.tv_sec++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void *time_source_realtime_thread(void *ts)
|
||||
{
|
||||
time_source_realtime_t *time_source = ts;
|
||||
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
|
||||
AssertFatal(0, "clock_gettime failed\n");
|
||||
|
||||
/* go to next millisecond */
|
||||
now = next_ms(now);
|
||||
|
||||
while (!time_source->common.exit) {
|
||||
/* sleep */
|
||||
if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &now, NULL) == -1) {
|
||||
/* accept interruption by signals and then simply restart the sleep */
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
AssertFatal(0, "clock_nanosleep failed\n");
|
||||
}
|
||||
|
||||
if (time_source->common.exit)
|
||||
break;
|
||||
|
||||
/* tick */
|
||||
lock(&time_source->common);
|
||||
void (*callback)(void *callback_data) = time_source->common.callback;
|
||||
void *callback_data = time_source->common.callback_data;
|
||||
unlock(&time_source->common);
|
||||
if (callback != NULL)
|
||||
callback(callback_data);
|
||||
|
||||
/* go to next millisecond */
|
||||
now = next_ms(now);
|
||||
}
|
||||
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
static void *time_source_iq_samples_thread(void *ts)
|
||||
{
|
||||
time_source_iq_t *time_source = ts;
|
||||
|
||||
while (!time_source->common.exit) {
|
||||
/* wait until we have at least 1ms of IQ samples */
|
||||
lock(&time_source->common);
|
||||
while (!time_source->common.exit
|
||||
&& (time_source->iq_samples_per_second == 0
|
||||
|| time_source->iq_samples_count < time_source->iq_samples_per_second / 1000))
|
||||
condwait(&time_source->common);
|
||||
time_source->iq_samples_count -= time_source->iq_samples_per_second / 1000;
|
||||
unlock(&time_source->common);
|
||||
|
||||
if (time_source->common.exit)
|
||||
break;
|
||||
|
||||
/* tick */
|
||||
lock(&time_source->common);
|
||||
void (*callback)(void *callback_data) = time_source->common.callback;
|
||||
void *callback_data = time_source->common.callback_data;
|
||||
unlock(&time_source->common);
|
||||
if (callback != NULL)
|
||||
callback(callback_data);
|
||||
}
|
||||
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
static void time_source_iq_samples_terminate(void *ts)
|
||||
{
|
||||
time_source_iq_t *time_source = ts;
|
||||
condsignal(&time_source->common);
|
||||
}
|
||||
|
||||
time_source_t *new_time_source(time_source_type_t type)
|
||||
{
|
||||
time_source_t *ret = NULL;
|
||||
void *(*thread_function)(void *) = NULL;
|
||||
void (*terminate_function)(void *) = NULL;
|
||||
char *thread_function_name = NULL;
|
||||
|
||||
switch (type) {
|
||||
case TIME_SOURCE_REALTIME: {
|
||||
time_source_realtime_t *ts = calloc_or_fail(1, sizeof(*ts));
|
||||
thread_function = time_source_realtime_thread;
|
||||
thread_function_name = "time source realtime";
|
||||
ret = ts;
|
||||
break;
|
||||
}
|
||||
case TIME_SOURCE_IQ_SAMPLES: {
|
||||
time_source_iq_t *ts = calloc_or_fail(1, sizeof(*ts));
|
||||
thread_function = time_source_iq_samples_thread;
|
||||
terminate_function = time_source_iq_samples_terminate;
|
||||
thread_function_name = "time source iq samples";
|
||||
ret = ts;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
time_source_common_t *c = ret;
|
||||
c->type = type;
|
||||
init_mutex(c);
|
||||
init_cond(c);
|
||||
c->terminate = terminate_function;
|
||||
threadCreate(&c->thread_id, thread_function, c, thread_function_name, -1, SCHED_OAI);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free_time_source(time_source_t *ts)
|
||||
{
|
||||
time_source_common_t *time_source = ts;
|
||||
time_source->exit = true;
|
||||
if (time_source->terminate != NULL)
|
||||
time_source->terminate(time_source);
|
||||
wait_thread_termination(time_source);
|
||||
free(time_source);
|
||||
}
|
||||
|
||||
void time_source_set_callback(time_source_t *ts,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
time_source_common_t *time_source = ts;
|
||||
lock(time_source);
|
||||
time_source->callback = callback;
|
||||
time_source->callback_data = callback_data;
|
||||
unlock(time_source);
|
||||
}
|
||||
|
||||
void time_source_iq_add(time_source_t *ts,
|
||||
uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
{
|
||||
if (ts == NULL)
|
||||
return;
|
||||
|
||||
time_source_iq_t *time_source = ts;
|
||||
|
||||
if (time_source->common.type != TIME_SOURCE_IQ_SAMPLES)
|
||||
return;
|
||||
|
||||
lock(&time_source->common);
|
||||
|
||||
time_source->iq_samples_count += iq_samples_count;
|
||||
|
||||
if (time_source->iq_samples_per_second == 0)
|
||||
time_source->iq_samples_per_second = iq_samples_per_second;
|
||||
AssertFatal(time_source->iq_samples_per_second == iq_samples_per_second, "unsupported change of value 'IQ samples per second'\n");
|
||||
|
||||
condsignal(&time_source->common);
|
||||
unlock(&time_source->common);
|
||||
}
|
||||
+18
-26
@@ -19,37 +19,29 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file FGSRegistrationResult.h
|
||||
#ifndef COMMON_UTIL_TIME_MANAGER_TIME_SOURCE
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_SOURCE
|
||||
|
||||
\brief 5GS Registration result for registration request procedures
|
||||
\author Yoshio INOUE, Masayuki HARADA
|
||||
\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
|
||||
\date 2020
|
||||
\version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "OctetString.h"
|
||||
/* opaque data type */
|
||||
typedef void time_source_t;
|
||||
|
||||
#ifndef FGS_REGISTRATION_RESULT_H_
|
||||
#define FGS_REGISTRATION_RESULT_H_
|
||||
#define FGS_REGISTRATION_RESULT_3GPP 0b001
|
||||
#define FGS_REGISTRATION_RESULT_NON_3GPP 0b010
|
||||
#define FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP 0b011
|
||||
typedef enum {
|
||||
TIME_SOURCE_REALTIME,
|
||||
TIME_SOURCE_IQ_SAMPLES
|
||||
} time_source_type_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t iei;
|
||||
uint8_t resultlength;
|
||||
uint8_t spare: 4;
|
||||
uint8_t smsallowed: 1;
|
||||
uint8_t registrationresult: 3;
|
||||
} FGSRegistrationResult;
|
||||
time_source_t *new_time_source(time_source_type_t type);
|
||||
|
||||
uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult);
|
||||
void free_time_source(time_source_t *time_source);
|
||||
|
||||
int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len);
|
||||
void time_source_set_callback(time_source_t *time_source,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
|
||||
#endif /* FGS REGISTRATION RESULT_H_*/
|
||||
void time_source_iq_add(time_source_t *time_source,
|
||||
uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second);
|
||||
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_SOURCE */
|
||||
+23
-5
@@ -38,7 +38,7 @@
|
||||
int nas_sock_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE.
|
||||
int nas_sock_mbms_fd;
|
||||
|
||||
static int tun_alloc(const char *dev)
|
||||
int tun_alloc(const char *dev)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd, err;
|
||||
@@ -157,13 +157,14 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief bring interface up (up != 0) or down (up == 0)
|
||||
*/
|
||||
|
||||
typedef enum { INTERFACE_DOWN, INTERFACE_UP } if_action_t;
|
||||
/*
|
||||
* \brief bring interface up (up != 0) or down (up == 0)
|
||||
*/
|
||||
static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_action)
|
||||
{
|
||||
const char* action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
|
||||
const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
|
||||
|
||||
struct ifreq ifr = {0};
|
||||
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
|
||||
@@ -189,6 +190,7 @@ fail_interface_state:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
|
||||
{
|
||||
AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n");
|
||||
@@ -262,3 +264,19 @@ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id)
|
||||
{
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1);
|
||||
}
|
||||
|
||||
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id)
|
||||
{
|
||||
char pdu_session_string[10];
|
||||
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
}
|
||||
|
||||
void tun_destroy(const char *dev, int fd) {
|
||||
if (change_interface_state(fd, dev, INTERFACE_DOWN) == 0) {
|
||||
LOG_I(UTIL, "Interface %s is now down.\n", dev);
|
||||
} else {
|
||||
LOG_E(UTIL, "Could not bring interface %s down.\n", dev);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
* \param[in] instance_id unique instance number
|
||||
*/
|
||||
int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id);
|
||||
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id);
|
||||
|
||||
/*!
|
||||
* \brief This function initializes the TUN interface
|
||||
@@ -73,4 +74,18 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6);
|
||||
*/
|
||||
void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4);
|
||||
|
||||
/*!
|
||||
* \brief This function allocates a TUN interface
|
||||
* \param[in] dev name of the interface
|
||||
* \return file descriptor of the allocated interface
|
||||
*/
|
||||
int tun_alloc(const char *dev);
|
||||
|
||||
/*!
|
||||
* \brief This function destroys the TUN interface
|
||||
* \param[in] dev name of the interface
|
||||
* \param[in] fd file descriptor of the allocated interface
|
||||
*/
|
||||
void tun_destroy(const char *dev, int fd);
|
||||
|
||||
#endif /*TUN_IF_H_*/
|
||||
|
||||
@@ -250,6 +250,8 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration.
|
||||
* `do_CSIRS` (default 0): flag whether to use channel-state information
|
||||
reference signal (CSI-RS)
|
||||
* `do_SRS` (default 0): flag whether to use sounding reference signal (SRS)
|
||||
* `do_SINR` (default 0): flag whether to enable CSI reporting of SSB-SINR (introduced in rel16)
|
||||
Default setting of CSI reporting quantity is SSB-RSRP.
|
||||
* `min_rxtxtime` (default 2): minimum feedback time for UE to respond to
|
||||
transmissions (k1 and k2 in 3GPP spec)
|
||||
* `ul_prbblacklist`: PRBs that should not be used for UL scheduling. Cf with
|
||||
@@ -272,6 +274,18 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration.
|
||||
- `du_sibs` (default `[]`): list of SIBs to transmit in the cell. Currently,
|
||||
SIB19 (for NTN) is supported.
|
||||
|
||||
| DL MIMO |`do_CSIRS`|`do_SINR`| CSI report Quantity |
|
||||
| ---------------------------- | -------- | ------- | --------------------------------------------------|
|
||||
| OFF (pdsch_AntennaPorts = 1) | 0 | 0 | SSB-RSRP |
|
||||
| OFF (pdsch_AntennaPorts = 1) | 0 | 1 | SSB-SINR |
|
||||
| OFF (pdsch_AntennaPorts = 1) | 1 | 0 | CSI-Reference signal RSRP |
|
||||
| OFF (pdsch_AntennaPorts = 1) | 1 | 1 | CSI-Reference signal SINR (not supported yet) |
|
||||
| ON (pdsch_AntennaPorts > 1) | 1 | 0 | cri-RI-PMI-CQI |
|
||||
|
||||
DL-MIMO is configured using following parameters:
|
||||
`pdsch_AntennaPorts_XP` , `pdsch_AntennaPorts_N1` , `pdsch_AntennaPorts_N2`, `maxMIMO_layers`
|
||||
(see also [`RUNMODEM.md`](../RUNMODEM.md))
|
||||
|
||||
## ServingCellConfigCommon parameters
|
||||
|
||||
The `gNBs` configuration section has a big structure `servingCellConfigCommon`
|
||||
|
||||
@@ -108,6 +108,7 @@ Legacy unmaintained files:
|
||||
- The [shared object loader](../common/utils/DOC/loader.md)
|
||||
- The [threadpool](../common/utils/threadPool/thread-pool.md) used in L1
|
||||
- The [LDPC implementation](../openair1/PHY/CODING/DOC/LDPCImplementation.md) is a shared library
|
||||
- The [time management](time_management.md) module
|
||||
|
||||
## Radios
|
||||
|
||||
|
||||
+2
-2
@@ -298,7 +298,7 @@ Even, a future evolution could remove this global rlc layer: rlc can be only a l
|
||||
When adding a UE, external code have to call `add_rlc_srb()` and/or `add_rlc_drb()`, to remove it: `rrc_rlc_remove_ue()`
|
||||
Inside UE, channels called drd or srb can be created: ??? and deleted: rrc_rlc_config_req()
|
||||
|
||||
nr_rlc_tick() must be called periodically to manage the internal timers
|
||||
nr_rlc_ms_tick() must be called periodically to manage the internal timers
|
||||
|
||||
successful_delivery() and max_retx_reached(): in ??? trigger, the RLC sends a itti message to RRC: RLC_SDU_INDICATION (neutralized by #if 0 right now)
|
||||
|
||||
@@ -329,7 +329,7 @@ To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in
|
||||
|
||||
## PDCP Tx flow
|
||||
|
||||
On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `enb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`.
|
||||
On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `gnb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`.
|
||||
|
||||
## PDCP Rx flow
|
||||
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
# Time management module
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
## Introduction
|
||||
|
||||
Several parts of the 4G/5G protocol stack keep track of time, for example
|
||||
for timeout events (in RRC, PDCP, or RLC for example).
|
||||
|
||||
The obvious simple way to deal with time is to use the computer's realtime
|
||||
clock. This works well when we run the stack in realtime, with real
|
||||
radio equipment. But in simulation the system may run faster or slower
|
||||
than realtime, so we need another way to deal with time. A good solution
|
||||
is then to base time on the current IQ data processed by the system. So time
|
||||
becomes "IQ samples" based, not realtime.
|
||||
|
||||
The system may be decomposed into various components (CU, DU, RU, various
|
||||
UEs) running either in realtime or simulation. Time may be distributed
|
||||
to all these components from only one time source for accurate execution
|
||||
of the scenario, or each component may have its own time source, either
|
||||
based on realtime or IQ samples.
|
||||
|
||||
## Overall structure
|
||||
|
||||
The time management module is made of three main parts. The first one
|
||||
is the time source. It can either be realtime or "IQ samples" based.
|
||||
In one running scenario of the system, there can be one or more time
|
||||
sources (imagine one for the gNB, and one per each UE). There can also
|
||||
be only one time source, shared between various users of the time
|
||||
manager.
|
||||
|
||||
The second part is the server. One server is attached to one time source
|
||||
and receives a tick every millisecond (real or simulated) from the time
|
||||
source. It distributes the tick to the various connected clients.
|
||||
|
||||
And finally the last part is the client, which connects to a single server
|
||||
and receives ticks from it. The client does not have a time source attached
|
||||
to it. It gets the time from the server.
|
||||
|
||||
It is possible for a program (monolithic gNB for example) to have only
|
||||
a time source, without server or client.
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure the time management module, add the following section in
|
||||
the configuration file.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
#valid time sources: realtime, iq_samples
|
||||
time_source = realtime
|
||||
|
||||
#valid modes: standalone, server, client
|
||||
mode = standalone
|
||||
|
||||
#set ip/port of server (for server mode, this is the address/port to bind to;
|
||||
#for client mode, this is the address/port to connect to)
|
||||
server_ip = "127.0.0.1"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
|
||||
If not set in the configuration file, some default is applied, depending
|
||||
on the program run. (See the function `time_manager_start()` for details.)
|
||||
|
||||
It is also possible to pass configuration parameters on the command line.
|
||||
For example add `--time_manager.time_source iq_samples` to the command line
|
||||
to set the time source to `iq_samples`. The same syntax is applicable to the
|
||||
other parameters.
|
||||
|
||||
## Examples
|
||||
|
||||
Here come some examples of configuration for typical use cases of OAI.
|
||||
|
||||
### Monolithic gNB realtime
|
||||
|
||||
This is a very simple example. The gNB runs in `standalone` mode with
|
||||
a `realtime` time source.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = realtime
|
||||
mode = standalone
|
||||
}
|
||||
```
|
||||
### Monolithic gNB "IQ samples time"
|
||||
|
||||
For this configuration, it's the same as the previous example, but the
|
||||
time source is now `iq_samples`.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = iq_samples
|
||||
mode = standalone
|
||||
}
|
||||
```
|
||||
### RF simulator CU/DU "IQ samples time"
|
||||
|
||||
Let's suppose the CU runs on a machine with IP address 1.2.3.4 and the DU
|
||||
runs on a machine with IP address 10.11.12.13.
|
||||
|
||||
The DU has the time source and so is the server. The CU acts as a client.
|
||||
|
||||
Here comes the configuration for the CU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
mode = client
|
||||
server_ip = "10.11.12.13"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
And here is the configuration for the DU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = iq_samples
|
||||
mode = server
|
||||
server_ip = "10.11.12.13"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
|
||||
### RF simulator CU/DU "realtime"
|
||||
|
||||
Let's suppose the CU runs on a machine with IP address 1.2.3.4 and the DU
|
||||
runs on a machine with IP address 10.11.12.13.
|
||||
|
||||
CU and DU can both run in standalone mode, with no exchange between them.
|
||||
Any one of them can also acts as a server and the other one as a client.
|
||||
|
||||
Let's suppose for this example that the CU and the DU run in client/server
|
||||
mode. Let's set the CU as the time source and so as the server. The DU acts
|
||||
as a client.
|
||||
|
||||
Here comes the configuration for the CU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = realtime
|
||||
mode = server
|
||||
server_ip = "1.2.3.4"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
And here is the configuration for the DU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
mode = client
|
||||
server_ip = "1.2.3.4"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
|
||||
Note that the time management module is flexible. It's possible to
|
||||
configure more complex setups. For example the time source can be a gNB
|
||||
and several UEs can be connected as client.
|
||||
|
||||
One could also write a simple program acting as a time source and distributing
|
||||
time to everyone (one or several gNB, several UEs).
|
||||
|
||||
## Programming API
|
||||
|
||||
Here comes the internal API of the time manager module. The (simpler) OAI
|
||||
API is described afterwards.
|
||||
|
||||
### Time source
|
||||
|
||||
- opaque type: `time_source_t`
|
||||
- create a time source:
|
||||
```
|
||||
time_source_t *new_time_source(time_source_type_t type)
|
||||
```
|
||||
where `type` is one of:
|
||||
* `TIME_SOURCE_REALTIME`
|
||||
* `TIME_SOURCE_IQ_SAMPLES`
|
||||
- delete a time source:
|
||||
```
|
||||
void free_time_source(time_source_t *time_source)
|
||||
```
|
||||
- set millisecond callback:
|
||||
```
|
||||
void time_source_set_callback(time_source_t *time_source,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
```
|
||||
where `callback` is a function that will be called for each millisecond using
|
||||
the provided `callback_data`
|
||||
- for IQ samples time management, the user of the time source must call
|
||||
this function when it processes IQ samples:
|
||||
```
|
||||
void time_source_iq_add(time_source_t *time_source,
|
||||
uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
```
|
||||
then the time source will generate a tick for each block for IQ samples
|
||||
lasting one millisecond. (If you pass `iq_samples_count` lasting several
|
||||
milliseconds then the time source will generate several ticks in a row,
|
||||
one for each millisecond.)
|
||||
|
||||
### Server
|
||||
|
||||
- opaque type: `time_server_t`
|
||||
- create a server:
|
||||
```
|
||||
time_server_t *new_time_server(const char *ip,
|
||||
int port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
```
|
||||
where ip/port is the IP adress and port the server will listen to
|
||||
and `callback` is a function that will be called for each millisecond using
|
||||
the provided `callback_data`
|
||||
- delete a server:
|
||||
```
|
||||
void free_time_server(time_server_t *time_server)
|
||||
```
|
||||
- attach a time source:
|
||||
```
|
||||
void time_server_attach_time_source(time_server_t *time_server,
|
||||
time_source_t *time_source)
|
||||
```
|
||||
|
||||
### Client
|
||||
|
||||
- opaque type: `time_client_t`
|
||||
- create a client:
|
||||
```
|
||||
time_client_t *new_time_client(const char *server_ip,
|
||||
int server_port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
```
|
||||
the client will connect on given server ip/port
|
||||
and use the `callback` with `callback_data` for each tick received
|
||||
- delete a client:
|
||||
```
|
||||
void free_time_client(time_client_t *time_client)
|
||||
```
|
||||
|
||||
### Threading
|
||||
|
||||
Each component (time source, server, client) runs its own thread which will
|
||||
be the one calling the configured callback. Be careful of using proper
|
||||
synchronization techniques in your callback to have correct behavior with
|
||||
the other threads of the program.
|
||||
|
||||
## OAI API
|
||||
|
||||
OAI uses the time manager through a simplified API. All the code is contained
|
||||
in `time_manager.c`, together with some global variables (so that there is no
|
||||
need to pass objects around, to limit risks of misuse).
|
||||
|
||||
Each program (for example: gnb, ue, cu, du) calls the `time_manager_start()`
|
||||
function, passing the callback functions to be called when a tick is generated
|
||||
(several callbacks can be passed) and a default time source. Based on this,
|
||||
`time_manager_start()` initializes what is needed.
|
||||
|
||||
The function `time_manager_iq_samples()` is to be called by programs that
|
||||
read IQ samples. It is called unconditionally. It may do nothing if the
|
||||
configuration is to use realtime ticks and not IQ samples ticks.
|
||||
|
||||
When the program exits, it calls `timer_manager_finish()` which in turns stops
|
||||
the various threads created by `time_manager_start()` and releases all the
|
||||
allocated data.
|
||||
|
||||
Here comes the API.
|
||||
|
||||
- init the time manager:
|
||||
```
|
||||
void time_manager_start(time_manager_tick_function_t *tick_functions,
|
||||
int tick_functions_count,
|
||||
time_source_type_t time_source);
|
||||
```
|
||||
(for valid values of `client_type` and `running_mode` see in
|
||||
`time_manager.h`)
|
||||
- update IQ samples' based time manager:
|
||||
```
|
||||
void time_manager_iq_samples(uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
```
|
||||
- terminate the time manager:
|
||||
```
|
||||
void time_manager_finish(void)
|
||||
```
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "openair2/GNB_APP/gnb_config.h"
|
||||
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
|
||||
RAN_CONTEXT_t RC;
|
||||
THREAD_STRUCT thread_struct;
|
||||
@@ -139,6 +140,16 @@ int main(int argc, char **argv)
|
||||
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
|
||||
}
|
||||
logInit();
|
||||
|
||||
// start time manager with some reasonable default for the running mode
|
||||
// (may be overwritten in configuration file or command line)
|
||||
void nr_pdcp_ms_tick(void);
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick
|
||||
};
|
||||
int tick_functions_count = 1;
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME);
|
||||
|
||||
// strdup to put the sring in the core file for post mortem identification
|
||||
LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION));
|
||||
set_softmodem_sighandler();
|
||||
@@ -177,6 +188,8 @@ int main(int argc, char **argv)
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
itti_wait_tasks_end(NULL);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
return 0;
|
||||
|
||||
+31
-40
@@ -31,54 +31,45 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
|
||||
|
||||
#include "assertions.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include <common/utils/system.h>
|
||||
|
||||
#include "PHY/types.h"
|
||||
|
||||
#include <fcntl.h> // for SEEK_SET
|
||||
#include <pthread.h> // for pthread_join
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/system.h"
|
||||
#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_ulsch.h"
|
||||
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
|
||||
#include "PHY/INIT/nr_phy_init.h"
|
||||
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include "PHY/defs_RU.h"
|
||||
#include "PHY/defs_common.h"
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "PHY/impl_defs_nr.h"
|
||||
#include "SCHED_NR/fapi_nr_l1.h"
|
||||
#include "SCHED_NR/phy_frame_config_nr.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "SCHED_NR/fapi_nr_l1.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "PHY/LTE_TRANSPORT/if4_tools.h"
|
||||
|
||||
#include "PHY/phy_extern.h"
|
||||
|
||||
#include "assertions.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "RRC/LTE/rrc_extern.h"
|
||||
#include "PHY_INTERFACE/phy_interface.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "UTIL/OTG/otg_tx.h"
|
||||
#include "UTIL/OTG/otg_externs.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "gnb_paramdef.h"
|
||||
|
||||
#include <executables/softmodem-common.h>
|
||||
|
||||
#include "T.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include <nfapi/oai_integration/nfapi_pnf.h>
|
||||
#include <openair1/PHY/NR_TRANSPORT/nr_ulsch.h>
|
||||
#include <openair1/PHY/NR_TRANSPORT/nr_dlsch.h>
|
||||
#include <PHY/NR_ESTIMATION/nr_ul_estimation.h>
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "nfapi_nr_interface_scf.h"
|
||||
#include "notified_fifo.h"
|
||||
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
|
||||
#include "thread-pool.h"
|
||||
#include "time_meas.h"
|
||||
#include "utils.h"
|
||||
|
||||
// #define USRP_DEBUG 1
|
||||
#include "executables/thread-common.h"
|
||||
|
||||
//#define TICK_TO_US(ts) (ts.diff)
|
||||
#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials)
|
||||
#define L1STATSSTRLEN 16384
|
||||
static void rx_func(processingData_L1_t *param);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
|
||||
#include <executables/softmodem-common.h>
|
||||
@@ -1249,6 +1250,10 @@ void *ru_thread(void *param)
|
||||
slot++;
|
||||
}
|
||||
|
||||
// pretend we have 1 iq sample per slot
|
||||
// and so slots_per_frame * 100 iq samples per second (1 frame being 10ms)
|
||||
time_manager_iq_samples(1, fp->slots_per_frame * 100);
|
||||
|
||||
// synchronization on input FH interface, acquire signals/data and block
|
||||
LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "PHY/TOOLS/smbv.h"
|
||||
unsigned short config_frames[4] = {2,9,11,13};
|
||||
#endif
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#ifdef ENABLE_AERIAL
|
||||
#include "nfapi/oai_integration/aerial/fapi_nvIPC.h"
|
||||
#endif
|
||||
@@ -85,6 +86,7 @@ unsigned short config_frames[4] = {2,9,11,13};
|
||||
#include "utils.h"
|
||||
#include "x2ap_eNB.h"
|
||||
#include "openair1/SCHED_NR/sched_nr.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
|
||||
pthread_cond_t nfapi_sync_cond;
|
||||
pthread_mutex_t nfapi_sync_mutex;
|
||||
@@ -497,11 +499,8 @@ static void wait_nfapi_init(char *thread_name)
|
||||
}
|
||||
|
||||
void init_pdcp(void) {
|
||||
uint32_t pdcp_initmask = IS_SOFTMODEM_NOS1 ? ENB_NAS_USE_TUN_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;
|
||||
|
||||
if (!NODE_IS_DU(get_node_type())) {
|
||||
nr_pdcp_layer_init();
|
||||
nr_pdcp_module_init(pdcp_initmask, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,9 +519,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args)
|
||||
const gNB_RRC_INST* rrc = RC.nrrrc[0];
|
||||
assert(rrc != NULL && "rrc cannot be NULL");
|
||||
|
||||
const int mcc = rrc->configuration.mcc[0];
|
||||
const int mnc = rrc->configuration.mnc[0];
|
||||
const int mnc_digit_len = rrc->configuration.mnc_digit_length[0];
|
||||
const int mcc = rrc->configuration.plmn[0].mcc;
|
||||
const int mnc = rrc->configuration.plmn[0].mnc;
|
||||
const int mnc_digit_len = rrc->configuration.plmn[0].mnc_digit_length;
|
||||
// const ngran_node_t node_type = rrc->node_type;
|
||||
int nb_id = 0;
|
||||
int cu_du_id = 0;
|
||||
@@ -599,8 +598,6 @@ int main( int argc, char **argv ) {
|
||||
char *pckg = strdup(OAI_PACKAGE_VERSION);
|
||||
LOG_I(HW, "Version: %s\n", pckg);
|
||||
|
||||
// don't create if node doesn't connect to RRC/S1/GTP
|
||||
const ngran_node_t node_type = get_node_type();
|
||||
// Init RAN context
|
||||
if (!(CONFIG_ISFLAGSET(CONFIG_ABORT)))
|
||||
NRRCConfig();
|
||||
@@ -615,6 +612,9 @@ int main( int argc, char **argv ) {
|
||||
RCconfig_nr_prs();
|
||||
}
|
||||
|
||||
// don't create if node doesn't connect to RRC/S1/GTP
|
||||
const ngran_node_t node_type = get_node_type();
|
||||
|
||||
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
||||
int ret = create_gNB_tasks(node_type, uniqCfg);
|
||||
AssertFatal(ret == 0, "cannot create ITTI tasks\n");
|
||||
@@ -629,6 +629,38 @@ int main( int argc, char **argv ) {
|
||||
pthread_mutex_init(&sync_mutex, NULL);
|
||||
}
|
||||
|
||||
// start time manager with some reasonable default for the running mode
|
||||
// (may be overwritten in configuration file or command line)
|
||||
void nr_pdcp_ms_tick(void);
|
||||
void x2ap_ms_tick();
|
||||
void nr_rlc_ms_tick(void);
|
||||
time_manager_tick_function_t tick_functions[3];
|
||||
int tick_functions_count = 0;
|
||||
if (NODE_IS_MONOLITHIC(node_type)) {
|
||||
/* monolithic */
|
||||
tick_functions[tick_functions_count++] = nr_pdcp_ms_tick;
|
||||
tick_functions[tick_functions_count++] = nr_rlc_ms_tick;
|
||||
/* x2ap is enabled when in NSA mode */
|
||||
if (get_softmodem_params()->nsa)
|
||||
tick_functions[tick_functions_count++] = x2ap_ms_tick;
|
||||
} else if (NODE_IS_CU(node_type)) {
|
||||
/* CU */
|
||||
tick_functions[tick_functions_count++] = nr_pdcp_ms_tick;
|
||||
/* x2ap is enabled when in NSA mode */
|
||||
if (get_softmodem_params()->nsa)
|
||||
tick_functions[tick_functions_count++] = x2ap_ms_tick;
|
||||
} else {
|
||||
/* DU */
|
||||
tick_functions[tick_functions_count++] = nr_rlc_ms_tick;
|
||||
}
|
||||
time_manager_start(tick_functions, tick_functions_count,
|
||||
// iq_samples time source for monolithic/du with rfsim,
|
||||
// realtime time source for other cases
|
||||
IS_SOFTMODEM_RFSIM
|
||||
&& (NODE_IS_MONOLITHIC(node_type) || NODE_IS_DU(node_type))
|
||||
? TIME_SOURCE_IQ_SAMPLES
|
||||
: TIME_SOURCE_REALTIME);
|
||||
|
||||
// start the main threads
|
||||
number_of_cards = 1;
|
||||
|
||||
@@ -731,6 +763,8 @@ int main( int argc, char **argv ) {
|
||||
pthread_cond_destroy(&nfapi_sync_cond);
|
||||
pthread_mutex_destroy(&nfapi_sync_mutex);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
free(pckg);
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
|
||||
+6
-11
@@ -42,6 +42,7 @@
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
#include "position_interface.h"
|
||||
#include "nr_phy_common.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
|
||||
/*
|
||||
* NR SLOT PROCESSING SEQUENCE
|
||||
@@ -563,7 +564,7 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
if (get_nrUE_params()->cont_fo_comp == 2) // different from LO frequency error compensation, Doppler UL pre-compensation has to be negative
|
||||
ul_freq_offset = -ul_freq_offset;
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++)
|
||||
nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], writeBlockSize);
|
||||
nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], txp[i], writeBlockSize);
|
||||
}
|
||||
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags);
|
||||
@@ -706,16 +707,6 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
|
||||
process_msg_rcc_to_mac(msg);
|
||||
} while (msg);
|
||||
|
||||
if (IS_SOFTMODEM_NOS1 || IS_SA_MODE(get_softmodem_params())) {
|
||||
/* send tick to RLC and PDCP every ms */
|
||||
if (proc->nr_slot_rx % fp->slots_per_subframe == 0) {
|
||||
void nr_rlc_tick(int frame, int subframe);
|
||||
void nr_pdcp_tick(int frame, int subframe);
|
||||
nr_rlc_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe);
|
||||
nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe);
|
||||
}
|
||||
}
|
||||
|
||||
if (UE->if_inst)
|
||||
UE->if_inst->slot_indication(UE->Mod_id, false);
|
||||
|
||||
@@ -1095,6 +1086,10 @@ void *UE_thread(void *arg)
|
||||
absolute_slot++;
|
||||
TracyCFrameMark;
|
||||
|
||||
// pretend we have 1 iq sample per slot
|
||||
// and so nb_slot_frame * 100 iq samples per second (1 frame being 10ms)
|
||||
time_manager_iq_samples(1, nb_slot_frame * 100);
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
nr_rxtx_thread_data_t curMsg = {0};
|
||||
curMsg.UE=UE;
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
unsigned short config_frames[4] = {2,9,11,13};
|
||||
#endif
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
|
||||
#include "UTIL/OPT/opt.h"
|
||||
@@ -301,25 +302,10 @@ void init_openair0()
|
||||
|
||||
static void init_pdcp(int ue_id)
|
||||
{
|
||||
uint32_t pdcp_initmask = (!IS_SOFTMODEM_NOS1) ? LINK_ENB_PDCP_TO_GTPV1U_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;
|
||||
|
||||
/*if (IS_SOFTMODEM_RFSIM || (nfapi_getmode()==NFAPI_UE_STUB_PNF)) {
|
||||
pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
|
||||
}*/
|
||||
|
||||
// previous code was:
|
||||
// if (IS_SOFTMODEM_NOKRNMOD)
|
||||
// pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
|
||||
// The kernel module (KRNMOD) has been removed from the project, so the 'if'
|
||||
// was removed but the flag 'pdcp_initmask' was kept, as "no kernel module"
|
||||
// was always set. further refactoring could take it out
|
||||
pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
|
||||
|
||||
if (get_softmodem_params()->nsa && nr_rlc_module_init(0) != 0) {
|
||||
LOG_I(RLC, "Problem at RLC initiation \n");
|
||||
}
|
||||
nr_pdcp_layer_init();
|
||||
nr_pdcp_module_init(pdcp_initmask, ue_id);
|
||||
}
|
||||
|
||||
// Stupid function addition because UE itti messages queues definition is common with eNB
|
||||
@@ -449,6 +435,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (create_tasks_nrue(1) < 0) {
|
||||
printf("cannot create ITTI tasks\n");
|
||||
exit(-1); // need a softer mode
|
||||
}
|
||||
|
||||
int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1;
|
||||
uint16_t node_number = get_softmodem_params()->node_number;
|
||||
ue_id_g = (node_number == 0) ? 0 : node_number - 2;
|
||||
@@ -467,9 +458,20 @@ int main(int argc, char **argv)
|
||||
get_channel_model_mode(uniqCfg);
|
||||
}
|
||||
|
||||
// Delay to allow the convergence of the IIR filter on PRACH noise measurements at gNB side
|
||||
if (IS_SOFTMODEM_RFSIM && !get_softmodem_params()->phy_test)
|
||||
sleep(3);
|
||||
// start time manager with some reasonable default for the running mode
|
||||
// (may be overwritten in configuration file or command line)
|
||||
void nr_pdcp_ms_tick(void);
|
||||
void nr_rlc_ms_tick(void);
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick
|
||||
};
|
||||
int tick_functions_count = 2;
|
||||
time_manager_start(tick_functions, tick_functions_count,
|
||||
// iq_samples time source for rfsim,
|
||||
// realtime time source if not
|
||||
IS_SOFTMODEM_RFSIM ? TIME_SOURCE_IQ_SAMPLES
|
||||
: TIME_SOURCE_REALTIME);
|
||||
|
||||
if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1)
|
||||
start_oai_nrue_threads();
|
||||
@@ -557,11 +559,6 @@ int main(int argc, char **argv)
|
||||
// wait for end of program
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
|
||||
if (create_tasks_nrue(1) < 0) {
|
||||
printf("cannot create ITTI tasks\n");
|
||||
exit(-1); // need a softer mode
|
||||
}
|
||||
|
||||
// Sleep a while before checking all parameters have been used
|
||||
// Some are used directly in external threads, asynchronously
|
||||
sleep(2);
|
||||
@@ -601,6 +598,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
free_nrLDPC_coding_interface(&nrLDPC_coding_interface);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
free(pckg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ extern "C"
|
||||
#define EMULATE_L1 softmodem_params.emulate_l1
|
||||
#define CONTINUOUS_TX softmodem_params.continuous_tx
|
||||
#define SYNC_REF softmodem_params.sync_ref
|
||||
#define DEFAULT_PDU_ID softmodem_params.default_pdu_session_id
|
||||
|
||||
#define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
|
||||
|
||||
@@ -188,6 +189,7 @@ extern int usrp_tx_thread;
|
||||
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
|
||||
{"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \
|
||||
{"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \
|
||||
{"default_pdu_id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -234,6 +236,7 @@ extern int usrp_tx_thread;
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -343,6 +346,7 @@ typedef struct {
|
||||
uint32_t sync_ref;
|
||||
int no_itti;
|
||||
int threequarter_fs;
|
||||
int default_pdu_session_id;
|
||||
} softmodem_params_t;
|
||||
|
||||
#define IS_SA_MODE(sM_params) (!(sM_params)->phy_test && !(sM_params)->do_ra && !(sM_params)->nsa)
|
||||
|
||||
@@ -129,6 +129,8 @@ typedef struct {
|
||||
short rsrp_dBm;
|
||||
long arfcn;
|
||||
rlm_t radiolink_monitoring; // -1 no monitoring, 0 out_of_sync, 1 in_sync
|
||||
// SINR value times 10 as reporting granularity is 0.5
|
||||
float sinr_dB;
|
||||
} fapi_nr_ssb_pdu_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -350,7 +350,7 @@ int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams,
|
||||
uint16_t Zc = p_decParams->Z;
|
||||
uint8_t BG = p_decParams->BG;
|
||||
// uint8_t numMaxIter = p_decParams->numMaxIter;
|
||||
int block_length = p_decParams->block_length;
|
||||
int block_length = p_decParams->Kprime;
|
||||
// e_nrLDPC_outMode outMode = p_decParams->outMode;
|
||||
uint8_t row,col;
|
||||
if(BG == 1){
|
||||
|
||||
@@ -180,8 +180,10 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
AssertFatal( nb_connected_gNB <= NUMBER_OF_CONNECTED_gNB_MAX, "n_connected_gNB is too large" );
|
||||
// init phy_vars_ue
|
||||
|
||||
for (int i = 0; i < fp->Lmax; i++)
|
||||
for (int i = 0; i < fp->Lmax; i++) {
|
||||
ue->measurements.ssb_rsrp_dBm[i] = INT_MIN;
|
||||
ue->measurements.ssb_sinr_dB[i] = INT_MIN;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ue->rx_gain_max[i] = 135;
|
||||
|
||||
@@ -28,13 +28,6 @@
|
||||
#include "PHY/nr_phy_common/inc/nr_phy_common.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
|
||||
//#define DEBUG_FEP
|
||||
|
||||
/*#ifdef LOG_I
|
||||
#undef LOG_I
|
||||
#define LOG_I(A,B...) printf(A)
|
||||
#endif*/
|
||||
|
||||
int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
unsigned int slot,
|
||||
@@ -44,7 +37,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
uint32_t sample_offset,
|
||||
c16_t **rxdata)
|
||||
{
|
||||
|
||||
AssertFatal(symbol < frame_parms->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_parms->symbols_per_slot-1);
|
||||
AssertFatal(slot < frame_parms->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_parms->slots_per_frame - 1);
|
||||
|
||||
@@ -68,7 +60,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
|
||||
dft_size_idx_t dftsize = get_dft(frame_parms->ofdm_symbol_size);
|
||||
// This is for misalignment issues
|
||||
int32_t tmp_dft_in[8192] __attribute__ ((aligned (32)));
|
||||
c16_t tmp_dft_in[frame_parms->ofdm_symbol_size] __attribute__ ((aligned (32)));
|
||||
|
||||
unsigned int rx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
||||
unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol;
|
||||
@@ -81,16 +73,10 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
// use OFDM symbol from within 1/8th of the CP to avoid ISI
|
||||
rx_offset -= (nb_prefix_samples / frame_parms->ofdm_offset_divisor);
|
||||
|
||||
#ifdef DEBUG_FEP
|
||||
// if (ue->frame <100)
|
||||
LOG_D(PHY,"slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u energy %d\n",
|
||||
Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset, dB_fixed(signal_energy((int32_t *)&common_vars->rxdata[0][rx_offset],frame_parms->ofdm_symbol_size)));
|
||||
#endif
|
||||
rx_offset %= total_samples;
|
||||
|
||||
for (unsigned char aa=0; aa<frame_parms->nb_antennas_rx; aa++) {
|
||||
int16_t *rxdata_ptr = (int16_t *)&rxdata[aa][rx_offset];
|
||||
|
||||
rx_offset %= total_samples;
|
||||
c16_t *rxdata_ptr = &rxdata[aa][rx_offset];
|
||||
|
||||
// This happens only during initial sync
|
||||
if (rx_offset + frame_parms->ofdm_symbol_size > total_samples) {
|
||||
@@ -101,17 +87,17 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
memcpy((void *)&tmp_dft_in[total_samples - rx_offset],
|
||||
(void *)&rxdata[aa][0],
|
||||
(frame_parms->ofdm_symbol_size - (total_samples - rx_offset)) * sizeof(int32_t));
|
||||
rxdata_ptr = (int16_t *)tmp_dft_in;
|
||||
rxdata_ptr = tmp_dft_in;
|
||||
|
||||
} else if ((rx_offset & 7) != 0) { // if input to dft is not 256-bit aligned
|
||||
memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], frame_parms->ofdm_symbol_size * sizeof(int32_t));
|
||||
|
||||
rxdata_ptr = (int16_t *)tmp_dft_in;
|
||||
rxdata_ptr = tmp_dft_in;
|
||||
}
|
||||
|
||||
if (ue && ue->cont_fo_comp) {
|
||||
start_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS);
|
||||
nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, (c16_t *)rxdata_ptr, frame_parms->ofdm_symbol_size);
|
||||
nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, rxdata_ptr, tmp_dft_in, frame_parms->ofdm_symbol_size);
|
||||
rxdata_ptr = tmp_dft_in;
|
||||
stop_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS);
|
||||
}
|
||||
|
||||
@@ -119,7 +105,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
start_meas_nr_ue_phy(ue, RX_DFT_STATS);
|
||||
|
||||
dft(dftsize,
|
||||
rxdata_ptr,
|
||||
(int16_t *)rxdata_ptr,
|
||||
(int16_t *)&rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
|
||||
1);
|
||||
|
||||
@@ -129,10 +115,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
apply_nr_rotation_RX(frame_parms, rxdataF[aa], frame_parms->symbol_rotation[linktype], slot, N_RB, 0, symbol, 1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FEP
|
||||
printf("slot_fep: done\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "nr_common.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "nr_ul_estimation.h"
|
||||
@@ -480,6 +481,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
||||
pusch_pdu->scid,
|
||||
Ns,
|
||||
symbol);
|
||||
pusch_dmrs_type_t dmrs_type = pusch_pdu->dmrs_config_type == NFAPI_NR_DMRS_TYPE1 ? pusch_dmrs_type1 : pusch_dmrs_type2;
|
||||
float beta_dmrs_pusch = get_beta_dmrs_pusch(pusch_pdu->num_dmrs_cdm_grps_no_data, dmrs_type);
|
||||
int16_t dmrs_scaling = (1 / beta_dmrs_pusch) * (1 << 14);
|
||||
nr_pusch_dmrs_rx(gNB,
|
||||
Ns,
|
||||
gold,
|
||||
@@ -488,7 +492,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
||||
0,
|
||||
nb_rb_pusch,
|
||||
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
|
||||
pusch_pdu->dmrs_config_type);
|
||||
pusch_pdu->dmrs_config_type,
|
||||
dmrs_scaling);
|
||||
} else { // if transform precoding or SC-FDMA is enabled in Uplink
|
||||
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
|
||||
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
//#define NR_PBCH_DMRS_LENGTH 144
|
||||
//#define DEBUG_PUSCH
|
||||
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include "refsig_defs_ue.h"
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include "nr_refsig.h"
|
||||
@@ -73,7 +74,8 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
|
||||
unsigned char lp,
|
||||
unsigned short nb_pusch_rb,
|
||||
uint32_t re_offset,
|
||||
uint8_t dmrs_type)
|
||||
uint8_t dmrs_type,
|
||||
int16_t dmrs_scaling)
|
||||
{
|
||||
typedef int array_of_w[2];
|
||||
const array_of_w *wf = (dmrs_type == pusch_dmrs_type1) ? wf1 : wf2;
|
||||
@@ -91,6 +93,7 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
|
||||
int i = k + dmrs_offset;
|
||||
int w = (wf[p - 1000][i & 1]) * (wt[p - 1000][lp]);
|
||||
output[k] = get_modulated(nr_gold_pusch, i, w == 1);
|
||||
output[k] = c16mulRealShift(output[k], dmrs_scaling, 14);
|
||||
#ifdef DEBUG_PUSCH
|
||||
printf("nr_pusch_dmrs_rx dmrs config type %d port %d nb_pusch_rb %d\n", dmrs_type, p, nb_pusch_rb);
|
||||
printf("wf[%d] = %d wt[%d]= %d\n", i&1, wf[p-1000][i&1], lp, wt[p-1000][lp]);
|
||||
|
||||
@@ -36,7 +36,8 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
|
||||
unsigned char lp,
|
||||
unsigned short nb_pusch_rb,
|
||||
uint32_t re_offset,
|
||||
uint8_t dmrs_type);
|
||||
uint8_t dmrs_type,
|
||||
int16_t dmrs_scaling);
|
||||
|
||||
void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int32_t **dataF,
|
||||
|
||||
@@ -1081,7 +1081,6 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
unsigned short nb_rb_pdsch,
|
||||
int8_t delta,
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
{
|
||||
@@ -1094,30 +1093,23 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int nest_count = 0;
|
||||
uint64_t noise_amp2 = 0;
|
||||
|
||||
for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) {
|
||||
if (pilot_cnt % 2 == 0) {
|
||||
c16_t ch = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
ch = c16maddShift(*pil, rxF[re_offset], ch, 15);
|
||||
ch = c16Shift(ch, 1);
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
|
||||
dl_ls_est[k] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt += 2) {
|
||||
c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n",
|
||||
pilot_cnt,
|
||||
pil->r,
|
||||
pil->i,
|
||||
rxF[re_offset].r,
|
||||
rxF[re_offset].i,
|
||||
dl_ls_est[pilot_cnt << 1].r,
|
||||
dl_ls_est[pilot_cnt << 1].i);
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i);
|
||||
#endif
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
|
||||
#endif
|
||||
c16_t ch = c16addShift(ch_l, ch_r, 1);
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
|
||||
dl_ls_est[k] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
@@ -1247,8 +1239,6 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
unsigned short nb_rb_pdsch,
|
||||
int8_t delta,
|
||||
unsigned short p,
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
{
|
||||
@@ -1270,7 +1260,7 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size;
|
||||
c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
|
||||
#endif
|
||||
c16_t ch = c16addShift(ch_l, ch_r, 1);
|
||||
for (int k = 3 * pilot_cnt; k < (3 * pilot_cnt) + 6; k++) {
|
||||
@@ -1427,9 +1417,8 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf(
|
||||
"PDSCH Channel Estimation : gNB_id %d ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, Ns=%d, bwp_start_subcarrier=%d "
|
||||
"PDSCH Channel Estimation : ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, Ns=%d, bwp_start_subcarrier=%d "
|
||||
"symbol %d\n",
|
||||
gNB_id,
|
||||
ch_offset,
|
||||
symbol_offset,
|
||||
fp->ofdm_symbol_size,
|
||||
@@ -1467,7 +1456,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
bwp_start_subcarrier,
|
||||
nb_rb_pdsch,
|
||||
delta,
|
||||
&delay,
|
||||
nvar);
|
||||
|
||||
@@ -1478,8 +1466,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
bwp_start_subcarrier,
|
||||
nb_rb_pdsch,
|
||||
delta,
|
||||
p,
|
||||
&delay,
|
||||
nvar);
|
||||
|
||||
|
||||
@@ -111,11 +111,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
|
||||
uint32_t pdsch_est_size,
|
||||
int32_t dl_ch_estimates[][pdsch_est_size]);
|
||||
|
||||
int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier);
|
||||
uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier);
|
||||
|
||||
void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
|
||||
uint8_t gNB_index,
|
||||
|
||||
@@ -172,11 +172,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
|
||||
|
||||
// This function calculates:
|
||||
// - SS reference signal received digital power in dB/RE
|
||||
int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier)
|
||||
uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier)
|
||||
{
|
||||
int k_start = 56;
|
||||
int k_end = 183;
|
||||
@@ -209,9 +209,7 @@ int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
|
||||
LOG_D(PHY, "In %s: RSRP/nb_re: %d nb_re :%d\n", __FUNCTION__, rsrp, nb_re);
|
||||
|
||||
int rsrp_db_per_re = 10 * log10(rsrp);
|
||||
|
||||
return rsrp_db_per_re;
|
||||
return rsrp;
|
||||
}
|
||||
|
||||
// This function implements:
|
||||
@@ -234,7 +232,8 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
|
||||
if (fp->half_frame_bit)
|
||||
symbol_offset += (fp->slots_per_frame >> 1) * fp->symbols_per_slot;
|
||||
|
||||
int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier);
|
||||
uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier);
|
||||
float rsrp_db_per_re = 10 * log10(rsrp_avg);
|
||||
|
||||
openair0_config_t *cfg0 = &openair0_cfg[0];
|
||||
|
||||
@@ -242,12 +241,18 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
|
||||
- ((int)cfg0->rx_gain[0] - (int)cfg0->rx_gain_offset[0])
|
||||
- dB_fixed(fp->ofdm_symbol_size);
|
||||
|
||||
// to obtain non-integer dB value with a resoluion of 0.5dB
|
||||
uint32_t signal_pwr = rsrp_avg > ue->measurements.n0_power_avg ? rsrp_avg - ue->measurements.n0_power_avg : 0;
|
||||
int SNRtimes10 = dB_fixed_x10(signal_pwr) - dB_fixed_x10(ue->measurements.n0_power_avg);
|
||||
ue->measurements.ssb_sinr_dB[ssb_index] = SNRtimes10 / 10.0;
|
||||
|
||||
LOG_D(PHY,
|
||||
"[UE %d] ssb %d SS-RSRP: %d dBm/RE (%d dB/RE)\n",
|
||||
"[UE %d] ssb %d SS-RSRP: %d dBm/RE (%f dB/RE), SS-SINR: %f dB\n",
|
||||
ue->Mod_id,
|
||||
ssb_index,
|
||||
ue->measurements.ssb_rsrp_dBm[ssb_index],
|
||||
rsrp_db_per_re);
|
||||
rsrp_db_per_re,
|
||||
ue->measurements.ssb_sinr_dB[ssb_index]);
|
||||
}
|
||||
|
||||
// This function computes the received noise power
|
||||
|
||||
@@ -576,6 +576,25 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
*log2_maxh,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
// Please keep it: useful for debugging
|
||||
#ifdef DEBUG_PDSCH_RX
|
||||
char filename[50];
|
||||
|
||||
snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF0", &rxdataF[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_ext0", &rxdataF_ext[0][0], rx_size_symbol, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates_ext0", &dl_ch_estimates_ext[0][0], rx_size_symbol, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_comp00_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_comp00", &rxdataF_comp[0][0][symbol * rx_size_symbol], rx_size_symbol, 1, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
start_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
|
||||
@@ -694,32 +713,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
rx_llr_layer_size,
|
||||
layer_llr);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
|
||||
// Please keep it: useful for debugging
|
||||
#ifdef DEBUG_PDSCH_RX
|
||||
char filename[50];
|
||||
uint8_t aa = 0;
|
||||
|
||||
snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF0", &rxdataF[0][0], NR_SYMBOLS_PER_SLOT*frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates", &dl_ch_estimates[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_ext0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_ext", &rxdataF_ext[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates_ext0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates_ext00", &dl_ch_estimates_ext[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_comp0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_comp00", &rxdataF_comp[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1);
|
||||
/*
|
||||
for (int i=0; i < 2; i++){
|
||||
snprintf(filename, 50, "llr%d_symb_%d_nr_slot_rx_%d.m", i, symbol, nr_slot_rx);
|
||||
write_output(filename,"llr", &llr[i][0], (NR_SYMBOLS_PER_SLOT*nb_rb_pdsch*NR_NB_SC_PER_RB*dlsch1_harq->Qm) - 4*(nb_rb_pdsch*4*dlsch1_harq->Qm), 1, 0);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
if (UEScopeHasTryLock(ue)) {
|
||||
metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx };
|
||||
int total_valid_res = 0;
|
||||
|
||||
@@ -285,7 +285,8 @@ void nr_scan_ssb(void *arg)
|
||||
&ssbInfo->pbchResult,
|
||||
rxdataF); // start pbch detection at first symbol after pss
|
||||
if (ssbInfo->syncRes.cell_detected) {
|
||||
int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC);
|
||||
uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC);
|
||||
int rsrp_db_per_re = 10 * log10(rsrp_avg);
|
||||
ssbInfo->adjust_rxgain = TARGET_RX_POWER - rsrp_db_per_re;
|
||||
LOG_I(PHY, "pbch rx ok. rsrp:%d dB/RE, adjust_rxgain:%d dB\n", rsrp_db_per_re, ssbInfo->adjust_rxgain);
|
||||
}
|
||||
|
||||
@@ -392,13 +392,15 @@ static void dmrs_amp_mult(const uint32_t dmrs_port,
|
||||
const c16_t *mod_dmrs,
|
||||
c16_t *mod_dmrs_out,
|
||||
const uint32_t n_dmrs,
|
||||
const pusch_dmrs_type_t dmrs_type)
|
||||
const pusch_dmrs_type_t dmrs_type,
|
||||
const unsigned int num_cdm_groups_no_data)
|
||||
{
|
||||
float beta_dmrs_pusch = get_beta_dmrs_pusch(num_cdm_groups_no_data, dmrs_type);
|
||||
/* short array that hold amplitude for k_prime = 0 and k_prime = 1 */
|
||||
int32_t alpha_dmrs[2] __attribute((aligned(16)));
|
||||
for (int_fast8_t i = 0; i < sizeofArray(alpha_dmrs); i++) {
|
||||
const int32_t a = Wf[i] * Wt * AMP;
|
||||
alpha_dmrs[i] = a;
|
||||
alpha_dmrs[i] = a * beta_dmrs_pusch;
|
||||
}
|
||||
|
||||
/* multiply amplitude with complex DMRS vector */
|
||||
@@ -440,9 +442,9 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
|
||||
c16_t mod_dmrs[ALNARS_16_4(n_dmrs)] __attribute((aligned(16)));
|
||||
if (p.transform_precoding == transformPrecoder_disabled) {
|
||||
nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type);
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
|
||||
} else {
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type);
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
|
||||
}
|
||||
} else if ((p.pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && ptrs_symbol) {
|
||||
AssertFatal(p.transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n");
|
||||
|
||||
@@ -140,6 +140,7 @@ typedef struct {
|
||||
uint32_t rsrp[7];
|
||||
short rsrp_dBm[7];
|
||||
int ssb_rsrp_dBm[64];
|
||||
float ssb_sinr_dB[64];
|
||||
// common measurements
|
||||
//! estimated noise power (linear)
|
||||
unsigned int n0_power[NB_ANTENNAS_RX];
|
||||
|
||||
@@ -344,12 +344,6 @@ typedef enum {
|
||||
* DESCRIPTION : configuration for PUSCH
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
pusch_dmrs_type1 = 0,
|
||||
pusch_dmrs_type2 = 1
|
||||
} pusch_dmrs_type_t;
|
||||
|
||||
typedef enum {
|
||||
txConfig_codebook = 1,
|
||||
txConfig_nonCodebook = 2
|
||||
|
||||
@@ -80,6 +80,6 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int
|
||||
void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal);
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb);
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size);
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -454,7 +454,7 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in
|
||||
return (0);
|
||||
}
|
||||
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size)
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size)
|
||||
{
|
||||
const double phase_inc = -fo_Hz / (samples_per_ms * 1000);
|
||||
double phase = sample_offset * phase_inc;
|
||||
@@ -473,12 +473,13 @@ void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16
|
||||
}
|
||||
const c16_t rot_vec = get_sin_cos(CHUNK * phase_inc);
|
||||
while (size > CHUNK) {
|
||||
mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, CHUNK, 14);
|
||||
rxdata_ptr += CHUNK;
|
||||
mult_complex_vectors(rxdata_in, rot, rxdata_out, CHUNK, 14);
|
||||
rotate_cpx_vector(rot, &rot_vec, rot, CHUNK, 14);
|
||||
rxdata_in += CHUNK;
|
||||
rxdata_out += CHUNK;
|
||||
size -= CHUNK;
|
||||
}
|
||||
mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, size, 14);
|
||||
mult_complex_vectors(rxdata_in, rot, rxdata_out, size, 14);
|
||||
#else
|
||||
// This code path computes the complex rotation values for the complete OFDM symbol using get_sin_cos().
|
||||
// This is more accurate, but also slower than the code path above.
|
||||
@@ -487,6 +488,6 @@ void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16
|
||||
rot[i] = get_sin_cos(phase);
|
||||
phase += phase_inc;
|
||||
}
|
||||
mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, size, 14);
|
||||
mult_complex_vectors(rxdata_in, rot, rxdata_out, size, 14);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -120,7 +120,8 @@ void prach_procedures(PHY_VARS_eNB *eNB,
|
||||
*/
|
||||
|
||||
if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) {
|
||||
if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) {
|
||||
if ((eNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
&& (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) {
|
||||
eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++;
|
||||
eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; //
|
||||
eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind];
|
||||
@@ -142,7 +143,7 @@ void prach_procedures(PHY_VARS_eNB *eNB,
|
||||
}
|
||||
} */// ce_level
|
||||
} else {
|
||||
if ((eNB->prach_energy_counter == 100) &&
|
||||
if ((eNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) &&
|
||||
(max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) {
|
||||
LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
|
||||
eNB->Mod_id,
|
||||
@@ -186,7 +187,8 @@ void prach_procedures(PHY_VARS_eNB *eNB,
|
||||
|
||||
if (frame==0) LOG_D(PHY,"prach_I0 = %d.%d dB\n",eNB->measurements.prach_I0/10,eNB->measurements.prach_I0%10);
|
||||
|
||||
if (eNB->prach_energy_counter < 100) eNB->prach_energy_counter++;
|
||||
if (eNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
eNB->prach_energy_counter++;
|
||||
}
|
||||
} // else br_flag
|
||||
|
||||
|
||||
@@ -145,7 +145,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
|
||||
max_preamble_delay[0],
|
||||
gNB->prach_energy_counter);
|
||||
|
||||
if ((gNB->prach_energy_counter == 100) && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres)
|
||||
if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
&& (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres)
|
||||
&& (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) {
|
||||
LOG_A(NR_PHY,
|
||||
"[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol "
|
||||
@@ -185,7 +186,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
|
||||
}
|
||||
gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>10);
|
||||
if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10);
|
||||
if (gNB->prach_energy_counter < 100) gNB->prach_energy_counter++;
|
||||
if (gNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
gNB->prach_energy_counter++;
|
||||
} //if prach_id>0
|
||||
rach_ind->slot = prach_start_slot;
|
||||
} // for NUMBER_OF_NR_PRACH_OCCASION_MAX
|
||||
|
||||
@@ -175,6 +175,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
|
||||
rx->ssb_pdu.cell_id = frame_parms->Nid_cell;
|
||||
rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier;
|
||||
rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index];
|
||||
rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index];
|
||||
rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms);
|
||||
rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here
|
||||
rx->ssb_pdu.decoded_pdu = true;
|
||||
@@ -485,6 +486,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
|
||||
int G)
|
||||
{
|
||||
int frame_rx = proc->frame_rx;
|
||||
int nr_slot_rx = proc->nr_slot_rx;
|
||||
|
||||
// We handle only one CW now
|
||||
@@ -496,9 +498,10 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid];
|
||||
|
||||
LOG_D(PHY,
|
||||
"[UE %d] nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask "
|
||||
"[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask "
|
||||
"%x, Nl %d\n",
|
||||
ue->Mod_id,
|
||||
frame_rx,
|
||||
nr_slot_rx,
|
||||
harq_pid,
|
||||
dlsch0_harq->status,
|
||||
@@ -558,10 +561,9 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
||||
nvar += nvar_tmp;
|
||||
#if 0
|
||||
///LOG_M: the channel estimation
|
||||
int nr_frame_rx = proc->frame_rx;
|
||||
char filename[100];
|
||||
for (uint8_t aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
|
||||
sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", nr_frame_rx, nr_slot_rx, m, nl, aarx);
|
||||
sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", frame_rx, nr_slot_rx, m, nl, aarx);
|
||||
int **dl_ch_estimates = ue->pdsch_vars[gNB_id]->dl_ch_estimates;
|
||||
LOG_M(filename,"channel_F",&dl_ch_estimates[nl*ue->frame_parms.nb_antennas_rx+aarx][ue->frame_parms.ofdm_symbol_size*m],ue->frame_parms.ofdm_symbol_size, 1, 1);
|
||||
}
|
||||
|
||||
@@ -469,6 +469,10 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t;
|
||||
*/
|
||||
typedef ul_info_transfer_ind_t dl_info_transfer_ind_t;
|
||||
|
||||
typedef struct nas_nos1_msg_s {
|
||||
int dummy; // This dummy element is to avoid CLANG warning: empty struct has size 0 in C, size 1 in C++
|
||||
} nas_nos1_msg_t;
|
||||
|
||||
typedef struct nas_pdu_session_req_s {
|
||||
int pdusession_id;
|
||||
int pdusession_type;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include "common/5g_platform_types.h"
|
||||
#include "common/platform_constants.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
// Defines to access message fields.
|
||||
@@ -92,12 +93,6 @@ typedef struct f1ap_net_config_t {
|
||||
uint16_t DUport;
|
||||
} f1ap_net_config_t;
|
||||
|
||||
typedef struct f1ap_plmn_t {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
} f1ap_plmn_t;
|
||||
|
||||
typedef struct f1ap_cp_tnl_s {
|
||||
in_addr_t tl_address; // currently only IPv4 supported
|
||||
uint16_t port;
|
||||
@@ -129,7 +124,7 @@ typedef struct f1ap_tdd_info_t {
|
||||
|
||||
typedef struct f1ap_served_cell_info_t {
|
||||
// NR CGI
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
|
||||
// NR Physical Cell Ids
|
||||
@@ -140,7 +135,7 @@ typedef struct f1ap_served_cell_info_t {
|
||||
|
||||
// Number of slice support items (max 16, could be increased to as much as 1024)
|
||||
uint16_t num_ssi;
|
||||
nssai_t nssai[16];
|
||||
nssai_t nssai[MAX_NUM_SLICES];
|
||||
|
||||
f1ap_mode_t mode;
|
||||
union {
|
||||
@@ -192,7 +187,7 @@ typedef struct f1ap_sib_msg_t {
|
||||
} f1ap_sib_msg_t;
|
||||
|
||||
typedef struct served_cells_to_activate_s {
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
// NR Global Cell Id
|
||||
uint64_t nr_cellid;
|
||||
/// NRPCI [int 0..1007]
|
||||
@@ -239,7 +234,7 @@ typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s {
|
||||
uint16_t num_cells_failed_to_be_activated;
|
||||
struct {
|
||||
// NR CGI
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint16_t cause;
|
||||
} cells_failed_to_be_activated[F1AP_MAX_NB_CELLS];
|
||||
@@ -256,7 +251,7 @@ typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s {
|
||||
struct {
|
||||
uint32_t gNB_CU_ue_id;
|
||||
// NR CGI
|
||||
f1ap_plmn_t ue_plmn;
|
||||
plmn_id_t ue_plmn;
|
||||
uint64_t ue_nr_cellid;
|
||||
} dedicatedSIDeliveryNeededUEs[F1AP_MAX_NO_UE_ID];
|
||||
} f1ap_gnb_cu_configuration_update_acknowledge_t;
|
||||
@@ -283,7 +278,7 @@ typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
/// int cells_to_modify
|
||||
uint16_t num_cells_to_modify;
|
||||
struct {
|
||||
f1ap_plmn_t old_plmn;
|
||||
plmn_id_t old_plmn;
|
||||
uint64_t old_nr_cellid; // NR Global Cell Id
|
||||
f1ap_served_cell_info_t info;
|
||||
f1ap_gnb_du_system_info_t *sys_info;
|
||||
@@ -293,7 +288,7 @@ typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
uint16_t num_cells_to_delete;
|
||||
struct {
|
||||
// NR CGI
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
} cell_to_delete[F1AP_MAX_NB_CELLS];
|
||||
/// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1)
|
||||
@@ -333,7 +328,7 @@ typedef struct f1ap_dl_rrc_message_s {
|
||||
|
||||
typedef struct f1ap_initial_ul_rrc_message_s {
|
||||
uint32_t gNB_DU_ue_id;
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
/// nr cell id
|
||||
uint64_t nr_cellid;
|
||||
/// crnti
|
||||
@@ -475,7 +470,7 @@ typedef struct f1ap_ue_context_setup_s {
|
||||
uint32_t gNB_CU_ue_id;
|
||||
uint32_t gNB_DU_ue_id;
|
||||
// SpCell Info
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint8_t servCellIndex;
|
||||
uint8_t *cellULConfigured;
|
||||
@@ -549,7 +544,7 @@ typedef struct f1ap_paging_ind_s {
|
||||
uint16_t ueidentityindexvalue;
|
||||
uint64_t fiveg_s_tmsi;
|
||||
uint8_t fiveg_s_tmsi_length;
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint8_t paging_drx;
|
||||
} f1ap_paging_ind_t;
|
||||
|
||||
@@ -435,10 +435,8 @@ typedef enum ngap_paging_ind_present_s {
|
||||
} ngap_paging_ind_present_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
uint8_t num_nssai;
|
||||
plmn_id_t plmn;
|
||||
uint16_t num_nssai;
|
||||
nssai_t s_nssai[8];
|
||||
} ngap_plmn_t;
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ MESSAGE_DEF(NR_NAS_CONN_ESTABLISH_IND, MESSAGE_PRIORITY_MED, nas_establish_ind_t
|
||||
MESSAGE_DEF(NR_NAS_CONN_RELEASE_IND, MESSAGE_PRIORITY_MED, NRNasConnReleaseInd, nr_nas_conn_release_ind)
|
||||
MESSAGE_DEF(NAS_UPLINK_DATA_CNF, MESSAGE_PRIORITY_MED, ul_info_transfer_cnf_t, nas_ul_data_cnf)
|
||||
MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, dl_info_transfer_ind_t, nas_dl_data_ind)
|
||||
MESSAGE_DEF(NAS_INIT_NOS1_IF, MESSAGE_PRIORITY_MED, nas_nos1_msg_t, nas_init_nos1_if)
|
||||
|
||||
// xNB: realtime -> RRC messages
|
||||
MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process)
|
||||
|
||||
@@ -416,9 +416,7 @@ typedef struct NbIoTRrcConfigurationReq_s {
|
||||
// gNB: GNB_APP -> RRC messages
|
||||
typedef struct NRRrcConfigurationReq_s {
|
||||
uint32_t tac;
|
||||
uint16_t mcc[PLMN_LIST_MAX_SIZE];
|
||||
uint16_t mnc[PLMN_LIST_MAX_SIZE];
|
||||
uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE];
|
||||
plmn_id_t plmn[PLMN_LIST_MAX_SIZE];
|
||||
uint8_t num_plmn;
|
||||
|
||||
bool um_on_default_drb;
|
||||
|
||||
+19
-34
@@ -36,19 +36,18 @@ static void get_NGU_S1U_addr(char **addr, uint16_t *port)
|
||||
uint32_t gnb_port_for_NGU = 0;
|
||||
char *gnb_ipv4_address_for_S1U = NULL;
|
||||
uint32_t gnb_port_for_S1U = 0;
|
||||
char gtpupath[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
||||
LOG_I(GTPU, "Configuring GTPu\n");
|
||||
|
||||
/* get number of active eNodeBs */
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
// get gNB params
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs > 0, "Failed to parse config file no active gNodeBs in %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS);
|
||||
|
||||
// Config GTPu
|
||||
char gtpupath[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
LOG_I(GTPU, "Configuring GTPu\n");
|
||||
sprintf(gtpupath, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
||||
config_get(config_get_if(), NETParams, sizeofArray(NETParams), gtpupath);
|
||||
GET_PARAMS(NETParams, GNBNETPARAMS_DESC, gtpupath);
|
||||
|
||||
char *address;
|
||||
if (NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr != NULL) {
|
||||
LOG_I(GTPU, "SA mode \n");
|
||||
@@ -84,15 +83,14 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity)
|
||||
if (!msgConfig)
|
||||
return NULL;
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs == 1, "Support only one gNB per process\n");
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
|
||||
paramdef_t *gnbParms = GNBParamList.paramarray[0];
|
||||
e1ap_setup_req_t *e1Setup = &E1AP_REGISTER_REQ(msgConfig).setup_req;
|
||||
|
||||
@@ -104,17 +102,8 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity)
|
||||
// Only 5GC supported
|
||||
e1Setup->cn_support = cn_support_5GC;
|
||||
|
||||
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
||||
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
|
||||
"config_check_PLMNParams and PLMNParams should have the same size");
|
||||
|
||||
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
|
||||
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix);
|
||||
// get and config PLMN params
|
||||
GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK);
|
||||
int numPLMNs = PLMNParamList.numelt;
|
||||
e1Setup->supported_plmns = numPLMNs;
|
||||
|
||||
@@ -123,14 +112,12 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity)
|
||||
e1Setup->plmn[I].id.mnc = *PLMNParamList.paramarray[I][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
e1Setup->plmn[I].id.mnc_digit_length = *PLMNParamList.paramarray[I][GNB_MNC_DIGIT_LENGTH].uptr;
|
||||
|
||||
// get and config SNSSAI params
|
||||
char snssaistr[MAX_OPTNAME_SIZE*2 + 8];
|
||||
sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_PLMN_LIST, I);
|
||||
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
|
||||
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
|
||||
config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeof(SNSSAIParams) / sizeof(paramdef_t), snssaistr);
|
||||
GET_PARAMS_LIST(SNSSAIParamList, SNSSAIParams, GNBSNSSAIPARAMS_DESC, GNB_CONFIG_STRING_SNSSAI_LIST, snssaistr);
|
||||
e1Setup->plmn[I].supported_slices = SNSSAIParamList.numelt;
|
||||
e1Setup->plmn[I].slice = calloc(SNSSAIParamList.numelt, sizeof(*e1Setup->plmn[I].slice));
|
||||
AssertFatal(e1Setup->plmn[I].slice != NULL, "out of memory\n");
|
||||
e1Setup->plmn[I].slice = calloc_or_fail(SNSSAIParamList.numelt, sizeof(*e1Setup->plmn[I].slice));
|
||||
for (int s = 0; s < SNSSAIParamList.numelt; ++s) {
|
||||
e1ap_nssai_t *slice = &e1Setup->plmn[I].slice[s];
|
||||
slice->sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
||||
@@ -150,9 +137,7 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity)
|
||||
E1AP_REGISTER_REQ(msgConfig).gnb_id = gnb_id;
|
||||
|
||||
if (entity != NULL) {
|
||||
paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0};
|
||||
paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC;
|
||||
config_getlist(config_get_if(), &GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix);
|
||||
GET_PARAMS_LIST(GNBE1ParamList, GNBE1Params, GNBE1PARAMS_DESC, GNB_CONFIG_STRING_E1_PARAMETERS, aprefix);
|
||||
paramdef_t *e1Parms = GNBE1ParamList.paramarray[0];
|
||||
strcpy(e1ap_nc->CUCP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUCP].strptr));
|
||||
e1ap_nc->CUCP_e1_ip_address.ipv4 = 1;
|
||||
|
||||
@@ -1423,7 +1423,7 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
&served_cells_to_modify_item_ies->value.choice.Served_Cells_To_Modify_Item;
|
||||
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_to_modify_item->oldNRCGI;
|
||||
const f1ap_plmn_t *old_plmn = &msg->cell_to_modify[i].old_plmn;
|
||||
const plmn_id_t *old_plmn = &msg->cell_to_modify[i].old_plmn;
|
||||
MCC_MNC_TO_PLMNID(old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length, &oldNRCGI->pLMN_Identity);
|
||||
NR_CELL_ID_TO_BIT_STRING(msg->cell_to_modify[i].old_nr_cellid, &oldNRCGI->nRCellIdentity);
|
||||
|
||||
@@ -1449,7 +1449,7 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
F1AP_Served_Cells_To_Delete_Item_t *served_cells_to_delete_item =
|
||||
&served_cells_to_delete_item_ies->value.choice.Served_Cells_To_Delete_Item;
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_to_delete_item->oldNRCGI;
|
||||
const f1ap_plmn_t *plmn = &msg->cell_to_delete[i].plmn;
|
||||
const plmn_id_t *plmn = &msg->cell_to_delete[i].plmn;
|
||||
MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &(oldNRCGI->pLMN_Identity));
|
||||
NR_CELL_ID_TO_BIT_STRING(msg->cell_to_delete[i].nr_cellid, &(oldNRCGI->nRCellIdentity));
|
||||
}
|
||||
@@ -1519,7 +1519,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
->value.choice.Served_Cells_To_Modify_Item;
|
||||
/* Old NR CGI (M) */
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn;
|
||||
plmn_id_t *old_plmn = &out->cell_to_modify[i].old_plmn;
|
||||
PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
/* Old NR CGI Cell ID */
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid);
|
||||
@@ -1542,7 +1542,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
&((F1AP_Served_Cells_To_Delete_ItemIEs_t *)ie->value.choice.Served_Cells_To_Delete_List.list.array[i])
|
||||
->value.choice.Served_Cells_To_Delete_Item;
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn;
|
||||
plmn_id_t *plmn = &out->cell_to_delete[i].plmn;
|
||||
/* Old NR CGI (M) */
|
||||
PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
// NR cellID
|
||||
@@ -1833,7 +1833,7 @@ F1AP_F1AP_PDU_t *encode_f1ap_cu_configuration_update_acknowledge(const f1ap_gnb_
|
||||
p1->cause.present = F1AP_Cause_PR_radioNetwork;
|
||||
p1->cause.choice.radioNetwork = msg->cells_failed_to_be_activated[i].cause;
|
||||
// NR CGI (M)
|
||||
const f1ap_plmn_t *plmn = &msg->cells_failed_to_be_activated[i].plmn;
|
||||
const plmn_id_t *plmn = &msg->cells_failed_to_be_activated[i].plmn;
|
||||
MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &(p1->nRCGI.pLMN_Identity));
|
||||
printf("plmn->mcc %d %d %d %ld \n",
|
||||
p1->nRCGI.pLMN_Identity.buf[0], p1->nRCGI.pLMN_Identity.buf[1], p1->nRCGI.pLMN_Identity.buf[2], p1->nRCGI.pLMN_Identity.size);
|
||||
@@ -1880,7 +1880,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu,
|
||||
(F1AP_Cells_Failed_to_be_Activated_List_ItemIEs_t *)cell_fail_list->list.array[j];
|
||||
const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn;
|
||||
plmn_id_t *plmn = &out->cells_failed_to_be_activated[j].plmn;
|
||||
PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid);
|
||||
// Cause (M)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/utils.h"
|
||||
|
||||
bool eq_f1ap_plmn(const f1ap_plmn_t *a, const f1ap_plmn_t *b)
|
||||
bool eq_f1ap_plmn(const plmn_id_t *a, const plmn_id_t *b)
|
||||
{
|
||||
_F1_EQ_CHECK_INT(a->mcc, b->mcc);
|
||||
_F1_EQ_CHECK_INT(a->mnc, b->mnc);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "openair3/UTILS/conversions.h"
|
||||
#include "common/5g_platform_types.h"
|
||||
|
||||
#include "F1AP_Cause.h"
|
||||
#include "f1ap_messages_types.h"
|
||||
@@ -71,8 +72,7 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct f1ap_plmn_t;
|
||||
bool eq_f1ap_plmn(const struct f1ap_plmn_t *a, const struct f1ap_plmn_t *b);
|
||||
bool eq_f1ap_plmn(const plmn_id_t *a, const plmn_id_t *b);
|
||||
struct f1ap_served_cell_info_t;
|
||||
bool eq_f1ap_cell_info(const struct f1ap_served_cell_info_t *a, const struct f1ap_served_cell_info_t *b);
|
||||
struct f1ap_gnb_du_system_info_t;
|
||||
|
||||
@@ -80,7 +80,7 @@ static void f1ap_msg_free(F1AP_F1AP_PDU_t *pdu)
|
||||
*/
|
||||
static void test_initial_ul_rrc_message_transfer(void)
|
||||
{
|
||||
f1ap_plmn_t plmn = { .mcc = 208, .mnc = 95, .mnc_digit_length = 2 };
|
||||
plmn_id_t plmn = {.mcc = 208, .mnc = 95, .mnc_digit_length = 2};
|
||||
uint8_t rrc[] = "RRC Container";
|
||||
uint8_t du2cu[] = "DU2CU Container";
|
||||
f1ap_initial_ul_rrc_message_t orig = {
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
{GNB_CONFIG_STRING_PRACHMSG1FDM,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM,.defint64val=NR_RACH_ConfigGeneric__msg1_FDM_one,TYPE_INT64,0/*72*/},\
|
||||
{GNB_CONFIG_STRING_PRACHMSG1FREQUENCYSTART,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart,.defint64val=0,TYPE_INT64,0/*73*/},\
|
||||
{GNB_CONFIG_STRING_ZEROCORRELATIONZONECONFIG,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,.defint64val=13,TYPE_INT64,0/*74*/},\
|
||||
{GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,.defintval=-118,TYPE_INT64,0/*75*/},\
|
||||
{GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,.defint64val=-118,TYPE_INT64,0/*75*/},\
|
||||
{GNB_CONFIG_STRING_PREAMBLETRANSMAX,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax,.defint64val=NR_RACH_ConfigGeneric__preambleTransMax_n10,TYPE_INT64,0/*76*/},\
|
||||
{GNB_CONFIG_STRING_POWERRAMPINGSTEP,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep,.defint64val=NR_RACH_ConfigGeneric__powerRampingStep_dB2,TYPE_INT64,0/*77*/},\
|
||||
{GNB_CONFIG_STRING_RARESPONSEWINDOW,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow,.defint64val=NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20,TYPE_INT64,0/*78*/},\
|
||||
@@ -234,15 +234,15 @@
|
||||
{GNB_CONFIG_STRING_RSRPTHRESHOLDSSB,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB,.defint64val=19,TYPE_INT64,0/*82*/},\
|
||||
{GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR,NULL,0,.uptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present,.defuintval=NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139,TYPE_UINT,0/*83*/},\
|
||||
{GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.choice.l139,.defint64val=0,TYPE_INT64,0/*84*/},\
|
||||
{GNB_CONFIG_STRING_RESTRICTEDSETCONFIG,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig,.defintval=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet,TYPE_INT64,0/*85*/}, \
|
||||
{GNB_CONFIG_STRING_MSG3TRANSFPREC,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder,.defintval=1,TYPE_INT64,0/*86*/}, \
|
||||
{GNB_CONFIG_STRING_RESTRICTEDSETCONFIG,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig,.defint64val=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet,TYPE_INT64,0/*85*/}, \
|
||||
{GNB_CONFIG_STRING_MSG3TRANSFPREC,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder,.defint64val=1,TYPE_INT64,0/*86*/}, \
|
||||
{GNB_CONFIG_STRING_MSG3DELTAPREABMLE, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble,.defint64val=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_P0NOMINALWITHGRANT, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant,.defint64val=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_PUCCHGROUPHOPPING, NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping,.defint64val=NR_PUCCH_ConfigCommon__pucch_GroupHopping_neither,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_HOPPINGID, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId,.defint64val=40,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_P0NOMINAL, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal,.defint64val=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_PUCCHRES, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon,.defint64val=0,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_SSBPOSITIONSINBURST,NULL,0,.u64ptr=&ssb_bitmap,.defintval=0xff,TYPE_UINT64,0}, \
|
||||
{GNB_CONFIG_STRING_SSBPOSITIONSINBURST,NULL,0,.u64ptr=&ssb_bitmap,.defint64val=0xff,TYPE_UINT64,0}, \
|
||||
{GNB_CONFIG_STRING_REFERENCESUBCARRIERSPACING,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->referenceSubcarrierSpacing,.defint64val=NR_SubcarrierSpacing_kHz30,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_DLULTRANSMISSIONPERIODICITY,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity,.defint64val=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms0p5,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFDOWNLINKSLOTS,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots,.defint64val=7,TYPE_INT64,0},\
|
||||
@@ -259,7 +259,7 @@
|
||||
{GNB_CONFIG_STRING_EPHEMERIS_VELOCITY_VZ,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVZ_r17,.defint64val=LONG_MAX,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_TA_COMMON,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ta_Info_r17->ta_Common_r17,.defint64val=-1,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_TA_COMMONDRIFT,NULL,0,.i64ptr=scc->ext2->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17,.defint64val=0,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing,.defintval=-1,TYPE_INT64,0}}
|
||||
{GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing,.defint64val=-1,TYPE_INT64,0}}
|
||||
|
||||
#define SCC_PATTERN2_STRING_CONFIG "pattern2"
|
||||
|
||||
@@ -323,20 +323,20 @@
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define MSGASCCPARAMS_DESC(scc) { \
|
||||
{GNB_CONFIG_STRING_MSGBRESPONSEWINDOW_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.rach_ConfigGenericTwoStepRA_r16.msgB_ResponseWindow_r16,.defintval=-1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGARSRPTHRESHOLD_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_RSRP_Threshold_r16,.defintval=19,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGAMCS_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_MCS_r16,.defintval=2,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFSLOTSMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofSlotsMsgA_PUSCH_r16,.defintval=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFMSGAPOPERSLOT_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_PerSlot_r16,.defintval=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_PerSlot_r16_one,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGAPUSCHTIMEDOMAINOFFSET_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_PUSCH_TimeDomainOffset_r16,.defintval=0,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_STARTSYMBOLANDLENGTHMSGA_PO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->startSymbolAndLengthMsgA_PO_r16,.defintval=38,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MAPPINGTYPEMSGAPUSCH_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->mappingTypeMsgA_PUSCH_r16,.defintval=0,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_GUARDBANDMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->guardBandMsgA_PUSCH_r16,.defintval=0,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_FREQUENCYSTARTMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->frequencyStartMsgA_PUSCH_r16,.defintval=0,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_NROFPRBSPERMSGAPO_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofPRBs_PerMsgA_PO_r16,.defintval=8,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_NROFMSGAPOFDM_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_FDM_r16,.defintval=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_FDM_r16_one,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_MSGAPUSCHNROFPORTS_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_DMRS_Config_r16.msgA_PUSCH_NrofPorts_r16,.defintval=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFDMRSSEQUENCES_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofDMRS_Sequences_r16,.defintval=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGATRANSFORMPRECODER_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_TransformPrecoder_r16,.defintval=NR_MsgA_PUSCH_Config_r16__msgA_TransformPrecoder_r16_disabled,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGACBPREAMBLESPERSHAREDRO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_CB_PreamblesPerSSB_PerSharedRO_r16,.defintval=1,TYPE_INT64,0}}
|
||||
{GNB_CONFIG_STRING_MSGBRESPONSEWINDOW_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.rach_ConfigGenericTwoStepRA_r16.msgB_ResponseWindow_r16,.defint64val=-1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGARSRPTHRESHOLD_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_RSRP_Threshold_r16,.defint64val=19,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGAMCS_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_MCS_r16,.defint64val=2,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFSLOTSMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofSlotsMsgA_PUSCH_r16,.defint64val=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFMSGAPOPERSLOT_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_PerSlot_r16,.defint64val=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_PerSlot_r16_one,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGAPUSCHTIMEDOMAINOFFSET_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_PUSCH_TimeDomainOffset_r16,.defint64val=0,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_STARTSYMBOLANDLENGTHMSGA_PO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->startSymbolAndLengthMsgA_PO_r16,.defint64val=38,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MAPPINGTYPEMSGAPUSCH_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->mappingTypeMsgA_PUSCH_r16,.defint64val=0,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_GUARDBANDMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->guardBandMsgA_PUSCH_r16,.defint64val=0,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_FREQUENCYSTARTMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->frequencyStartMsgA_PUSCH_r16,.defint64val=0,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_NROFPRBSPERMSGAPO_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofPRBs_PerMsgA_PO_r16,.defint64val=8,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_NROFMSGAPOFDM_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_FDM_r16,.defint64val=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_FDM_r16_one,TYPE_INT64,0}, \
|
||||
{GNB_CONFIG_STRING_MSGAPUSCHNROFPORTS_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_DMRS_Config_r16.msgA_PUSCH_NrofPorts_r16,.defint64val=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_NROFDMRSSEQUENCES_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofDMRS_Sequences_r16,.defint64val=1,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGATRANSFORMPRECODER_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_TransformPrecoder_r16,.defint64val=NR_MsgA_PUSCH_Config_r16__msgA_TransformPrecoder_r16_disabled,TYPE_INT64,0},\
|
||||
{GNB_CONFIG_STRING_MSGACBPREAMBLESPERSHAREDRO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_CB_PreamblesPerSSB_PerSharedRO_r16,.defint64val=1,TYPE_INT64,0}}
|
||||
#endif
|
||||
|
||||
@@ -181,43 +181,6 @@ void *gNB_app_task(void *args_p)
|
||||
case NGAP_REGISTER_GNB_CNF:
|
||||
LOG_I(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name,
|
||||
NGAP_REGISTER_GNB_CNF(msg_p).nb_amf);
|
||||
/*
|
||||
DevAssert(register_gnb_pending > 0);
|
||||
register_gnb_pending--;
|
||||
|
||||
// Check if at least gNB is registered with one AMF
|
||||
if (NGAP_REGISTER_GNB_CNF(msg_p).nb_amf > 0) {
|
||||
registered_gnb++;
|
||||
}
|
||||
|
||||
// Check if all register gNB requests have been processed
|
||||
if (register_gnb_pending == 0) {
|
||||
if (registered_gnb == gnb_nb) {
|
||||
// If all gNB are registered, start L2L1 task
|
||||
MessageDef *msg_init_p;
|
||||
|
||||
msg_init_p = itti_alloc_new_message (TASK_GNB_APP, 0, INITIALIZE_MESSAGE);
|
||||
itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p);
|
||||
|
||||
} else {
|
||||
uint32_t not_associated = gnb_nb - registered_gnb;
|
||||
|
||||
LOG_W(GNB_APP, " %d gNB %s not associated with a AMF, retrying registration in %d seconds ...\n",
|
||||
not_associated, not_associated > 1 ? "are" : "is", GNB_REGISTER_RETRY_DELAY);
|
||||
|
||||
// Restart the gNB registration process in GNB_REGISTER_RETRY_DELAY seconds
|
||||
if (timer_setup (GNB_REGISTER_RETRY_DELAY, 0, TASK_GNB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
|
||||
NULL, &gnb_register_retry_timer_id) < 0) {
|
||||
LOG_E(GNB_APP, " Can not start gNB register retry timer, use \"sleep\" instead!\n");
|
||||
|
||||
sleep(GNB_REGISTER_RETRY_DELAY);
|
||||
// Restart the registration process
|
||||
registered_gnb = 0;
|
||||
register_gnb_pending = gNB_app_register (gnb_id_start, gnb_id_end);//, gnb_properties_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
break;
|
||||
|
||||
case F1AP_SETUP_RESP:
|
||||
@@ -247,13 +210,6 @@ void *gNB_app_task(void *args_p)
|
||||
|
||||
case TIMER_HAS_EXPIRED:
|
||||
LOG_I(GNB_APP, " Received %s: timer_id %ld\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
|
||||
|
||||
//if (TIMER_HAS_EXPIRED (msg_p).timer_id == gnb_register_retry_timer_id) {
|
||||
/* Restart the registration process */
|
||||
// registered_gnb = 0;
|
||||
// register_gnb_pending = gNB_app_register(gnb_id_start, gnb_id_end);//, gnb_properties_p);
|
||||
//}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
+201
-386
@@ -98,6 +98,45 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1};
|
||||
(element)->choice.setup = CALLOC(1, sizeof(*((element)->choice.setup))); \
|
||||
} while (0)
|
||||
|
||||
static uint16_t set_snssai_config(nssai_t *nssai, const int max_num_ssi, uint8_t k, uint8_t l)
|
||||
{
|
||||
char snssaistr[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
snprintf(snssaistr, sizeof(snssaistr), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l);
|
||||
GET_PARAMS_LIST(SNSSAIParamList,
|
||||
SNSSAIParams,
|
||||
GNBSNSSAIPARAMS_DESC,
|
||||
GNB_CONFIG_STRING_SNSSAI_LIST,
|
||||
snssaistr,
|
||||
SNSSAIPARAMS_CHECK);
|
||||
uint16_t num_ssi = SNSSAIParamList.numelt;
|
||||
AssertFatal(num_ssi < max_num_ssi, "S-NSSAI size %d exceeds the max array size %d", num_ssi, max_num_ssi);
|
||||
for (int s = 0; s < num_ssi; ++s) {
|
||||
nssai[s].sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
||||
// SD is optional
|
||||
// 0xffffff is "no SD", see 23.003 Sec 28.4.2
|
||||
nssai[s].sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr;
|
||||
AssertFatal(nssai[s].sd <= 0xffffff, "SD cannot be bigger than 0xffffff, but is %d\n", nssai[s].sd);
|
||||
}
|
||||
return num_ssi;
|
||||
}
|
||||
|
||||
static uint8_t set_plmn_config(plmn_id_t *p, uint8_t idx)
|
||||
{
|
||||
char gnbpath[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
snprintf(gnbpath, sizeof(gnbpath), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, idx);
|
||||
GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, gnbpath, PLMNPARAMS_CHECK);
|
||||
uint8_t num_plmn = PLMNParamList.numelt;
|
||||
AssertFatal(num_plmn >= 1 && num_plmn <= 6, "The number of PLMN IDs must be in [1,6], but is %d\n", num_plmn);
|
||||
for (int l = 0; l < num_plmn; ++l) {
|
||||
plmn_id_t *plmn = &p[l];
|
||||
plmn->mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
plmn->mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
plmn->mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
||||
AssertFatal((plmn->mnc_digit_length == 2) || (plmn->mnc_digit_length == 3), "BAD MNC DIGIT LENGTH %d", plmn->mnc_digit_length);
|
||||
}
|
||||
return num_plmn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate memory and initialize ServingCellConfigCommon struct members
|
||||
*/
|
||||
@@ -780,7 +819,7 @@ void fix_scd(NR_ServingCellConfig_t *scd) {
|
||||
static void verify_gnb_param_notset(paramdef_t *params, int paramidx, const char *paramname)
|
||||
{
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
AssertFatal(!config_isparamset(params, paramidx),
|
||||
"Option \"%s." GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON
|
||||
".%s\" is not allowed in this config, please remove it\n",
|
||||
@@ -796,13 +835,10 @@ static void verify_section_notset(configmodule_interface_t *cfg, char *aprefix,
|
||||
}
|
||||
void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
|
||||
{
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
config_get(cfg, GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs == 1, "need to have a " GNB_CONFIG_STRING_GNB_LIST " section, but %d found\n", num_gnbs);
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
config_getlist(cfg, &GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL, GNBPARAMS_CHECK);
|
||||
paramdef_t *gnbp = GNBParamList.paramarray[0];
|
||||
|
||||
if (NODE_IS_CU(node_type)) {
|
||||
@@ -822,6 +858,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
|
||||
verify_gnb_param_notset(gnbp, GNB_DISABLE_HARQ_IDX, GNB_CONFIG_STRING_DISABLE_HARQ);
|
||||
verify_gnb_param_notset(gnbp, GNB_NUM_DL_HARQ_IDX, GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES);
|
||||
verify_gnb_param_notset(gnbp, GNB_NUM_UL_HARQ_IDX, GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES);
|
||||
verify_gnb_param_notset(gnbp, GNB_DO_SINR_IDX, GNB_CONFIG_STRING_DOSINR);
|
||||
|
||||
// check for some general sections
|
||||
verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST);
|
||||
@@ -847,9 +884,7 @@ void RCconfig_nr_prs(void)
|
||||
|
||||
AssertFatal(RC.gNB != NULL, "gNB context is null, cannot complete PRS configuration\n");
|
||||
|
||||
paramdef_t PRS_Params[] = PRS_PARAMS_DESC;
|
||||
paramlist_def_t PRS_ParamList = {CONFIG_STRING_PRS_CONFIG,NULL,0};
|
||||
config_getlist(config_get_if(), &PRS_ParamList, PRS_Params, sizeofArray(PRS_Params), NULL);
|
||||
GET_PARAMS_LIST(PRS_ParamList, PRS_Params, PRS_PARAMS_DESC, CONFIG_STRING_PRS_CONFIG, NULL);
|
||||
|
||||
if (PRS_ParamList.numelt > 0) {
|
||||
for (j = 0; j < RC.nb_nr_L1_inst; j++) {
|
||||
@@ -959,6 +994,13 @@ static int get_prb_blacklist(uint8_t instance, uint16_t *prbbl)
|
||||
return num_prbbl;
|
||||
}
|
||||
|
||||
static void set_antenna_ports(paramlist_def_t *p, int *N1, int *N2, int *XP)
|
||||
{
|
||||
*N1 = *p->paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
||||
*N2 = *p->paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
||||
*XP = *p->paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
||||
}
|
||||
|
||||
void RCconfig_NR_L1(void)
|
||||
{
|
||||
LOG_I(NR_PHY, "Initializing NR L1: RC.nb_nr_L1_inst = %d\n", RC.nb_nr_L1_inst);
|
||||
@@ -968,17 +1010,10 @@ void RCconfig_NR_L1(void)
|
||||
AssertFatal(RC.gNB[j] != NULL, "gNB L1 instance is null at index %d, cannot complete L1 configuration\n", j);
|
||||
// gNB params
|
||||
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs > 0, "Failed to parse config file, no GNBs found in field %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS);
|
||||
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
int N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
||||
int N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
||||
int XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
|
||||
// PRB Blacklist
|
||||
uint16_t prbbl[MAX_BWP_SIZE] = {0};
|
||||
@@ -990,15 +1025,12 @@ void RCconfig_NR_L1(void)
|
||||
}
|
||||
|
||||
// Antenna ports
|
||||
gNB->ap_N1 = N1;
|
||||
gNB->ap_N2 = N2;
|
||||
gNB->ap_XP = XP;
|
||||
set_antenna_ports(&GNBParamList, &gNB->ap_N1, &gNB->ap_N2, &gNB->ap_XP);
|
||||
}
|
||||
|
||||
// L1 params
|
||||
paramdef_t L1_Params[] = L1PARAMS_DESC;
|
||||
paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST, NULL, 0};
|
||||
config_getlist(config_get_if(), &L1_ParamList, L1_Params, sizeofArray(L1_Params), NULL);
|
||||
GET_PARAMS_LIST(L1_ParamList, L1_Params, L1PARAMS_DESC, CONFIG_STRING_L1_LIST, NULL);
|
||||
|
||||
if (L1_ParamList.numelt > 0) {
|
||||
AssertFatal(*L1_ParamList.paramarray[j][L1_THREAD_POOL_SIZE].uptr == 2022,
|
||||
"thread_pool_size removed, please use --thread-pool\n");
|
||||
@@ -1059,27 +1091,30 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf
|
||||
NR_ServingCellConfigCommon_t *scc = calloc_or_fail(1, sizeof(*scc));
|
||||
uint64_t ssb_bitmap=0xff;
|
||||
prepare_scc(scc);
|
||||
paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
|
||||
prepare_msgA_scc(scc);
|
||||
paramdef_t MsgASCCsParams[] = MSGASCCPARAMS_DESC(scc);
|
||||
paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
||||
paramlist_def_t MsgASCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
||||
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
config_getlist(cfg, &SCCsParamList, NULL, 0, aprefix);
|
||||
config_getlist(cfg, &MsgASCCsParamList, NULL, 0, aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix);
|
||||
GET_PARAMS_LIST(MsgASCCsParamList, MsgASCCsParams, MSGASCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix);
|
||||
|
||||
if (SCCsParamList.numelt > 0 || MsgASCCsParamList.numelt > 0) {
|
||||
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
||||
config_get(cfg, SCCsParams, sizeofArray(SCCsParams), aprefix);
|
||||
config_get(cfg, MsgASCCsParams, sizeofArray(MsgASCCsParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
||||
GET_PARAMS(SCCsParams, SCCPARAMS_DESC(scc), aprefix);
|
||||
GET_PARAMS(MsgASCCsParams, MSGASCCPARAMS_DESC(scc), aprefix);
|
||||
// NR_TDD-UL-DL-ConfigCommon pattern2 (optional IE)
|
||||
// fetch params
|
||||
struct NR_TDD_UL_DL_Pattern p2;
|
||||
paramdef_t pattern2Params[] = SCC_PATTERN2_PARAMS_DESC(p2);
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[%i].%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0, SCC_PATTERN2_STRING_CONFIG);
|
||||
snprintf(aprefix,
|
||||
sizeof(aprefix),
|
||||
"%s.[%i].%s.[%i].%s",
|
||||
GNB_CONFIG_STRING_GNB_LIST,
|
||||
0,
|
||||
GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON,
|
||||
0,
|
||||
SCC_PATTERN2_STRING_CONFIG);
|
||||
config_get(config_get_if(), pattern2Params, sizeofArray(pattern2Params), aprefix);
|
||||
// check validity
|
||||
bool is_pattern2 = false;
|
||||
@@ -1165,15 +1200,14 @@ static NR_ServingCellConfig_t *get_scd_config(configmodule_interface_t *cfg)
|
||||
{
|
||||
NR_ServingCellConfig_t *scd = calloc(1, sizeof(*scd));
|
||||
prepare_scd(scd);
|
||||
paramdef_t SCDsParams[] = SCDPARAMS_DESC(scd);
|
||||
paramlist_def_t SCDsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, NULL, 0};
|
||||
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
config_getlist(cfg, &SCDsParamList, NULL, 0, aprefix);
|
||||
GET_PARAMS_LIST(SCDsParamList, SCDsParams, SCDPARAMS_DESC(scd), GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, aprefix);
|
||||
|
||||
if (SCDsParamList.numelt > 0) {
|
||||
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0);
|
||||
config_get(cfg, SCDsParams, sizeof(SCDsParams) / sizeof(paramdef_t), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0);
|
||||
GET_PARAMS(SCDsParams, SCDPARAMS_DESC(scd), aprefix);
|
||||
const NR_BWP_UplinkDedicated_t *bwp_Dedicated = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated;
|
||||
const NR_PTRS_UplinkConfig_t *setup =
|
||||
bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup;
|
||||
@@ -1206,15 +1240,11 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
|
||||
AssertFatal(max_cell_info == 1, "only one cell supported\n");
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
||||
config_get(cfg, GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs == 1, "cannot configure DU: required config section \"gNBs\" missing\n");
|
||||
|
||||
// Output a list of all eNBs.
|
||||
config_getlist(cfg, &GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
|
||||
// read the gNB-ID. The DU itself only needs the gNB-DU ID, but some (e.g.,
|
||||
// E2 agent) need the gNB-ID as well if it is running in a separate process
|
||||
@@ -1226,20 +1256,6 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
|
||||
GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[0],
|
||||
*GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr);
|
||||
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[0]", GNB_CONFIG_STRING_GNB_LIST);
|
||||
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
|
||||
"config_check_PLMNParams and PLMNParams should have the same size");
|
||||
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
||||
config_getlist(cfg, &PLMNParamList, PLMNParams, sizeof(PLMNParams) / sizeof(paramdef_t), aprefix);
|
||||
AssertFatal(PLMNParamList.numelt > 0, "need to have a PLMN in PLMN section\n");
|
||||
AssertFatal(PLMNParamList.numelt == 1, "cannot have more than one PLMN\n");
|
||||
|
||||
// if fronthaul is F1, require gNB_DU_ID, else use gNB_ID
|
||||
if (separate_du) {
|
||||
AssertFatal(config_isparamset(GNBParamList.paramarray[0], GNB_GNB_DU_ID_IDX), "%s is not defined in configuration file\n", GNB_CONFIG_STRING_GNB_DU_ID);
|
||||
@@ -1255,30 +1271,15 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
|
||||
info->tac = malloc(sizeof(*info->tac));
|
||||
AssertFatal(info->tac != NULL, "out of memory\n");
|
||||
*info->tac = *GNBParamList.paramarray[0][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
||||
info->plmn.mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
info->plmn.mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
info->plmn.mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
||||
AssertFatal((info->plmn.mnc_digit_length == 2) || (info->plmn.mnc_digit_length == 3),
|
||||
"BAD MNC DIGIT LENGTH %d",
|
||||
info->plmn.mnc_digit_length);
|
||||
|
||||
// PLMN
|
||||
plmn_id_t p[PLMN_LIST_MAX_SIZE] = {0};
|
||||
set_plmn_config(p, 0);
|
||||
info->plmn = p[0];
|
||||
info->nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr);
|
||||
|
||||
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
|
||||
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
|
||||
checkedparam_t config_check_SNSSAIParams[] = SNSSAIPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_SNSSAIParams) == sizeofArray(SNSSAIParams),
|
||||
"config_check_SNSSAIParams and SNSSAIParams should have the same size");
|
||||
for (int J = 0; J < sizeofArray(SNSSAIParams); ++J)
|
||||
SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]);
|
||||
char snssaistr[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(snssaistr, "%s.[0].%s.[0]", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_PLMN_LIST);
|
||||
config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeofArray(SNSSAIParams), snssaistr);
|
||||
info->num_ssi = SNSSAIParamList.numelt;
|
||||
for (int s = 0; s < info->num_ssi; ++s) {
|
||||
info->nssai[s].sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
||||
info->nssai[s].sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr;
|
||||
AssertFatal(info->nssai[s].sd <= 0xffffff, "SD cannot be bigger than 0xffffff, but is %d\n", info->nssai[s].sd);
|
||||
}
|
||||
// SNSSAI
|
||||
info->num_ssi = set_snssai_config(info->nssai, MAX_NUM_SLICES, 0, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1403,7 +1404,7 @@ static nr_redcap_config_t *get_redcap_config(int gnb_idx)
|
||||
{
|
||||
paramdef_t RedCap_Params[] = GNB_REDCAP_PARAMS_DESC;
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_REDCAP);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_REDCAP);
|
||||
int ret = config_get(config_get_if(), RedCap_Params, sizeofArray(RedCap_Params), aprefix);
|
||||
|
||||
if (ret <= 0) {
|
||||
@@ -1459,37 +1460,19 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
config_get(cfg, GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL, GNBPARAMS_CHECK);
|
||||
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs == 1,
|
||||
"Failed to parse config file: number of gnbs for gNB %s is %d != 1\n",
|
||||
GNB_CONFIG_STRING_ACTIVE_GNBS,
|
||||
num_gnbs);
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_GNBParams[] = GNBPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_GNBParams) == sizeofArray(GNBParams),
|
||||
"config_check_GNBParams and GNBParams should have the same size");
|
||||
for (int i = 0; i < sizeofArray(GNBParams); ++i)
|
||||
GNBParams[i].chkPptr = &(config_check_GNBParams[i]);
|
||||
config_getlist(cfg, &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
|
||||
paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC;
|
||||
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST, NULL, 0};
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_MacRLCParams[] = MACRLCPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_MacRLCParams) == sizeofArray(MacRLC_Params),
|
||||
"config_check_MacRLCParams and MacRLC_Params should have the same size");
|
||||
for (int i = 0; i < sizeofArray(MacRLC_Params); ++i)
|
||||
MacRLC_Params[i].chkPptr = &(config_check_MacRLCParams[i]);
|
||||
config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL);
|
||||
|
||||
// MAC / RLC
|
||||
GET_PARAMS_LIST(MacRLC_ParamList, MacRLC_Params, MACRLCPARAMS_DESC, CONFIG_STRING_MACRLC_LIST, NULL, MACRLCPARAMS_CHECK);
|
||||
nr_mac_config_t config = {0};
|
||||
config.pdsch_AntennaPorts.N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
||||
config.pdsch_AntennaPorts.N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
||||
config.pdsch_AntennaPorts.XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
||||
nr_pdsch_AntennaPorts_t *p = &config.pdsch_AntennaPorts;
|
||||
set_antenna_ports(&GNBParamList, &p->N1, &p->N2, &p->XP);
|
||||
config.pusch_AntennaPorts = *GNBParamList.paramarray[0][GNB_PUSCH_ANTENNAPORTS_IDX].iptr;
|
||||
LOG_I(GNB_APP,
|
||||
"pdsch_AntennaPorts N1 %d N2 %d XP %d pusch_AntennaPorts %d\n",
|
||||
@@ -1498,9 +1481,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
||||
config.pdsch_AntennaPorts.XP,
|
||||
config.pusch_AntennaPorts);
|
||||
|
||||
paramdef_t RUParams[] = RUPARAMS_DESC;
|
||||
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST, NULL, 0};
|
||||
config_getlist(config_get_if(), &RUParamList, RUParams, sizeofArray(RUParams), NULL);
|
||||
// RU
|
||||
GET_PARAMS_LIST(RUParamList, RUParams, RUPARAMS_DESC, CONFIG_STRING_RU_LIST, NULL);
|
||||
int num_tx = 0;
|
||||
if (RUParamList.numelt > 0) {
|
||||
for (int i = 0; i < RUParamList.numelt; i++)
|
||||
@@ -1519,6 +1501,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
||||
LOG_I(GNB_APP, "SIB1 TDA %d\n", config.sib1_tda);
|
||||
config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr;
|
||||
config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr;
|
||||
config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr;
|
||||
config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr;
|
||||
config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr;
|
||||
config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0;
|
||||
@@ -1529,9 +1512,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
||||
if (config.disable_harq)
|
||||
LOG_W(GNB_APP, "\"disable_harq\" is a REL17 feature and is incompatible with REL15 and REL16 UEs!\n");
|
||||
LOG_I(GNB_APP,
|
||||
"CSI-RS %d, SRS %d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n",
|
||||
"CSI-RS %d, SRS %d, SINR:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n",
|
||||
config.do_CSIRS,
|
||||
config.do_SRS,
|
||||
config.do_SINR,
|
||||
config.force_256qam_off ? "force off" : "may be on",
|
||||
config.use_deltaMCS ? "on" : "off",
|
||||
config.maxMIMO_layers,
|
||||
@@ -1543,10 +1527,9 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
||||
|
||||
config.redcap = get_redcap_config(0);
|
||||
|
||||
paramdef_t Timers_Params[] = GNB_TIMERS_PARAMS_DESC;
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
sprintf(aprefix, "%s.[0].%s", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_TIMERS_CONFIG);
|
||||
config_get(config_get_if(), Timers_Params, sizeofArray(Timers_Params), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_TIMERS_CONFIG);
|
||||
GET_PARAMS(Timers_Params, GNB_TIMERS_PARAMS_DESC, aprefix);
|
||||
|
||||
config.timer_config.sr_ProhibitTimer = *Timers_Params[GNB_TIMERS_SR_PROHIBIT_TIMER_IDX].iptr;
|
||||
config.timer_config.sr_TransMax = *Timers_Params[GNB_TIMERS_SR_TRANS_MAX_IDX].iptr;
|
||||
@@ -1910,12 +1893,14 @@ static seq_arr_t *fill_cu_sibs(paramdef_t *GNBparamarray)
|
||||
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);
|
||||
snprintf(gnbpath, sizeof(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};
|
||||
GET_PARAMS_LIST(neighbour_list_param_list,
|
||||
neighbour_list_params,
|
||||
GNB_NEIGHBOUR_LIST_PARAM_LIST,
|
||||
GNB_CONFIG_STRING_NEIGHBOUR_LIST,
|
||||
gnbpath);
|
||||
|
||||
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;
|
||||
|
||||
@@ -1928,10 +1913,12 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
|
||||
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);
|
||||
snprintf(neighbourpath, sizeof(neighbourpath), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm);
|
||||
GET_PARAMS_LIST(NeighbourCellParamList,
|
||||
NeighbourCellParams,
|
||||
GNBNEIGHBOURCELLPARAMS_DESC,
|
||||
GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST,
|
||||
neighbourpath);
|
||||
LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt);
|
||||
if (NeighbourCellParamList.numelt < 1)
|
||||
continue;
|
||||
@@ -1950,15 +1937,14 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
|
||||
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);
|
||||
snprintf(neighbour_plmn_path,
|
||||
sizeof(neighbour_plmn_path),
|
||||
"%s.%s.[%i].%s",
|
||||
neighbourpath,
|
||||
GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST,
|
||||
l,
|
||||
GNB_CONFIG_STRING_NEIGHBOUR_PLMN);
|
||||
GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path);
|
||||
|
||||
neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
@@ -1978,19 +1964,20 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
|
||||
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);
|
||||
snprintf(measurement_path, sizeof(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);
|
||||
snprintf(periodic_event_path,
|
||||
sizeof(periodic_event_path),
|
||||
"%s.[%i].%s.%s",
|
||||
GNB_CONFIG_STRING_GNB_LIST,
|
||||
gnb_idx,
|
||||
GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION,
|
||||
MEASUREMENT_EVENTS_PERIODICAL);
|
||||
GET_PARAMS(Periodical_EventParams, MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC, 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;
|
||||
@@ -2001,14 +1988,9 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
|
||||
|
||||
// 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);
|
||||
snprintf(a2_path, sizeof(a2_path), "%s.[%i].%s.%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, MEASUREMENT_EVENTS_A2);
|
||||
GET_PARAMS(A2_EventParams, MEASUREMENT_A2_GLOBALPARAMS_DESC, 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;
|
||||
@@ -2017,9 +1999,8 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
|
||||
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);
|
||||
GET_PARAMS_LIST(A3_EventList, A3_EventParams, MEASUREMENT_A3_GLOBALPARAMS_DESC, MEASUREMENT_EVENTS_A3, measurement_path);
|
||||
|
||||
LOG_D(GNB_APP, "HO LOG: A3 Configuration Exists: %d\n", A3_EventList.numelt);
|
||||
|
||||
if (A3_EventList.numelt < 1)
|
||||
@@ -2057,29 +2038,17 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
gNB_RRC_INST *rrc = calloc(1, sizeof(*rrc));
|
||||
|
||||
int num_gnbs = 0;
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
int32_t gnb_id = 0;
|
||||
int k = 0;
|
||||
int i = 0;
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
////////// Identification parameters
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
||||
|
||||
////////// Physical parameters
|
||||
|
||||
/* get global parameters, defined outside any section in the config file */
|
||||
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal (i < num_gnbs,"Failed to parse config file no %dth element in %s \n", i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
||||
AssertFatal(num_gnbs == 1, "required section \"gNBs\" not in config!\n");
|
||||
|
||||
if (num_gnbs > 0) {
|
||||
|
||||
// Output a list of all gNBs. ////////// Identification parameters
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
if (GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr == NULL) {
|
||||
// Calculate a default gNB ID
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
@@ -2093,17 +2062,15 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
gnb_id = *(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr);
|
||||
}
|
||||
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
|
||||
LOG_D(GNB_APP, "NRRRC %d: Southbound Transport %s\n", i, *(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr));
|
||||
|
||||
rrc->node_type = get_node_type();
|
||||
rrc->node_id = gnb_id;
|
||||
|
||||
if (NODE_IS_CU(rrc->node_type)) {
|
||||
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
sprintf(aprefix,"%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG);
|
||||
config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG);
|
||||
GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix);
|
||||
LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n", k, rrc->node_id);
|
||||
rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
|
||||
LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n", k, rrc->node_name);
|
||||
@@ -2116,8 +2083,6 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
rrc->eth_params_s.transp_preference = ETH_UDP_MODE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr);
|
||||
|
||||
if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) {
|
||||
@@ -2138,9 +2103,6 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
gNB_RrcConfigurationReq nrrrc_config = {0};
|
||||
for (k=0; k <num_gnbs ; k++) {
|
||||
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[k], *(GNBParamList.paramarray[i][GNB_GNB_NAME_IDX].strptr) )== 0) {
|
||||
|
||||
char gnbpath[MAX_OPTNAME_SIZE + 8];
|
||||
sprintf(gnbpath,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
||||
|
||||
fill_neighbour_cell_configuration(k, rrc);
|
||||
|
||||
@@ -2148,17 +2110,6 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
|
||||
rrc->SIBs = fill_cu_sibs(GNBParamList.paramarray[i]);
|
||||
|
||||
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
||||
|
||||
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
|
||||
"config_check_PLMNParams and PLMNParams should have the same size");
|
||||
|
||||
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
|
||||
nrrrc_config.tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
||||
AssertFatal(!GNBParamList.paramarray[i][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr
|
||||
&& !GNBParamList.paramarray[i][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr,
|
||||
@@ -2169,23 +2120,8 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
"to\n"
|
||||
" tracking_area_code = 1; // no string!!\n"
|
||||
" plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n");
|
||||
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), gnbpath);
|
||||
|
||||
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
||||
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
||||
PLMNParamList.numelt);
|
||||
|
||||
nrrrc_config.num_plmn = PLMNParamList.numelt;
|
||||
|
||||
for (int l = 0; l < PLMNParamList.numelt; ++l) {
|
||||
|
||||
nrrrc_config.mcc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
nrrrc_config.mnc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
nrrrc_config.mnc_digit_length[l] = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
||||
AssertFatal((nrrrc_config.mnc_digit_length[l] == 2) ||
|
||||
(nrrrc_config.mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d",
|
||||
nrrrc_config.mnc_digit_length[l]);
|
||||
}
|
||||
nrrrc_config.num_plmn = set_plmn_config(nrrrc_config.plmn, k);
|
||||
nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
|
||||
LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled");
|
||||
nrrrc_config.drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr;
|
||||
@@ -2202,32 +2138,17 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
return rrc;
|
||||
}
|
||||
|
||||
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
|
||||
|
||||
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i)
|
||||
{
|
||||
int j,k = 0;
|
||||
int gnb_id;
|
||||
int32_t my_int;
|
||||
const char* active_gnb[MAX_GNB];
|
||||
char *address = NULL;
|
||||
char *cidr = NULL;
|
||||
|
||||
// for no gcc warnings
|
||||
|
||||
(void) my_int;
|
||||
|
||||
memset((char*)active_gnb,0,MAX_GNB* sizeof(char*));
|
||||
char* gnb_ipv4_address_for_NGU = NULL;
|
||||
uint32_t gnb_port_for_NGU = 0;
|
||||
char* gnb_ipv4_address_for_S1U = NULL;
|
||||
uint32_t gnb_port_for_S1U = 0;
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
||||
|
||||
/* get global parameters, defined outside any section in the config file */
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
AssertFatal (i<GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
|
||||
"Failed to parse config file %s, %uth attribute %s \n",
|
||||
RC.config_file_name, i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
||||
@@ -2235,7 +2156,7 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
|
||||
|
||||
if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt>0) {
|
||||
// Output a list of all gNBs.
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
if (GNBParamList.numelt > 0) {
|
||||
for (k = 0; k < GNBParamList.numelt; k++) {
|
||||
if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) {
|
||||
@@ -2256,31 +2177,8 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
|
||||
// search if in active list
|
||||
for (j=0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) {
|
||||
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
||||
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
||||
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
||||
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
|
||||
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
|
||||
"config_check_PLMNParams and PLMNParams should have the same size");
|
||||
checkedparam_t config_check_SNSSAIParams [] = SNSSAIPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_SNSSAIParams) == sizeofArray(SNSSAIParams),
|
||||
"config_check_SNSSAIParams and SNSSAIParams should have the same size");
|
||||
|
||||
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
for (int J = 0; J < sizeofArray(SNSSAIParams); ++J)
|
||||
SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]);
|
||||
|
||||
paramdef_t NGParams[] = GNBNGPARAMS_DESC;
|
||||
paramlist_def_t NGParamList = {GNB_CONFIG_STRING_AMF_IP_ADDRESS,NULL,0};
|
||||
|
||||
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
||||
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k);
|
||||
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).gNB_id = gnb_id;
|
||||
|
||||
if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) {
|
||||
@@ -2304,108 +2202,57 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
|
||||
"to\n"
|
||||
" tracking_area_code = 1; // no string!!\n"
|
||||
" plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n");
|
||||
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix);
|
||||
|
||||
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
||||
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
||||
PLMNParamList.numelt);
|
||||
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt;
|
||||
|
||||
for (int l = 0; l < PLMNParamList.numelt; ++l) {
|
||||
char snssaistr[MAX_OPTNAME_SIZE*2 + 8];
|
||||
sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l);
|
||||
config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeofArray(SNSSAIParams), snssaistr);
|
||||
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).default_drx = 0;
|
||||
AssertFatal((NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length == 2)
|
||||
|| (NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length == 3),
|
||||
"BAD MNC DIGIT LENGTH %d",
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length);
|
||||
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = SNSSAIParamList.numelt;
|
||||
for (int s = 0; s < SNSSAIParamList.numelt; ++s) {
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai[s].sst =
|
||||
*SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
||||
// SD is optional
|
||||
// 0xffffff is "no SD", see 23.003 Sec 28.4.2
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai[s].sd =
|
||||
(*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0xffffff);
|
||||
}
|
||||
// PLMN
|
||||
plmn_id_t p[PLMN_LIST_MAX_SIZE] = {0};
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = set_plmn_config(p, 0);
|
||||
for (int l = 0; l < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; ++l) {
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn = p[l];
|
||||
// SNSSAI
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = set_snssai_config(NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai, 8, k, l);
|
||||
}
|
||||
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
||||
config_getlist(config_get_if(), &NGParamList, NGParams, sizeofArray(NGParams), aprefix);
|
||||
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).default_drx = 0;
|
||||
// NG
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k);
|
||||
GET_PARAMS_LIST(NGParamList, NGParams, GNBNGPARAMS_DESC, GNB_CONFIG_STRING_AMF_IP_ADDRESS, aprefix);
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0;
|
||||
|
||||
for (int l = 0; l < NGParamList.numelt; l++) {
|
||||
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).nb_amf += 1;
|
||||
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[l].ipv4_address,*(NGParamList.paramarray[l][GNB_AMF_IPV4_ADDRESS_IDX].strptr));
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv4 = 1;
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv6 = 0;
|
||||
|
||||
/* not in configuration yet ...
|
||||
if (NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr)
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].numelt;
|
||||
else
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = 0;
|
||||
|
||||
AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] <= NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
||||
"List of broadcast PLMN to be sent to AMF can not be longer than actual "
|
||||
"PLMN list (max %d, but is %d)\n",
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]);
|
||||
|
||||
for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]; ++el) {
|
||||
// UINTARRAY gets mapped to int, see config_libconfig.c:223
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr[el];
|
||||
AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] >= 0
|
||||
&& NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
||||
"index for AMF's MCC/MNC (%d) is an invalid index for the registered PLMN IDs (%d)\n",
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el],
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn);
|
||||
}
|
||||
*/
|
||||
|
||||
/* if no broadcasst_plmn array is defined, fill default values */
|
||||
if (NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] == 0) {
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGAP_REGISTER_GNB_REQ(msg_p).num_plmn;
|
||||
|
||||
for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; ++el)
|
||||
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = el;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// SCTP SETTING
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
||||
config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_SCTP_CONFIG);
|
||||
GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix);
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
||||
}
|
||||
|
||||
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
||||
// NETWORK_INTERFACES
|
||||
config_get(config_get_if(), NETParams, sizeofArray(NETParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
||||
GET_PARAMS(NETParams, GNBNETPARAMS_DESC, aprefix);
|
||||
if (NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr != NULL) {
|
||||
char *cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr);
|
||||
char *save = NULL;
|
||||
char *address = strtok_r(cidr, "/", &save);
|
||||
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4_address, address);
|
||||
LOG_I(GNB_APP, "Parsed IPv4 address for NG AMF: %s\n", address);
|
||||
}
|
||||
|
||||
// NGAP_REGISTER_GNB_REQ (msg_p).enb_interface_name_for_NGU = strdup(enb_interface_name_for_NGU);
|
||||
cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr);
|
||||
char *save = NULL;
|
||||
address = strtok_r(cidr, "/", &save);
|
||||
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv6 = 0;
|
||||
NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4 = 1;
|
||||
|
||||
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4_address, address);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2434,8 +2281,7 @@ void NRRCConfig(void)
|
||||
|
||||
memset((void *)&RC, 0, sizeof(RC));
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
|
||||
// Set num of gNBs instances
|
||||
RC.nb_nr_inst = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
@@ -2482,23 +2328,16 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
||||
int J, l;
|
||||
char *address = NULL;
|
||||
char *cidr = NULL;
|
||||
//int num_gnbs = 0;
|
||||
//int num_component_carriers = 0;
|
||||
int j,k = 0;
|
||||
int32_t gnb_id = 0;
|
||||
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
////////// Identification parameters
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
||||
/* get global parameters, defined outside any section in the config file */
|
||||
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
||||
GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL);
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = calloc_or_fail(1, sizeof(*scc));
|
||||
uint64_t ssb_bitmap=0xff;
|
||||
memset((void*)scc,0,sizeof(NR_ServingCellConfigCommon_t));
|
||||
prepare_scc(scc);
|
||||
paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
|
||||
paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
||||
|
||||
AssertFatal(i < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
|
||||
"Failed to parse config file %s, %uth attribute %s \n",
|
||||
@@ -2506,7 +2345,7 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
||||
|
||||
if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt > 0) {
|
||||
// Output a list of all gNBs.
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
|
||||
if (GNBParamList.numelt > 0) {
|
||||
for (k = 0; k < GNBParamList.numelt; k++) {
|
||||
@@ -2526,29 +2365,13 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
||||
// search if in active list
|
||||
for (j = 0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) {
|
||||
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
||||
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
||||
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
||||
/* map parameter checking array instances to parameter definition array instances */
|
||||
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
||||
static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams),
|
||||
"config_check_PLMNParams and PLMNParams should have the same size");
|
||||
|
||||
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
||||
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
||||
char* gnb_ipv4_address_for_NGU = NULL;
|
||||
uint32_t gnb_port_for_NGU = 0;
|
||||
char* gnb_ipv4_address_for_S1U = NULL;
|
||||
uint32_t gnb_port_for_S1U = 0;
|
||||
|
||||
paramdef_t X2Params[] = X2PARAMS_DESC;
|
||||
paramlist_def_t X2ParamList = {ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS,NULL,0};
|
||||
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
||||
char* gnb_ipv4_address_for_NGU = NULL;
|
||||
uint32_t gnb_port_for_NGU = 0;
|
||||
char* gnb_ipv4_address_for_S1U = NULL;
|
||||
uint32_t gnb_port_for_S1U = 0;
|
||||
|
||||
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
||||
/* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */
|
||||
/* this is most probably a problem with the config module */
|
||||
char aprefix[MAX_OPTNAME_SIZE*80 + 8];
|
||||
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
||||
/* Some default/random parameters */
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).eNB_id = gnb_id;
|
||||
|
||||
@@ -2562,29 +2385,26 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
||||
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr));
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
||||
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix);
|
||||
|
||||
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
||||
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
||||
PLMNParamList.numelt);
|
||||
|
||||
if (PLMNParamList.numelt > 1)
|
||||
// PLMN
|
||||
plmn_id_t p[PLMN_LIST_MAX_SIZE];
|
||||
uint8_t num_plmn = set_plmn_config(p, k);
|
||||
if (num_plmn > 1)
|
||||
LOG_W(X2AP, "X2AP currently handles only one PLMN, ignoring the others!\n");
|
||||
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
||||
X2AP_REGISTER_ENB_REQ(msg_p).mcc = p[0].mcc;
|
||||
X2AP_REGISTER_ENB_REQ(msg_p).mnc = p[0].mnc;
|
||||
X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length = p[0].mnc_digit_length;
|
||||
AssertFatal(X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3
|
||||
|| X2AP_REGISTER_ENB_REQ(msg_p).mnc < 100,
|
||||
"MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n",
|
||||
X2AP_REGISTER_ENB_REQ(msg_p).mnc);
|
||||
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
|
||||
config_getlist(config_get_if(), &SCCsParamList, NULL, 0, aprefix);
|
||||
char aprefix[MAX_OPTNAME_SIZE * 80 + 8];
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix);
|
||||
if (SCCsParamList.numelt > 0) {
|
||||
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
||||
config_get(config_get_if(), SCCsParams, sizeofArray(SCCsParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
||||
GET_PARAMS(SCCsParams, SCCPARAMS_DESC(scc), aprefix);
|
||||
fix_scc(scc,ssb_bitmap);
|
||||
}
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).num_cc = SCCsParamList.numelt;
|
||||
@@ -2604,8 +2424,9 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).num_cc);
|
||||
}
|
||||
|
||||
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
||||
config_getlist(config_get_if(), &X2ParamList, X2Params, sizeofArray(X2Params), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k);
|
||||
GET_PARAMS_LIST(X2ParamList, X2Params, X2PARAMS_DESC, ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS, aprefix);
|
||||
|
||||
AssertFatal(X2ParamList.numelt <= X2AP_MAX_NB_ENB_IP_ADDRESS,
|
||||
"value of X2ParamList.numelt %d must be lower than X2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase X2AP_MAX_NB_ENB_IP_ADDRESS\n",
|
||||
X2ParamList.numelt,X2AP_MAX_NB_ENB_IP_ADDRESS);
|
||||
@@ -2650,15 +2471,15 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
||||
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
||||
config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_SCTP_CONFIG);
|
||||
GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix);
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
||||
}
|
||||
|
||||
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
||||
// NETWORK_INTERFACES
|
||||
config_get(config_get_if(), NETParams, sizeofArray(NETParams), aprefix);
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
||||
GET_PARAMS(NETParams, GNBNETPARAMS_DESC, aprefix);
|
||||
X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C = (uint32_t)*(NETParams[GNB_PORT_FOR_X2C_IDX].uptr);
|
||||
|
||||
//temp out
|
||||
@@ -2702,7 +2523,7 @@ void wait_f1_setup_response(void)
|
||||
}
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
}
|
||||
static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn)
|
||||
static bool check_plmn_identity(const plmn_id_t *check_plmn, const plmn_id_t *plmn)
|
||||
{
|
||||
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
|
||||
}
|
||||
@@ -2766,28 +2587,22 @@ int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_up
|
||||
|
||||
ngran_node_t get_node_type(void)
|
||||
{
|
||||
paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC;
|
||||
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0};
|
||||
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
||||
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
||||
paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC;
|
||||
paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0};
|
||||
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
|
||||
GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL);
|
||||
if (GNBParamList.numelt == 0) // We have no valid configuration, let's return a default
|
||||
return ngran_gNB;
|
||||
|
||||
config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL);
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
config_getlist(config_get_if(), &GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix);
|
||||
for (int j = 0; j < MacRLC_ParamList.numelt; j++) {
|
||||
// MAC/RLC params
|
||||
GET_PARAMS_LIST(MacRLC_ParamList, MacRLC_Params, MACRLCPARAMS_DESC, CONFIG_STRING_MACRLC_LIST, NULL);
|
||||
for (int j = 0; j < RC.nb_nr_macrlc_inst; j++) {
|
||||
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "f1") == 0) {
|
||||
return ngran_gNB_DU; // MACRLCs present in config: it must be a DU
|
||||
}
|
||||
}
|
||||
|
||||
// E1 params
|
||||
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
||||
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
GET_PARAMS_LIST(GNBE1ParamList, GNBE1Params, GNBE1PARAMS_DESC, GNB_CONFIG_STRING_E1_PARAMETERS, aprefix);
|
||||
if (strcmp(*(GNBParamList.paramarray[0][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "f1") == 0) {
|
||||
if ( GNBE1ParamList.paramarray == NULL || GNBE1ParamList.numelt == 0 )
|
||||
return ngran_gNB_CU;
|
||||
|
||||
@@ -46,51 +46,15 @@
|
||||
}\
|
||||
} while (0);
|
||||
|
||||
/** @defgroup _enb_app ENB APP
|
||||
* @ingroup _oai2
|
||||
* @{
|
||||
*/
|
||||
|
||||
// Hard to find a defined value for max enb...
|
||||
#define MAX_GNB 16
|
||||
|
||||
/*
|
||||
typedef struct mme_ip_address_s {
|
||||
unsigned ipv4:1;
|
||||
unsigned ipv6:1;
|
||||
unsigned active:1;
|
||||
char *ipv4_address;
|
||||
char *ipv6_address;
|
||||
} mme_ip_address_t;
|
||||
|
||||
typedef struct ru_config_s {
|
||||
// indicates if local or remote rf is used (1 == LOCAL)
|
||||
unsigned local_rf:1;
|
||||
// indicates if UDP socket is used
|
||||
unsigned udp:1;
|
||||
// indicates if RAW socket is used
|
||||
unsigned raw:1;
|
||||
char *ru_if_name;
|
||||
char *local_address;
|
||||
char *remote_address;
|
||||
uint16_t local_port;
|
||||
uint16_t remote_port;
|
||||
uint8_t udpif4p5;
|
||||
uint8_t rawif4p5;
|
||||
uint8_t rawif5_mobipass;
|
||||
uint8_t if_compress;
|
||||
} ru_config_t;
|
||||
*/
|
||||
|
||||
void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type);
|
||||
extern void RCconfig_nr_prs(void);
|
||||
extern void RCconfig_NR_L1(void);
|
||||
extern void RCconfig_nr_macrlc(configmodule_interface_t *cfg);
|
||||
extern void NRRCConfig(void);
|
||||
|
||||
//void enb_config_display(void);
|
||||
//void ru_config_display(void);
|
||||
|
||||
gNB_RRC_INST *RCconfig_NRRRC();
|
||||
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i);
|
||||
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
|
||||
|
||||
@@ -141,6 +141,7 @@ typedef enum {
|
||||
#define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels"
|
||||
#define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs"
|
||||
#define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs"
|
||||
#define GNB_CONFIG_STRING_DOSINR "do_SINR"
|
||||
|
||||
#define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n"
|
||||
#define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support"
|
||||
@@ -154,6 +155,7 @@ typedef enum {
|
||||
#define GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST "List of aggregation levels with number of candidates per level. Element 0 - aggregation level 1"
|
||||
#define GNB_CONFIG_HLP_CU_SIBS "List of CU generated SIBs to be transmitted"
|
||||
#define GNB_CONFIG_HLP_DU_SIBS "List of DU generated SIBs to be transmitted"
|
||||
#define GNB_CONFIG_HLP_DOSINR "Enable CSI feedback using SINR measurements on SSB"
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* cell configuration parameters */
|
||||
@@ -201,6 +203,7 @@ typedef enum {
|
||||
GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \
|
||||
{GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
|
||||
{GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
|
||||
{GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -244,6 +247,7 @@ typedef enum {
|
||||
#define GNB_UESS_AGG_LEVEL_LIST_IDX 36
|
||||
#define GNB_CU_SIBS_IDX 37
|
||||
#define GNB_DU_SIBS_IDX 38
|
||||
#define GNB_DO_SINR_IDX 39
|
||||
|
||||
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
|
||||
#define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32}
|
||||
@@ -289,6 +293,7 @@ typedef enum {
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
@@ -517,7 +517,9 @@ typedef struct {
|
||||
uint8_t cri_ssbri_bitlen;
|
||||
uint8_t rsrp_bitlen;
|
||||
uint8_t diff_rsrp_bitlen;
|
||||
} L1_RSRP_bitlen_t;
|
||||
uint8_t sinr_bitlen;
|
||||
uint8_t diff_sinr_bitlen;
|
||||
} L1_Meas_bitlen_t;
|
||||
|
||||
typedef struct{
|
||||
uint8_t ri_restriction;
|
||||
@@ -535,13 +537,14 @@ typedef struct{
|
||||
typedef struct nr_csi_report {
|
||||
NR_CSI_ReportConfigId_t reportConfigId;
|
||||
NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type;
|
||||
NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16;
|
||||
long periodicity;
|
||||
uint16_t offset;
|
||||
long **SSB_Index_list;
|
||||
long **CSI_Index_list;
|
||||
// uint8_t nb_of_nzp_csi_report;
|
||||
uint8_t nb_of_csi_ssb_report;
|
||||
L1_RSRP_bitlen_t CSI_report_bitlen;
|
||||
L1_Meas_bitlen_t CSI_report_bitlen;
|
||||
CSI_Meas_bitlen_t csi_meas_bitlen;
|
||||
int codebook_mode;
|
||||
int N1;
|
||||
|
||||
@@ -4305,12 +4305,21 @@ int get_f3_dmrs_symbols(NR_PUCCH_Resource_t *pucchres, NR_PUCCH_Config_t *pucch_
|
||||
|
||||
uint16_t compute_pucch_prb_size(uint8_t format,
|
||||
uint8_t nr_prbs,
|
||||
uint16_t O_uci,
|
||||
uint16_t O_csi,
|
||||
uint16_t O_ack,
|
||||
uint8_t O_sr,
|
||||
NR_PUCCH_MaxCodeRate_t *maxCodeRate,
|
||||
uint8_t Qm,
|
||||
uint8_t n_symb,
|
||||
uint8_t n_re_ctrl)
|
||||
{
|
||||
// TODO: Consider also the case where there is a HARQ-ACK in response to a PDSCH reception without a corresponding PDCCH
|
||||
// as described in the 3GPP TS 38.213 - Section 9.2.5.2
|
||||
if (O_csi > 0 && O_ack == 0) {
|
||||
return nr_prbs;
|
||||
}
|
||||
|
||||
int O_uci = O_csi + O_ack + O_sr;
|
||||
int O_crc = compute_pucch_crc_size(O_uci);
|
||||
int O_tot = O_uci + O_crc;
|
||||
|
||||
@@ -4427,7 +4436,10 @@ static uint8_t number_of_bits_set(uint8_t buf)
|
||||
return nb_of_bits_set;
|
||||
}
|
||||
|
||||
static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t nb_resources, nr_csi_report_t *csi_report)
|
||||
static void compute_rsrp_or_sinr_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig,
|
||||
uint8_t nb_resources,
|
||||
nr_csi_report_t *csi_report,
|
||||
bool is_RSRP_configured)
|
||||
{
|
||||
if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) {
|
||||
if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)
|
||||
@@ -4445,13 +4457,20 @@ static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, u
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri = 2;
|
||||
|
||||
if (nb_resources) {
|
||||
csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources));
|
||||
csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
csi_report->CSI_report_bitlen.cri_ssbri_bitlen = ceil(log2 (nb_resources));
|
||||
if (is_RSRP_configured) {
|
||||
csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
} else {
|
||||
csi_report->CSI_report_bitlen.sinr_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6A: CRI, SSBRI, and SINR
|
||||
csi_report->CSI_report_bitlen.diff_sinr_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6A: CRI, SSBRI, and SINR
|
||||
}
|
||||
} else {
|
||||
csi_report->CSI_report_bitlen.cri_ssbri_bitlen = 0;
|
||||
csi_report->CSI_report_bitlen.rsrp_bitlen = 0;
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 0;
|
||||
csi_report->CSI_report_bitlen.sinr_bitlen = 0;
|
||||
csi_report->CSI_report_bitlen.diff_sinr_bitlen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4878,9 +4897,13 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report
|
||||
reportQuantity_type = csi_reportconfig->reportQuantity.present;
|
||||
csi_report->reportQuantity_type = reportQuantity_type;
|
||||
csi_report->reportConfigId = csi_reportconfig->reportConfigId;
|
||||
csi_report->reportQuantity_type_r16 = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING;
|
||||
if (csi_reportconfig->ext2 != NULL && csi_reportconfig->ext2->reportQuantity_r16)
|
||||
csi_report->reportQuantity_type_r16 = csi_reportconfig->ext2->reportQuantity_r16->present;
|
||||
|
||||
// setting the CSI or SSB index list
|
||||
if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type) {
|
||||
if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type
|
||||
|| NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16 == csi_report->reportQuantity_type_r16) {
|
||||
for (int csi_idx = 0; csi_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_idx++) {
|
||||
if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceSetId ==
|
||||
*(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){
|
||||
@@ -4891,8 +4914,7 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (resourceType == NR_CSI_ResourceConfig__resourceType_periodic) {
|
||||
AssertFatal(csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList != NULL,
|
||||
"Wrong settings! Report quantity requires CSI-RS but csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList is NULL\n");
|
||||
@@ -4911,33 +4933,46 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report
|
||||
}
|
||||
LOG_D(NR_MAC,"nb_resources %d\n",nb_resources);
|
||||
// computation of bit length depending on the report type
|
||||
switch(reportQuantity_type){
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP):
|
||||
compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP):
|
||||
compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Not yet supported CSI report quantity type");
|
||||
if (csi_report->reportQuantity_type_r16 != NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING) {
|
||||
switch (csi_report->reportQuantity_type_r16) {
|
||||
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16:
|
||||
compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, false);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16:
|
||||
compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, false);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Not yet supported CSI report quantity type");
|
||||
}
|
||||
} else {
|
||||
switch (reportQuantity_type) {
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP):
|
||||
compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, true);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP):
|
||||
compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, true);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Not yet supported CSI report quantity type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4946,11 +4981,16 @@ uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report)
|
||||
{
|
||||
uint16_t csi_bitlen = 0;
|
||||
uint16_t max_bitlen = 0;
|
||||
L1_RSRP_bitlen_t *CSI_report_bitlen = NULL;
|
||||
L1_Meas_bitlen_t *CSI_report_bitlen = NULL;
|
||||
CSI_Meas_bitlen_t *csi_meas_bitlen = NULL;
|
||||
|
||||
if (csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP ||
|
||||
csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) {
|
||||
if (csi_report->reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16
|
||||
|| csi_report->reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16) {
|
||||
CSI_report_bitlen = &(csi_report->CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements
|
||||
csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + CSI_report_bitlen->sinr_bitlen
|
||||
+ (CSI_report_bitlen->diff_sinr_bitlen * (CSI_report_bitlen->nb_ssbri_cri - 1)));
|
||||
} else if (csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
|
||||
|| csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) {
|
||||
CSI_report_bitlen = &(csi_report->CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements
|
||||
csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) +
|
||||
CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen *
|
||||
|
||||
@@ -254,7 +254,9 @@ uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config,
|
||||
|
||||
uint16_t compute_pucch_prb_size(uint8_t format,
|
||||
uint8_t nr_prbs,
|
||||
uint16_t O_uci,
|
||||
uint16_t O_csi,
|
||||
uint16_t O_ack,
|
||||
uint8_t O_sr,
|
||||
NR_PUCCH_MaxCodeRate_t *maxCodeRate,
|
||||
uint8_t Qm,
|
||||
uint8_t n_symb,
|
||||
|
||||
@@ -417,6 +417,7 @@ typedef struct {
|
||||
uint32_t ssb_index;
|
||||
/// SSB RSRP in dBm
|
||||
short ssb_rsrp_dBm;
|
||||
float_t ssb_sinr_dB;
|
||||
} NR_SSB_meas_t;
|
||||
|
||||
typedef enum ta_type {
|
||||
|
||||
@@ -1633,7 +1633,9 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
|
||||
pucch_pdu->dmrs_scrambling_id = id0 != NULL ? *id0 : mac->physCellId;
|
||||
pucch_pdu->prb_size = compute_pucch_prb_size(2,
|
||||
pucchres->format.choice.format2->nrofPRBs,
|
||||
n_uci,
|
||||
pucch->n_csi,
|
||||
pucch->n_harq,
|
||||
pucch->n_sr,
|
||||
pucch_Config->format2->choice.setup->maxCodeRate,
|
||||
2,
|
||||
pucchres->format.choice.format2->nrofSymbols,
|
||||
@@ -1666,7 +1668,9 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
|
||||
}
|
||||
pucch_pdu->prb_size = compute_pucch_prb_size(3,
|
||||
pucchres->format.choice.format3->nrofPRBs,
|
||||
n_uci,
|
||||
pucch->n_csi,
|
||||
pucch->n_harq,
|
||||
pucch->n_sr,
|
||||
pucch_Config->format3->choice.setup->maxCodeRate,
|
||||
2 - pucch_pdu->pi_2bpsk,
|
||||
pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols,
|
||||
@@ -2643,6 +2647,111 @@ int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCC
|
||||
return num_csi;
|
||||
}
|
||||
|
||||
// Referred - Table 10.1.16.1-1 in 38.133 V16.7.0.
|
||||
static uint8_t get_sinr_index(float sinr)
|
||||
{
|
||||
int index = sinr * 2 + 47;
|
||||
if (sinr >= 40)
|
||||
index = 127;
|
||||
if (sinr < -23)
|
||||
index = 0;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Reffered Table 10.1.16.1-2 in 38.133 V16.7.0. Differential value is reported.
|
||||
static uint8_t get_sinr_diff_index(float best_sinr, float current_sinr)
|
||||
{
|
||||
int diff = best_sinr - current_sinr;
|
||||
if (diff >= 15)
|
||||
return 15;
|
||||
else if (diff <= 0)
|
||||
return 0;
|
||||
else
|
||||
return diff;
|
||||
}
|
||||
|
||||
static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
|
||||
struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
|
||||
NR_CSI_MeasConfig_t *csi_MeasConfig)
|
||||
{
|
||||
int nb_ssb = 0; // nb of ssb in the resource
|
||||
int nb_meas = 0; // nb of ssb to report measurements on
|
||||
int bits = 0;
|
||||
uint32_t temp_payload = 0;
|
||||
|
||||
for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) {
|
||||
struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx];
|
||||
if (csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) {
|
||||
if (csi_reportconfig->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled) {
|
||||
if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS != NULL)
|
||||
nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1;
|
||||
else
|
||||
nb_meas = 1;
|
||||
} else
|
||||
nb_meas = 2;
|
||||
|
||||
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource;
|
||||
for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) {
|
||||
if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId
|
||||
== *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) {
|
||||
SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList;
|
||||
/// only one SSB resource set from spec 38.331 IE CSI-ResourceConfig
|
||||
nb_ssb = SSB_resource.list.count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal(nb_ssb > 0, "No SSB found in the resource set\n");
|
||||
AssertFatal(nb_meas == 1, "PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n");
|
||||
int ssbri_bits = ceil(log2(nb_ssb));
|
||||
|
||||
int ssb_index[nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs)
|
||||
float ssb_sinr[nb_meas];
|
||||
|
||||
// TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs
|
||||
for (int i = 0; i < nb_ssb; i++) {
|
||||
ssb_index[i] = -1;//Invalid index
|
||||
if (*SSB_resource.list.array[i] == mac->mib_ssb) {
|
||||
ssb_index[0] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AssertFatal(ssb_index[0] >= 0, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n");
|
||||
ssb_sinr[0] = mac->ssb_measurements.ssb_sinr_dB;
|
||||
|
||||
uint8_t ssbi;
|
||||
|
||||
// TS38.212 v16.5.0: Table 6.3.1.1.2-8A
|
||||
if (ssbri_bits > 0) {
|
||||
ssbi = ssb_index[0];
|
||||
temp_payload = reverse_bits(ssbi, ssbri_bits);
|
||||
bits += ssbri_bits;
|
||||
}
|
||||
|
||||
uint8_t sinr_idx = get_sinr_index(ssb_sinr[0]);
|
||||
temp_payload |= (reverse_bits(sinr_idx, 7) << bits);
|
||||
bits += 7; // 7 bits for highest SINR
|
||||
|
||||
// from the second SSB, differential report
|
||||
for (int i = 1; i < nb_meas; i++) {
|
||||
ssbi = ssb_index[i];
|
||||
temp_payload = reverse_bits(ssbi, ssbri_bits);
|
||||
bits += ssbri_bits;
|
||||
|
||||
sinr_idx = get_sinr_diff_index(ssb_sinr[0], ssb_sinr[i]);
|
||||
temp_payload |= (reverse_bits(sinr_idx, 4) << bits);
|
||||
bits += 4; // 7 bits for highest SINR
|
||||
}
|
||||
break; // resource found
|
||||
}
|
||||
}
|
||||
AssertFatal(bits <= 32, "Not supporting CSI report with more than 32 bits\n");
|
||||
csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = bits, csi.p2_bits = 0};
|
||||
return csi;
|
||||
}
|
||||
|
||||
csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
|
||||
int csi_report_id,
|
||||
CSI_mapping_t mapping_type,
|
||||
@@ -2652,26 +2761,39 @@ csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
|
||||
csi_payload_t csi = {0};
|
||||
struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
|
||||
NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement;
|
||||
switch(csi_reportconfig->reportQuantity.present) {
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_none:
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP:
|
||||
csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
|
||||
csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
|
||||
csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
|
||||
LOG_E(NR_MAC,"Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Invalid CSI report quantity type %d\n",csi_reportconfig->reportQuantity.present);
|
||||
if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) {
|
||||
switch (csi_reportconfig->ext2->reportQuantity_r16->present) {
|
||||
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16:
|
||||
csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16:
|
||||
LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n");
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present);
|
||||
}
|
||||
} else {
|
||||
switch (csi_reportconfig->reportQuantity.present) {
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_none:
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP:
|
||||
csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
|
||||
csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
|
||||
csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
|
||||
LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present);
|
||||
}
|
||||
}
|
||||
return csi;
|
||||
}
|
||||
|
||||
@@ -958,7 +958,7 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac,
|
||||
mac->mac_rrc.gnb_du_configuration_update(&update);
|
||||
}
|
||||
|
||||
void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const f1ap_plmn_t *plmn, uint64_t cellID, int tac)
|
||||
void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac)
|
||||
{
|
||||
AssertFatal(IS_SA_MODE(get_softmodem_params()), "error: SIB1 only applicable for SA\n");
|
||||
|
||||
|
||||
@@ -177,16 +177,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo
|
||||
start_meas(&gNB->eNB_scheduler);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
|
||||
|
||||
/* send tick to RLC, PDCP, and X2AP every ms */
|
||||
if ((slot & ((1 << *scc->ssbSubcarrierSpacing) - 1)) == 0) {
|
||||
void nr_rlc_tick(int frame, int subframe);
|
||||
void nr_pdcp_tick(int frame, int subframe);
|
||||
nr_rlc_tick(frame, slot >> *scc->ssbSubcarrierSpacing);
|
||||
nr_pdcp_tick(frame, slot >> *scc->ssbSubcarrierSpacing);
|
||||
if (is_x2ap_enabled())
|
||||
x2ap_trigger();
|
||||
}
|
||||
|
||||
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
int num_beams = 1;
|
||||
if(gNB->beam_info.beam_allocation)
|
||||
@@ -212,14 +202,16 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo
|
||||
|
||||
nr_mac_update_timers(module_idP, frame, slot);
|
||||
|
||||
// This schedules MIB
|
||||
schedule_nr_mib(module_idP, frame, slot, &sched_info->DL_req);
|
||||
if (gNB->num_scheduled_prach_rx >= NUM_PRACH_RX_FOR_NOISE_ESTIMATE || get_softmodem_params()->phy_test) {
|
||||
// This schedules MIB
|
||||
schedule_nr_mib(module_idP, frame, slot, &sched_info->DL_req);
|
||||
|
||||
// This schedules SIB1
|
||||
// SIB19 will be scheduled if ntn_Config_r17 is initialized
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||
schedule_nr_other_sib(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||
// This schedules SIB1
|
||||
// SIB19 will be scheduled if ntn_Config_r17 is initialized
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||
schedule_nr_other_sib(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req);
|
||||
}
|
||||
}
|
||||
|
||||
// This schedule PRACH if we are not in phy_test mode
|
||||
|
||||
@@ -430,6 +430,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
|
||||
}
|
||||
}
|
||||
if(td_index == 0) {
|
||||
gNB->num_scheduled_prach_rx++;
|
||||
AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]),
|
||||
"Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus);
|
||||
|
||||
|
||||
@@ -1023,7 +1023,9 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu,
|
||||
pucch_pdu->dmrs_scrambling_id = id0 ? *id0 : *scc->physCellId;
|
||||
pucch_pdu->prb_size = compute_pucch_prb_size(2,
|
||||
pucchres->format.choice.format2->nrofPRBs,
|
||||
O_uci + O_sr,
|
||||
O_csi,
|
||||
O_ack,
|
||||
O_sr,
|
||||
pucch_Config->format2->choice.setup->maxCodeRate,
|
||||
2,
|
||||
pucchres->format.choice.format2->nrofSymbols,
|
||||
@@ -1047,7 +1049,9 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu,
|
||||
int f3_dmrs_symbols = get_f3_dmrs_symbols(pucchres, pucch_Config);
|
||||
pucch_pdu->prb_size = compute_pucch_prb_size(3,
|
||||
pucchres->format.choice.format3->nrofPRBs,
|
||||
O_uci + O_sr,
|
||||
O_csi,
|
||||
O_ack,
|
||||
O_sr,
|
||||
pucch_Config->format3->choice.setup->maxCodeRate,
|
||||
2 - pucch_pdu->pi_2bpsk,
|
||||
pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols,
|
||||
|
||||
@@ -429,6 +429,78 @@ static uint8_t pickandreverse_bits(uint8_t *payload, uint16_t bitlen, uint8_t st
|
||||
return rev_bits;
|
||||
}
|
||||
|
||||
static void evaluate_sinr_report(gNB_MAC_INST *nrmac,
|
||||
NR_UE_info_t *UE,
|
||||
NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
uint8_t csi_report_id,
|
||||
uint8_t *payload,
|
||||
int *cumul_bits,
|
||||
NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16)
|
||||
{
|
||||
/*! As per the spec 38.212 and table: 6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report
|
||||
* the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE
|
||||
* From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set
|
||||
* From spec 38.214 section 5.2.1.2 For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets
|
||||
* configured is limited to S=1
|
||||
*/
|
||||
|
||||
/** from 38.214 sec 5.2.1.4.2
|
||||
- if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'disabled', the UE is
|
||||
not required to update measurements for more than 64 CSI-RS and/or SSB resources, and 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 is not
|
||||
required to update measurements for more than 64 CSI-RS and/or SSB resources, and 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
|
||||
*/
|
||||
|
||||
nr_csi_report_t *csi_report = &UE->csi_report_template[csi_report_id];
|
||||
RSRP_report_t *sinr_report;
|
||||
long **index_list;
|
||||
switch (reportQuantity_type_r16) {
|
||||
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16:
|
||||
sinr_report = &sched_ctrl->CSI_report.ssb_rsrp_report;
|
||||
index_list = csi_report->SSB_Index_list;
|
||||
break;
|
||||
case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16:
|
||||
sinr_report = &sched_ctrl->CSI_report.csirs_rsrp_report;
|
||||
index_list = csi_report->CSI_Index_list;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(false, "Invalid RSRP report type\n");
|
||||
}
|
||||
|
||||
sinr_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri;
|
||||
uint16_t curr_payload;
|
||||
for (int i = 0; i < sinr_report->nr_reports; i++) {
|
||||
int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen;
|
||||
curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits);
|
||||
sinr_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]);
|
||||
LOG_D(MAC, "SSB/CSI-RS index = %d\n", sinr_report->resource_id[i]);
|
||||
*cumul_bits += bitlen;
|
||||
}
|
||||
|
||||
curr_payload = pickandreverse_bits(payload, 7, *cumul_bits);
|
||||
sinr_report->SINR_index[0] = curr_payload & 0x7f;
|
||||
*cumul_bits += 7;
|
||||
|
||||
csi_report->nb_of_csi_ssb_report++;
|
||||
if (sinr_report->SINR_index[0] < 0 || sinr_report->SINR_index[0] > 127) {
|
||||
LOG_E(NR_MAC, "UE %04x: reported SINR index %d invalid\n", UE->rnti, sinr_report->SINR_index[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 1; i < sinr_report->nr_reports; i++) {
|
||||
curr_payload = pickandreverse_bits(payload, 4, *cumul_bits);
|
||||
sinr_report->SINR_index[i] = curr_payload & 0x0f;
|
||||
*cumul_bits += 4;
|
||||
}
|
||||
|
||||
LOG_D(MAC, "Reported SSB-SINR index = %d\n", sinr_report->SINR_index[0]);
|
||||
}
|
||||
|
||||
static void evaluate_rsrp_report(gNB_MAC_INST *nrmac,
|
||||
NR_UE_info_t *UE,
|
||||
NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
@@ -627,6 +699,8 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
uint8_t *payload = uci_pdu->csi_part1.csi_part1_payload;
|
||||
uint16_t bitlen = uci_pdu->csi_part1.csi_part1_bit_len;
|
||||
NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING;
|
||||
NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16 =
|
||||
NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
|
||||
@@ -650,72 +724,78 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
// verify if report with current id has been scheduled for this frame and slot
|
||||
if ((n_slots_frame*frame + slot - offset)%period == 0) {
|
||||
reportQuantity_type = csi_report->reportQuantity_type;
|
||||
// phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP
|
||||
if (get_softmodem_params()->phy_test
|
||||
&& reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
|
||||
&& reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP)
|
||||
continue;
|
||||
LOG_D(MAC,"SFN/SF:%d/%d reportQuantity type = %d\n",frame,slot,reportQuantity_type);
|
||||
switch(reportQuantity_type) {
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
|
||||
evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP:
|
||||
evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type);
|
||||
beam_selection_procedures(nrmac, UE);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
|
||||
if(cri_bitlen)
|
||||
evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if(ri_bitlen)
|
||||
r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl);
|
||||
cumul_bits += ri_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen);
|
||||
evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
|
||||
if(cri_bitlen)
|
||||
evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if(ri_bitlen)
|
||||
r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl);
|
||||
cumul_bits += ri_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen);
|
||||
pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl);
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id;
|
||||
cumul_bits += pmi_bitlen;
|
||||
evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
|
||||
if(cri_bitlen)
|
||||
evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if(ri_bitlen)
|
||||
r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl);
|
||||
cumul_bits += ri_bitlen;
|
||||
li_bitlen = evaluate_li_report(payload,csi_report,cumul_bits,r_index,sched_ctrl);
|
||||
cumul_bits += li_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen);
|
||||
pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl);
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id;
|
||||
cumul_bits += pmi_bitlen;
|
||||
evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0, "Invalid or not supported CSI measurement report\n");
|
||||
reportQuantity_type_r16 = csi_report->reportQuantity_type_r16;
|
||||
LOG_D(MAC, "SFN/SF:%d/%d reportQuantity type = %d, type_r16 = %d\n", frame, slot, reportQuantity_type, reportQuantity_type_r16);
|
||||
if (reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16
|
||||
|| reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16) {
|
||||
evaluate_sinr_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type_r16);
|
||||
} else {
|
||||
// phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP
|
||||
if (get_softmodem_params()->phy_test
|
||||
&& reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
|
||||
&& reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP)
|
||||
continue;
|
||||
switch (reportQuantity_type) {
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
|
||||
evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP:
|
||||
evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type);
|
||||
beam_selection_procedures(nrmac, UE);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
|
||||
if (cri_bitlen)
|
||||
evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if (ri_bitlen)
|
||||
r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl);
|
||||
cumul_bits += ri_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen);
|
||||
evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
|
||||
if (cri_bitlen)
|
||||
evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if (ri_bitlen)
|
||||
r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl);
|
||||
cumul_bits += ri_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen);
|
||||
pmi_bitlen = evaluate_pmi_report(payload, csi_report, cumul_bits, r_index, sched_ctrl);
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id;
|
||||
cumul_bits += pmi_bitlen;
|
||||
evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table);
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
|
||||
if (cri_bitlen)
|
||||
evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if (ri_bitlen)
|
||||
r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl);
|
||||
cumul_bits += ri_bitlen;
|
||||
li_bitlen = evaluate_li_report(payload, csi_report, cumul_bits, r_index, sched_ctrl);
|
||||
cumul_bits += li_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen);
|
||||
pmi_bitlen = evaluate_pmi_report(payload, csi_report, cumul_bits, r_index, sched_ctrl);
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id;
|
||||
cumul_bits += pmi_bitlen;
|
||||
evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table);
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Invalid or not supported CSI measurement report\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ void mac_top_init_gNB(ngran_node_t node_type,
|
||||
void nr_mac_send_f1_setup_req(void);
|
||||
|
||||
void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *mac_config);
|
||||
void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const f1ap_plmn_t *plmn, uint64_t cellID, int tac);
|
||||
void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac);
|
||||
bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_sib_msg_t cu_sib[num_cu_sib]);
|
||||
bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup);
|
||||
bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup);
|
||||
|
||||
@@ -94,7 +94,7 @@ bool DURecvCb(protocol_ctxt_t *ctxt_pP,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn)
|
||||
static bool check_plmn_identity(const plmn_id_t *check_plmn, const plmn_id_t *plmn)
|
||||
{
|
||||
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
|
||||
}
|
||||
|
||||
@@ -275,6 +275,7 @@ void mac_top_init_gNB(ngran_node_t node_type,
|
||||
RC.nrmac[i]->common_channels[0].pre_ServingCellConfig = scd;
|
||||
|
||||
RC.nrmac[i]->first_MIB = true;
|
||||
RC.nrmac[i]->num_scheduled_prach_rx = 0;
|
||||
RC.nrmac[i]->common_channels[0].mib = get_new_MIB_NR(scc);
|
||||
|
||||
RC.nrmac[i]->cset0_bwp_start = 0;
|
||||
|
||||
@@ -179,6 +179,7 @@ typedef struct nr_mac_config_t {
|
||||
int32_t *bw_list;
|
||||
int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
|
||||
nr_redcap_config_t *redcap;
|
||||
bool do_SINR;
|
||||
} nr_mac_config_t;
|
||||
|
||||
typedef struct NR_preamble_ue {
|
||||
@@ -537,6 +538,8 @@ typedef struct RSRP_report {
|
||||
uint8_t nr_reports;
|
||||
uint8_t resource_id[MAX_NR_OF_REPORTED_RS];
|
||||
int RSRP[MAX_NR_OF_REPORTED_RS];
|
||||
// SINR index according to tables 10.1.16.1-1, 10.1.16.1-2
|
||||
int SINR_index[MAX_NR_OF_REPORTED_RS];
|
||||
} RSRP_report_t;
|
||||
|
||||
struct CSI_Report {
|
||||
@@ -936,7 +939,7 @@ typedef struct gNB_MAC_INST_s {
|
||||
pthread_mutex_t sched_lock;
|
||||
|
||||
mac_stats_t mac_stats;
|
||||
|
||||
uint64_t num_scheduled_prach_rx;
|
||||
} gNB_MAC_INST;
|
||||
|
||||
#endif /*__LAYER2_NR_MAC_GNB_H__ */
|
||||
|
||||
@@ -74,11 +74,6 @@
|
||||
|
||||
static nr_pdcp_ue_manager_t *nr_pdcp_ue_manager;
|
||||
|
||||
/* TODO: handle time a bit more properly */
|
||||
static uint64_t nr_pdcp_current_time;
|
||||
static int nr_pdcp_current_time_last_frame;
|
||||
static int nr_pdcp_current_time_last_subframe;
|
||||
|
||||
/* necessary globals for OAI, not used internally */
|
||||
hash_table_t *pdcp_coll_p;
|
||||
static uint64_t pdcp_optmask;
|
||||
@@ -390,168 +385,6 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
|
||||
/* pdcp_data_ind thread - end */
|
||||
/****************************************************************************/
|
||||
|
||||
/****************************************************************************/
|
||||
/* hacks to be cleaned up at some point - begin */
|
||||
/****************************************************************************/
|
||||
|
||||
#include "LAYER2/MAC/mac_extern.h"
|
||||
|
||||
static void reblock_tun_socket(void)
|
||||
{
|
||||
extern int nas_sock_fd[];
|
||||
int f;
|
||||
|
||||
f = fcntl(nas_sock_fd[0], F_GETFL, 0);
|
||||
f &= ~(O_NONBLOCK);
|
||||
if (fcntl(nas_sock_fd[0], F_SETFL, f) == -1) {
|
||||
LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void *enb_tun_read_thread(void *_)
|
||||
{
|
||||
extern int nas_sock_fd[];
|
||||
char rx_buf[NL_MAX_PAYLOAD];
|
||||
int len;
|
||||
protocol_ctxt_t ctxt;
|
||||
ue_id_t UEid;
|
||||
|
||||
int rb_id = 1;
|
||||
pthread_setname_np( pthread_self(),"enb_tun_read");
|
||||
|
||||
while (1) {
|
||||
len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD);
|
||||
if (len == -1) {
|
||||
LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len);
|
||||
|
||||
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
|
||||
const bool has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid);
|
||||
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
|
||||
|
||||
if (!has_ue) continue;
|
||||
|
||||
ctxt.module_id = 0;
|
||||
ctxt.enb_flag = 1;
|
||||
ctxt.instance = 0;
|
||||
ctxt.frame = 0;
|
||||
ctxt.subframe = 0;
|
||||
ctxt.eNB_index = 0;
|
||||
ctxt.brOption = 0;
|
||||
ctxt.rntiMaybeUEid = UEid;
|
||||
|
||||
uint8_t qfi = 7;
|
||||
bool rqi = 0;
|
||||
int pdusession_id = 10;
|
||||
|
||||
sdap_data_req(&ctxt,
|
||||
UEid,
|
||||
SRB_FLAG_NO,
|
||||
rb_id,
|
||||
RLC_MUI_UNDEFINED,
|
||||
RLC_SDU_CONFIRM_NO,
|
||||
len,
|
||||
(unsigned char *)rx_buf,
|
||||
PDCP_TRANSMISSION_MODE_DATA,
|
||||
NULL,
|
||||
NULL,
|
||||
qfi,
|
||||
rqi,
|
||||
pdusession_id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *ue_tun_read_thread(void *_)
|
||||
{
|
||||
extern int nas_sock_fd[];
|
||||
char rx_buf[NL_MAX_PAYLOAD];
|
||||
int len;
|
||||
protocol_ctxt_t ctxt;
|
||||
ue_id_t UEid;
|
||||
int has_ue;
|
||||
|
||||
int rb_id = 1;
|
||||
pthread_setname_np( pthread_self(),"ue_tun_read");
|
||||
while (1) {
|
||||
len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD);
|
||||
if (len == -1) {
|
||||
LOG_E(PDCP, "error: cannot read() from fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno));
|
||||
return NULL; /* exit thread */
|
||||
}
|
||||
|
||||
LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len);
|
||||
|
||||
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
|
||||
has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid);
|
||||
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
|
||||
|
||||
if (!has_ue) continue;
|
||||
|
||||
ctxt.module_id = 0;
|
||||
ctxt.enb_flag = 0;
|
||||
ctxt.instance = 0;
|
||||
ctxt.frame = 0;
|
||||
ctxt.subframe = 0;
|
||||
ctxt.eNB_index = 0;
|
||||
ctxt.brOption = 0;
|
||||
ctxt.rntiMaybeUEid = UEid;
|
||||
|
||||
bool dc = SDAP_HDR_UL_DATA_PDU;
|
||||
extern uint8_t nas_qfi;
|
||||
extern uint8_t nas_pduid;
|
||||
|
||||
sdap_data_req(&ctxt,
|
||||
UEid,
|
||||
SRB_FLAG_NO,
|
||||
rb_id,
|
||||
RLC_MUI_UNDEFINED,
|
||||
RLC_SDU_CONFIRM_NO,
|
||||
len,
|
||||
(unsigned char *)rx_buf,
|
||||
PDCP_TRANSMISSION_MODE_DATA,
|
||||
NULL,
|
||||
NULL,
|
||||
nas_qfi,
|
||||
dc,
|
||||
nas_pduid);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void start_pdcp_tun_enb(void)
|
||||
{
|
||||
pthread_t t;
|
||||
|
||||
reblock_tun_socket();
|
||||
|
||||
if (pthread_create(&t, NULL, enb_tun_read_thread, NULL) != 0) {
|
||||
LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_pdcp_tun_ue(void)
|
||||
{
|
||||
pthread_t t;
|
||||
|
||||
reblock_tun_socket();
|
||||
|
||||
if (pthread_create(&t, NULL, ue_tun_read_thread, NULL) != 0) {
|
||||
LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* hacks to be cleaned up at some point - end */
|
||||
/****************************************************************************/
|
||||
|
||||
int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP)
|
||||
{
|
||||
return 0;
|
||||
@@ -584,62 +417,12 @@ void nr_pdcp_layer_init(void)
|
||||
nr_pdcp_e1_if_init(node_type == ngran_gNB_CUUP || node_type == ngran_gNB_CUCP);
|
||||
init_nr_pdcp_data_ind_queue();
|
||||
nr_pdcp_init_timer_thread(nr_pdcp_ue_manager);
|
||||
if (NODE_IS_CU(node_type)) {
|
||||
nr_pdcp_init_tick_thread();
|
||||
}
|
||||
}
|
||||
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "executables/lte-softmodem.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
|
||||
uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id)
|
||||
{
|
||||
/* hack: be sure to initialize only once */
|
||||
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int initialized = 0;
|
||||
if (pthread_mutex_lock(&m) != 0) abort();
|
||||
if (initialized) {
|
||||
abort();
|
||||
}
|
||||
initialized = 1;
|
||||
if (pthread_mutex_unlock(&m) != 0) abort();
|
||||
|
||||
pdcp_optmask = pdcp_optmask | _pdcp_optmask ;
|
||||
|
||||
if (UE_NAS_USE_TUN) {
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_nrue" : "oaitun_ue";
|
||||
int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF)
|
||||
? MAX_MOBILES_PER_ENB
|
||||
: 1;
|
||||
int begx = (id == 0) ? 0 : id - 1;
|
||||
int endx = (id == 0) ? num_if : id;
|
||||
for (int i = begx; i < endx; i++) {
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, i);
|
||||
tun_init(ifname, i);
|
||||
}
|
||||
if (IS_SOFTMODEM_NOS1) {
|
||||
const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3";
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, id);
|
||||
tun_config(ifname, ip, NULL);
|
||||
set_qfi_pduid(7, 10);
|
||||
}
|
||||
LOG_I(PDCP, "UE pdcp will use tun interface\n");
|
||||
start_pdcp_tun_ue();
|
||||
} else if (ENB_NAS_USE_TUN) {
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, id);
|
||||
tun_init(ifname, id);
|
||||
tun_config(ifname, "10.0.1.1", NULL);
|
||||
LOG_I(PDCP, "ENB pdcp will use tun interface\n");
|
||||
start_pdcp_tun_enb();
|
||||
}
|
||||
|
||||
return pdcp_optmask ;
|
||||
}
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
|
||||
static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
|
||||
char *buf, int size,
|
||||
@@ -817,9 +600,15 @@ void add_drb(int is_gnb,
|
||||
nr_pdcp_ue_t *ue;
|
||||
|
||||
int drb_id = s->drb_Identity;
|
||||
int sn_size_ul = decode_sn_size_ul(*s->pdcp_Config->drb->pdcp_SN_SizeUL);
|
||||
int sn_size_dl = decode_sn_size_dl(*s->pdcp_Config->drb->pdcp_SN_SizeDL);
|
||||
int discard_timer = decode_discard_timer(*s->pdcp_Config->drb->discardTimer);
|
||||
if (!s->pdcp_Config || !s->pdcp_Config->drb) {
|
||||
LOG_E(PDCP, "DRB field mandatory present at setup. DRB %d not configured.\n", drb_id);
|
||||
return;
|
||||
}
|
||||
|
||||
struct NR_PDCP_Config__drb *drb = s->pdcp_Config->drb;
|
||||
int sn_size_ul = decode_sn_size_ul(*drb->pdcp_SN_SizeUL);
|
||||
int sn_size_dl = decode_sn_size_dl(*drb->pdcp_SN_SizeDL);
|
||||
int discard_timer = decode_discard_timer(*drb->discardTimer);
|
||||
|
||||
int has_integrity;
|
||||
int has_ciphering;
|
||||
@@ -830,20 +619,18 @@ void add_drb(int is_gnb,
|
||||
t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering);
|
||||
}
|
||||
|
||||
if (s->pdcp_Config->drb != NULL
|
||||
&& s->pdcp_Config->drb->integrityProtection != NULL)
|
||||
if (drb->integrityProtection != NULL)
|
||||
has_integrity = 1;
|
||||
else
|
||||
has_integrity = 0;
|
||||
|
||||
if (s->pdcp_Config->ext1 != NULL
|
||||
&& s->pdcp_Config->ext1->cipheringDisabled != NULL)
|
||||
if (s->pdcp_Config->ext1 != NULL && s->pdcp_Config->ext1->cipheringDisabled != NULL)
|
||||
has_ciphering = 0;
|
||||
else
|
||||
has_ciphering = 1;
|
||||
|
||||
if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) {
|
||||
LOG_E(PDCP,"%s:%d:%s: fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
LOG_E(PDCP, "fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@@ -857,7 +644,7 @@ void add_drb(int is_gnb,
|
||||
pdusession_id = s->cnAssociation->choice.eps_BearerIdentity;
|
||||
else {
|
||||
if (!s->cnAssociation->choice.sdap_Config) {
|
||||
LOG_E(PDCP,"%s:%d:%s: fatal, sdap_Config is null",__FILE__,__LINE__,__FUNCTION__);
|
||||
LOG_E(PDCP,"fatal, sdap_Config is null");
|
||||
exit(-1);
|
||||
}
|
||||
pdusession_id = s->cnAssociation->choice.sdap_Config->pdu_Session;
|
||||
@@ -870,8 +657,7 @@ void add_drb(int is_gnb,
|
||||
}
|
||||
/* TODO(?): accept different UL and DL SN sizes? */
|
||||
if (sn_size_ul != sn_size_dl) {
|
||||
LOG_E(PDCP, "%s:%d:%s: fatal, bad SN sizes, must be same. ul=%d, dl=%d\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, sn_size_ul, sn_size_dl);
|
||||
LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -1261,17 +1047,6 @@ bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nr_pdcp_tick(int frame, int subframe)
|
||||
{
|
||||
if (frame != nr_pdcp_current_time_last_frame ||
|
||||
subframe != nr_pdcp_current_time_last_subframe) {
|
||||
nr_pdcp_current_time_last_frame = frame;
|
||||
nr_pdcp_current_time_last_subframe = subframe;
|
||||
nr_pdcp_current_time++;
|
||||
nr_pdcp_wakeup_timer_thread(nr_pdcp_current_time);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For the SDAP API
|
||||
*/
|
||||
|
||||
@@ -35,7 +35,6 @@ struct NR_DRB_ToAddMod;
|
||||
struct NR_SRB_ToAddMod;
|
||||
|
||||
void nr_pdcp_layer_init(void);
|
||||
uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id);
|
||||
|
||||
void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP,
|
||||
const srb_flag_t srb_flagP,
|
||||
@@ -128,8 +127,6 @@ bool nr_pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP,
|
||||
const uint32_t *const sourceL2Id,
|
||||
const uint32_t *const destinationL2Id);
|
||||
|
||||
void nr_pdcp_tick(int frame, int subframe);
|
||||
|
||||
nr_pdcp_ue_manager_t *nr_pdcp_sdap_get_ue_manager();
|
||||
|
||||
int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len);
|
||||
|
||||
@@ -70,26 +70,6 @@ static void *nr_pdcp_timer_thread(void *_nr_pdcp_ue_manager)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *nr_pdcp_tick_thread() {
|
||||
pthread_setname_np(pthread_self(),"nr_pdcp_tick_thread");
|
||||
uint64_t curr_time = 0;
|
||||
while (1) {
|
||||
usleep(1000);
|
||||
curr_time++;
|
||||
nr_pdcp_wakeup_timer_thread(curr_time);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nr_pdcp_init_tick_thread()
|
||||
{
|
||||
pthread_t t;
|
||||
if (pthread_create(&t, NULL, nr_pdcp_tick_thread, NULL) != 0) {
|
||||
LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager)
|
||||
{
|
||||
pthread_t t;
|
||||
@@ -100,10 +80,10 @@ void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager)
|
||||
}
|
||||
}
|
||||
|
||||
void nr_pdcp_wakeup_timer_thread(uint64_t time)
|
||||
void nr_pdcp_ms_tick(void)
|
||||
{
|
||||
if (pthread_mutex_lock(&timer_thread_mutex)) abort();
|
||||
timer_thread_curtime = time;
|
||||
timer_thread_curtime++;
|
||||
if (pthread_cond_broadcast(&timer_thread_cond)) abort();
|
||||
if (pthread_mutex_unlock(&timer_thread_mutex)) abort();
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void nr_pdcp_init_tick_thread();
|
||||
void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager);
|
||||
void nr_pdcp_wakeup_timer_thread(uint64_t time);
|
||||
void nr_pdcp_ms_tick(void);
|
||||
|
||||
#endif /* _NR_PDCP_TIMER_THREAD_H_ */
|
||||
|
||||
@@ -50,8 +50,6 @@ static nr_rlc_ue_manager_t *nr_rlc_ue_manager;
|
||||
/* TODO: handle time a bit more properly */
|
||||
static pthread_mutex_t nr_rlc_current_time_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static uint64_t nr_rlc_current_time;
|
||||
static int nr_rlc_current_time_last_frame;
|
||||
static int nr_rlc_current_time_last_subframe;
|
||||
|
||||
void lock_nr_rlc_current_time(void)
|
||||
{
|
||||
@@ -956,15 +954,10 @@ void nr_rlc_test_trigger_reestablishment(int ue_id)
|
||||
nr_rlc_manager_unlock(nr_rlc_ue_manager);
|
||||
}
|
||||
|
||||
void nr_rlc_tick(int frame, int subframe)
|
||||
void nr_rlc_ms_tick(void)
|
||||
{
|
||||
lock_nr_rlc_current_time();
|
||||
if (frame != nr_rlc_current_time_last_frame ||
|
||||
subframe != nr_rlc_current_time_last_subframe) {
|
||||
nr_rlc_current_time_last_frame = frame;
|
||||
nr_rlc_current_time_last_subframe = subframe;
|
||||
nr_rlc_current_time++;
|
||||
}
|
||||
nr_rlc_current_time++;
|
||||
unlock_nr_rlc_current_time();
|
||||
}
|
||||
|
||||
|
||||
@@ -1133,10 +1133,11 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac,
|
||||
return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci);
|
||||
}
|
||||
|
||||
static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm)
|
||||
static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm, float_t sinr_dB)
|
||||
{
|
||||
mac->ssb_measurements.ssb_index = ssb_index;
|
||||
mac->ssb_measurements.ssb_rsrp_dBm = rsrp_dbm;
|
||||
mac->ssb_measurements.ssb_sinr_dB = sinr_dB;
|
||||
}
|
||||
|
||||
// L2 Abstraction Layer
|
||||
@@ -1272,7 +1273,8 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio
|
||||
if(rx_indication_body.ssb_pdu.decoded_pdu) {
|
||||
handle_ssb_meas(mac,
|
||||
rx_indication_body.ssb_pdu.ssb_index,
|
||||
rx_indication_body.ssb_pdu.rsrp_dBm);
|
||||
rx_indication_body.ssb_pdu.rsrp_dBm,
|
||||
rx_indication_body.ssb_pdu.sinr_dB);
|
||||
ret_mask |= (handle_bcch_bch(mac,
|
||||
dl_info->cc_id,
|
||||
dl_info->gNB_index,
|
||||
|
||||
@@ -1934,7 +1934,8 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
int rep_id,
|
||||
int uid,
|
||||
int curr_bwp,
|
||||
int num_antenna_ports)
|
||||
int num_antenna_ports,
|
||||
bool do_sinr)
|
||||
{
|
||||
int resource_id = -1;
|
||||
for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) {
|
||||
@@ -1968,6 +1969,14 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
} else {
|
||||
csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP;
|
||||
csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0;
|
||||
if (do_sinr) {
|
||||
csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none;
|
||||
csirep->reportQuantity.choice.none = (NULL_t)0;
|
||||
csirep->ext2 = calloc(1, sizeof(*csirep->ext2));
|
||||
csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16));
|
||||
csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16;
|
||||
csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0;
|
||||
}
|
||||
}
|
||||
csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled;
|
||||
csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled));
|
||||
@@ -2463,7 +2472,7 @@ static bool is_ntn_band(int band)
|
||||
}
|
||||
|
||||
NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc,
|
||||
const f1ap_plmn_t *plmn,
|
||||
const plmn_id_t *plmn,
|
||||
uint64_t cellID,
|
||||
int tac,
|
||||
const nr_mac_config_t *mac_config)
|
||||
@@ -3298,7 +3307,15 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
|
||||
NR_PUCCH_CSI_Resource_t *pucchrsrp = calloc(1, sizeof(*pucchrsrp));
|
||||
pucchrsrp->uplinkBandwidthPartId = bwp_id;
|
||||
pucchrsrp->pucch_Resource = pucch_Resource;
|
||||
config_rsrp_meas_report(csi_MeasConfig, scc, pucchrsrp, configuration->do_CSIRS, bwp_id + 10, uid, curr_bwp, pdsch_AntennaPorts);
|
||||
config_rsrp_meas_report(csi_MeasConfig,
|
||||
scc,
|
||||
pucchrsrp,
|
||||
configuration->do_CSIRS,
|
||||
bwp_id + 10,
|
||||
uid,
|
||||
curr_bwp,
|
||||
pdsch_AntennaPorts,
|
||||
configuration->do_SINR);
|
||||
}
|
||||
|
||||
fill_harq_IEs(SpCellConfig->spCellConfigDedicated, configuration->num_dlharq, configuration->num_ulharq);
|
||||
@@ -3811,7 +3828,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
|
||||
bwp->bwp_Id + 10,
|
||||
uid,
|
||||
curr_bwp,
|
||||
dl_antenna_ports);
|
||||
dl_antenna_ports,
|
||||
configuration->do_SINR);
|
||||
}
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->sCellDeactivationTimer = NULL;
|
||||
secondaryCellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig = NULL;
|
||||
|
||||
@@ -79,7 +79,7 @@ void free_MeasurementTimingConfiguration(struct NR_MeasurementTimingConfiguratio
|
||||
|
||||
#define NR_MAX_SIB_LENGTH 2976 // 3GPP TS 38.331 section 5.2.1
|
||||
NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc,
|
||||
const f1ap_plmn_t *plmn,
|
||||
const plmn_id_t *plmn,
|
||||
uint64_t cellID,
|
||||
int tac,
|
||||
const nr_mac_config_t *mac_config);
|
||||
|
||||
@@ -2894,9 +2894,9 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc,
|
||||
f1ap_ue_context_setup_t ue_context_setup_req = {
|
||||
.gNB_CU_ue_id = ue_p->rrc_ue_id,
|
||||
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||
.plmn.mcc = rrc->configuration.mcc[0],
|
||||
.plmn.mnc = rrc->configuration.mnc[0],
|
||||
.plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0],
|
||||
.plmn.mcc = rrc->configuration.plmn[0].mcc,
|
||||
.plmn.mnc = rrc->configuration.plmn[0].mnc,
|
||||
.plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length,
|
||||
.nr_cellid = rrc->nr_cellid,
|
||||
.servCellId = 0, /* TODO: correct value? */
|
||||
.srbs_to_be_setup_length = nb_srb,
|
||||
@@ -2938,9 +2938,9 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc,
|
||||
f1ap_ue_context_modif_req_t ue_context_modif_req = {
|
||||
.gNB_CU_ue_id = ue_p->rrc_ue_id,
|
||||
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||
.plmn.mcc = rrc->configuration.mcc[0],
|
||||
.plmn.mnc = rrc->configuration.mnc[0],
|
||||
.plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0],
|
||||
.plmn.mcc = rrc->configuration.plmn[0].mcc,
|
||||
.plmn.mnc = rrc->configuration.plmn[0].mnc,
|
||||
.plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length,
|
||||
.nr_cellid = rrc->nr_cellid,
|
||||
.servCellId = 0, /* TODO: correct value? */
|
||||
.drbs_to_be_setup_length = n_drbs,
|
||||
|
||||
@@ -1454,18 +1454,18 @@ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance)
|
||||
for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) {
|
||||
LOG_I(NR_RRC,"[gNB %ld] In NGAP_PAGING_IND: MCC %d, MNC %d, TAC %d\n", instance, NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc,
|
||||
NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc, NGAP_PAGING_IND(msg_p).tac[tai_size]);
|
||||
|
||||
for (uint8_t j = 0; j < RC.nrrrc[instance]->configuration.num_plmn; j++) {
|
||||
if (RC.nrrrc[instance]->configuration.mcc[j] == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc
|
||||
&& RC.nrrrc[instance]->configuration.mnc[j] == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc
|
||||
&& RC.nrrrc[instance]->configuration.tac == NGAP_PAGING_IND(msg_p).tac[tai_size]) {
|
||||
gNB_RrcConfigurationReq *req = &RC.nrrrc[instance]->configuration;
|
||||
for (uint8_t j = 0; j < req->num_plmn; j++) {
|
||||
plmn_id_t *plmn = &req->plmn[j];
|
||||
if (plmn->mcc == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc
|
||||
&& plmn->mnc == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc && req->tac == NGAP_PAGING_IND(msg_p).tac[tai_size]) {
|
||||
for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
AssertFatal(false, "to be implemented properly\n");
|
||||
if (NODE_IS_CU(RC.nrrrc[instance]->node_type)) {
|
||||
MessageDef *m = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_PAGING_IND);
|
||||
F1AP_PAGING_IND(m).plmn.mcc = RC.nrrrc[j]->configuration.mcc[0];
|
||||
F1AP_PAGING_IND(m).plmn.mnc = RC.nrrrc[j]->configuration.mnc[0];
|
||||
F1AP_PAGING_IND(m).plmn.mnc_digit_length = RC.nrrrc[j]->configuration.mnc_digit_length[0];
|
||||
F1AP_PAGING_IND(m).plmn.mcc = RC.nrrrc[j]->configuration.plmn[0].mcc;
|
||||
F1AP_PAGING_IND(m).plmn.mnc = RC.nrrrc[j]->configuration.plmn[0].mnc;
|
||||
F1AP_PAGING_IND(m).plmn.mnc_digit_length = RC.nrrrc[j]->configuration.plmn[0].mnc_digit_length;
|
||||
F1AP_PAGING_IND (m).nr_cellid = RC.nrrrc[j]->nr_cellid;
|
||||
F1AP_PAGING_IND (m).ueidentityindexvalue = (uint16_t)(NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi%1024);
|
||||
F1AP_PAGING_IND (m).fiveg_s_tmsi = NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi;
|
||||
|
||||
@@ -263,13 +263,13 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t *
|
||||
|
||||
for (int i = 0; i < req->supported_plmns; i++) {
|
||||
const PLMN_ID_t *id = &req->plmn[i].id;
|
||||
if (rrc->configuration.mcc[i] != id->mcc || rrc->configuration.mnc[i] != id->mnc) {
|
||||
if (rrc->configuration.plmn[i].mcc != id->mcc || rrc->configuration.plmn[i].mnc != id->mnc) {
|
||||
LOG_E(NR_RRC,
|
||||
"PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n",
|
||||
id->mcc,
|
||||
id->mnc,
|
||||
rrc->configuration.mcc[i],
|
||||
rrc->configuration.mnc[i]);
|
||||
rrc->configuration.plmn[i].mcc,
|
||||
rrc->configuration.plmn[i].mnc);
|
||||
e1ap_cause_t cause = { .type = E1AP_CAUSE_RADIO_NETWORK, .value = E1AP_RADIO_CAUSE_OTHER};
|
||||
e1ap_setup_failure(assoc_id, req->transac_id, cause);
|
||||
return -1;
|
||||
|
||||
@@ -99,8 +99,7 @@ static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell
|
||||
{
|
||||
const gNB_RrcConfigurationReq *conf = &rrc->configuration;
|
||||
return conf->num_plmn == 1 // F1 supports only one
|
||||
&& conf->mcc[0] == info->plmn.mcc
|
||||
&& conf->mnc[0] == info->plmn.mnc;
|
||||
&& conf->plmn[0].mcc == info->plmn.mcc && conf->plmn[0].mnc == info->plmn.mnc;
|
||||
}
|
||||
|
||||
static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t **mib, NR_SIB1_t **sib1)
|
||||
@@ -309,9 +308,9 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
if (!rrc_gNB_plmn_matches(rrc, cell_info)) {
|
||||
LOG_E(NR_RRC,
|
||||
"PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n",
|
||||
rrc->configuration.mcc[0],
|
||||
rrc->configuration.mnc_digit_length[0],
|
||||
rrc->configuration.mnc[0],
|
||||
rrc->configuration.plmn[0].mcc,
|
||||
rrc->configuration.plmn[0].mnc_digit_length,
|
||||
rrc->configuration.plmn[0].mnc,
|
||||
cell_info->plmn.mcc,
|
||||
cell_info->plmn.mnc_digit_length,
|
||||
cell_info->plmn.mnc);
|
||||
|
||||
@@ -227,9 +227,7 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_
|
||||
f1ap_ue_context_modif_req_t ue_context_modif_req = {
|
||||
.gNB_CU_ue_id = ue->rrc_ue_id,
|
||||
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||
.plmn.mcc = rrc->configuration.mcc[0],
|
||||
.plmn.mnc = rrc->configuration.mnc[0],
|
||||
.plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0],
|
||||
.plmn = rrc->configuration.plmn[0],
|
||||
.nr_cellid = rrc->nr_cellid, // TODO target cell ID
|
||||
.servCellId = 0, // TODO: correct value?
|
||||
.ReconfigComplOutcome = RRCreconf_success,
|
||||
|
||||
@@ -62,6 +62,8 @@ void init_nsa_message(NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfig
|
||||
msg_len = fread(buffer, 1, 1024, fd);
|
||||
fclose(fd);
|
||||
process_nsa_message(rrc, nr_RadioBearerConfigX_r15, buffer,msg_len);
|
||||
MessageDef* ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_INIT_NOS1_IF);
|
||||
itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg);
|
||||
}
|
||||
else
|
||||
LOG_D(NR_RRC, "In NSA mode \n");
|
||||
|
||||
@@ -20,13 +20,29 @@
|
||||
*/
|
||||
|
||||
#include "nr_sdap.h"
|
||||
#include "assertions.h"
|
||||
#include "utils.h"
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include "nr_sdap_entity.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "errno.h"
|
||||
#include "rlc.h"
|
||||
#include "tun_if.h"
|
||||
#include "system.h"
|
||||
|
||||
static void reblock_tun_socket(int fd)
|
||||
{
|
||||
int f;
|
||||
|
||||
f = fcntl(fd, F_GETFL, 0);
|
||||
f &= ~(O_NONBLOCK);
|
||||
if (fcntl(fd, F_SETFL, f) == -1) {
|
||||
LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", fd, errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t nas_qfi;
|
||||
uint8_t nas_pduid;
|
||||
|
||||
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
|
||||
const ue_id_t ue_id,
|
||||
@@ -91,8 +107,110 @@ void sdap_data_ind(rb_id_t pdcp_entity,
|
||||
size);
|
||||
}
|
||||
|
||||
void set_qfi_pduid(uint8_t qfi, uint8_t pduid){
|
||||
nas_qfi = qfi;
|
||||
nas_pduid = pduid;
|
||||
return;
|
||||
struct thread_args {
|
||||
nr_sdap_entity_t *entity;
|
||||
bool is_gnb;
|
||||
};
|
||||
static void *sdap_tun_read_thread(void *arg)
|
||||
{
|
||||
DevAssert(arg != NULL);
|
||||
struct thread_args *ta = arg;
|
||||
nr_sdap_entity_t *entity = ta->entity;
|
||||
bool is_gnb = ta->is_gnb;
|
||||
free(ta);
|
||||
|
||||
char rx_buf[NL_MAX_PAYLOAD];
|
||||
int len;
|
||||
reblock_tun_socket(entity->pdusession_sock);
|
||||
|
||||
int rb_id = 1;
|
||||
|
||||
while (!entity->stop_thread) {
|
||||
len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD);
|
||||
if (len == -1) {
|
||||
LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D(SDAP, "read data of size %d\n", len);
|
||||
|
||||
protocol_ctxt_t ctxt = {.enb_flag = is_gnb, .rntiMaybeUEid = entity->ue_id};
|
||||
|
||||
bool dc = is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
|
||||
|
||||
DevAssert(entity != NULL);
|
||||
entity->tx_entity(entity,
|
||||
&ctxt,
|
||||
SRB_FLAG_NO,
|
||||
rb_id,
|
||||
RLC_MUI_UNDEFINED,
|
||||
RLC_SDU_CONFIRM_NO,
|
||||
len,
|
||||
(unsigned char *)rx_buf,
|
||||
PDCP_TRANSMISSION_MODE_DATA,
|
||||
NULL,
|
||||
NULL,
|
||||
entity->qfi,
|
||||
dc);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, ue_id - 1);
|
||||
entity->pdusession_sock = tun_alloc(ifname);
|
||||
tun_config(ifname, "10.0.1.1", NULL);
|
||||
struct thread_args *ta = calloc_or_fail(1, sizeof(*ta));
|
||||
ta->entity = entity;
|
||||
ta->is_gnb = true;
|
||||
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
entity->pdusession_sock = sock;
|
||||
entity->stop_thread = false;
|
||||
char thread_name[64];
|
||||
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id);
|
||||
struct thread_args *ta = calloc_or_fail(1, sizeof(*ta));
|
||||
ta->entity = entity;
|
||||
ta->is_gnb = false;
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, thread_name, -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id)
|
||||
{
|
||||
int default_pdu = get_softmodem_params()->default_pdu_session_id;
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ue_ifname(ifname, ue_id, pdu_session_id != default_pdu ? pdu_session_id : -1);
|
||||
const int sock = tun_alloc(ifname);
|
||||
tun_config(ifname, ipv4, ipv6);
|
||||
if (ipv4) {
|
||||
setup_ue_ipv4_route(ifname, ue_id, ipv4);
|
||||
}
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1
|
||||
}
|
||||
|
||||
void remove_ue_ip_if(nr_sdap_entity_t *entity)
|
||||
{
|
||||
DevAssert(entity != NULL);
|
||||
// Stop the read thread
|
||||
entity->stop_thread = true;
|
||||
int ret = pthread_join(entity->pdusession_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno));
|
||||
// Bring down the IP interface
|
||||
int default_pdu = get_softmodem_params()->default_pdu_session_id;
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1);
|
||||
tun_destroy(ifname, entity->pdusession_sock);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ void sdap_data_ind(rb_id_t pdcp_entity,
|
||||
char *buf,
|
||||
int size);
|
||||
|
||||
void set_qfi_pduid(uint8_t qfi, uint8_t pduid);
|
||||
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock);
|
||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id);
|
||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user