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:
Robert Schmidt
2025-04-22 16:16:33 +00:00
115 changed files with 3438 additions and 1425 deletions
+3
View File
@@ -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:
+6
View File
@@ -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;
+16
View File
@@ -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(), &param_list, param_def, sizeofArray(param_def), prefix);
#endif /* INCLUDE_CONFIG_PARAMDESC_H */
+3
View File
@@ -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__ */
+1
View File
@@ -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})
+13
View File
@@ -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;
}
+16
View File
@@ -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))
+14
View File
@@ -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)
+297
View File
@@ -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;
}
+232
View File
@@ -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);
}
+36
View File
@@ -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 */
+205
View File
@@ -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;
}
@@ -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 */
+249
View File
@@ -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);
}
+40
View File
@@ -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 */
+263
View File
@@ -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);
}
@@ -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
View File
@@ -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);
}
+15
View File
@@ -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_*/
+14
View File
@@ -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`
+1
View File
@@ -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
View File
@@ -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
+286
View File
@@ -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)
```
+13
View File
@@ -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
View File
@@ -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);
+5
View File
@@ -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);
+42 -8
View File
@@ -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
View File
@@ -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;
+23 -23
View File
@@ -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;
}
+4
View File
@@ -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){
+3 -1
View File
@@ -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;
+8 -26
View File
@@ -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));
+4 -1
View File
@@ -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]);
+2 -1
View File
@@ -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);
}
+6 -4
View File
@@ -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");
+1
View File
@@ -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];
-6
View File
@@ -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
}
+5 -3
View File
@@ -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
+4 -2
View File
@@ -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
+5 -3
View File
@@ -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);
}
+4
View File
@@ -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;
+11 -16
View File
@@ -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;
+2 -4
View File
@@ -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;
+1
View File
@@ -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)
+1 -3
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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 = {
+21 -21
View File
@@ -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
-44
View File
@@ -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
View File
@@ -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;
-36
View File
@@ -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);
+5
View File
@@ -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 } }, \
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
+5 -2
View File
@@ -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;
+78 -38
View File
@@ -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,
+1
View File
@@ -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 {
+144 -22
View File
@@ -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;
}
+1 -1
View File
@@ -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");
+9 -17
View File
@@ -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,
+146 -66
View File
@@ -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");
}
}
}
}
+1 -1
View File
@@ -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;
}
+1
View File
@@ -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;
+4 -1
View File
@@ -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__ */
+15 -240
View File
@@ -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);
+2 -22
View File
@@ -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_ */
+2 -9
View File
@@ -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();
}
+4 -2
View File
@@ -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,
+22 -4
View File
@@ -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;
+1 -1
View File
@@ -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);
+6 -6
View File
@@ -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,
+8 -8
View File
@@ -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;
+3 -3
View File
@@ -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;
+4 -5
View File
@@ -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);
+1 -3
View File
@@ -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,
+2
View File
@@ -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");
+124 -6
View File
@@ -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);
}
+3 -1
View File
@@ -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