Commit 0b684732 authored by Bartosz Podrygajlo's avatar Bartosz Podrygajlo

YAML as a drop-in replacement for libconfig

This commit introduces a substitute module library for setting up softmodems using YAML instead of libconfig.
The softmodems should work the same with both types of files. Extra care was put to make sure the behavior
of both modules is the same.

Example yaml config files were added for the UE and gNB
parent 69a84825
uicc0:
imsi: 208990100001100
key: fec86ba6eb707ed08905757b1bb44b8f
opc: C42449363BBAD02B66D16BC975D77CC1
dnn: oai
nssai_sst: 1
#/* configuration for channel modelisation */
#/* To be included in main config file when */
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
channelmod:
max_chan: 10;
modellist: modellist_rfsimu_1
modellist_rfsimu_1:
- model_name: rfsimu_channel_enB0
type: AWGN
ploss_dB: 20
noise_power_dB: -4
forgetfact: 0
offset: 0
ds_tdl: 0
- model_name: rfsimu_channel_ue0
type: AWGN
ploss_dB: 20
nose_power_dB: -2
forgetfact: 0
offset: 0
ds_tdl: 0
......@@ -589,8 +589,9 @@ check_install_oai_software() {
libtool \
patch \
openssl \
zlib1g-dev \
xxd
zlib1g-dev \
xxd \
libyaml-cpp-dev
elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]] || [[ "$OS_DISTRO" == "rocky" ]]; then
......@@ -625,7 +626,8 @@ check_install_oai_software() {
blas \
blas-devel \
vim-common \
zlib-devel
zlib-devel \
yaml-cpp-devel
fi
install_asn1c_from_source $1
......
add_subdirectory(utils)
add_subdirectory(config/yaml)
configure_file(oai_version.h.in oai_version.h @ONLY)
......@@ -293,8 +293,12 @@ configmodule_interface_t *load_configmodule(int argc,
} else if ( i == 1 ) {
/* -O argument doesn't contain ":" separator, assume -O <conf file> option, default cfgmode to libconfig
with one parameter, the path to the configuration file cfgmode must not be NULL */
modeparams=cfgmode;
cfgmode=strdup(CONFIG_LIBCONFIGFILE);
modeparams = cfgmode;
if (strstr(modeparams, ".yaml") != NULL || strstr(modeparams, ".yml") != NULL) {
cfgmode = strdup("yaml");
} else {
cfgmode = strdup(CONFIG_LIBCONFIGFILE);
}
}
static configmodule_interface_t *cfgptr;
if (cfgptr)
......
find_package(yaml-cpp REQUIRED)
# include(FetchContent)
# FetchContent_Declare(
# yaml-cpp
# GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
# GIT_TAG 0.8.0
# )
# FetchContent_GetProperties(yaml-cpp)
# if(NOT yaml-cpp_POPULATED)
# message(STATUS "Fetching yaml-cpp...")
# FetchContent_Populate(yaml-cpp)
# add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR})
# endif()
add_library(params_yaml_static config_yaml.cpp)
target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp)
if (ENABLE_TESTS)
add_subdirectory(tests)
endif()
add_library(params_yaml MODULE config_yaml.cpp)
target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp)
set_target_properties(params_yaml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
/*
* 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 "yaml-cpp/yaml.h"
extern "C" {
#include "common/config/config_load_configmodule.h"
#include "common/config/config_userapi.h"
void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree);
void config_check_valptr(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int elt_sz, int nb_elt);
}
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
#include <iostream>
namespace config_yaml {
class YamlConfig {
public:
YAML::Node config;
YamlConfig(std::string filename)
{
config = YAML::LoadFile(filename);
}
};
void SetDefault(configmodule_interface_t *cfg, paramdef_t *param)
{
switch (param->type) {
case TYPE_INT:
*param->iptr = param->defintval;
break;
case TYPE_UINT:
*param->uptr = param->defuintval;
break;
case TYPE_STRING:
if (param->defstrval != nullptr) {
if (param->numelt == 0) {
config_check_valptr(cfg, param, 1, strlen(param->defstrval) + 1);
}
sprintf(*param->strptr, "%s", param->defstrval);
}
break;
case TYPE_INT8:
*param->i8ptr = param->defintval;
break;
case TYPE_UINT8:
*param->i8ptr = param->defuintval;
break;
case TYPE_INT16:
*param->i16ptr = param->defintval;
break;
case TYPE_UINT16:
*param->u16ptr = param->defuintval;
break;
case TYPE_INT64:
*param->i64ptr = param->defint64val;
break;
case TYPE_UINT64:
*param->u64ptr = param->defint64val;
break;
case TYPE_DOUBLE:
*param->dblptr = param->defdblval;
break;
case TYPE_MASK:
*param->uptr = param->defuintval;
break;
case TYPE_STRINGLIST:
if (param->defstrlistval != nullptr) {
param->strlistptr = param->defstrlistval;
}
break;
case TYPE_INTARRAY:
if (param->defintarrayval) {
param->iptr = param->defintarrayval;
}
break;
case TYPE_UINTARRAY:
if (param->defintarrayval) {
param->uptr = (uint32_t *)param->defintarrayval;
}
break;
default:
AssertFatal(false, "Unhandled type %d", param->type);
}
param->paramflags |= PARAMFLAG_PARAMSETDEF;
}
void SetNonDefault(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *param)
{
auto optname = std::string(param->optname);
switch (param->type) {
case TYPE_INT:
*param->iptr = node[optname].as<int>();
break;
case TYPE_UINT:
*param->uptr = node[optname].as<uint>();
break;
case TYPE_STRING: {
std::string setting = node[optname].as<std::string>();
config_check_valptr(cfg, param, 1, setting.length() + 1);
sprintf(*param->strptr, "%s", setting.c_str());
break;
}
case TYPE_UINT8:
*param->i8ptr = node[optname].as<uint8_t>();
break;
case TYPE_INT16:
*param->i16ptr = node[optname].as<int16_t>();
break;
case TYPE_UINT16:
*param->u16ptr = node[optname].as<uint16_t>();
break;
case TYPE_INT64:
*param->i64ptr = node[optname].as<int64_t>();
break;
case TYPE_UINT64:
*param->u64ptr = node[optname].as<uint64_t>();
break;
case TYPE_DOUBLE:
*param->dblptr = node[optname].as<double>();
break;
case TYPE_MASK:
*param->uptr = node[optname].as<uint>();
break;
case TYPE_STRINGLIST: {
if (node[optname].IsSequence()) {
config_check_valptr(cfg, param, sizeof(char *), node[optname].size());
int i = 0;
for (const auto &elem : node[optname]) {
sprintf(param->strlistptr[i], "%s", elem.as<std::string>().c_str());
i++;
}
param->numelt = i;
} else {
param->numelt = 0;
}
break;
}
case TYPE_INTARRAY: {
if (node[optname].IsSequence() && node[optname].size() > 0) {
param->numelt = node[optname].size();
param->iptr =
(int32_t *)config_allocate_new(cfg, param->numelt * sizeof(*param->iptr), !(param->paramflags & PARAMFLAG_NOFREE));
for (int i = 0; i < param->numelt; i++) {
param->iptr[i] = node[optname][i].as<int32_t>();
}
} else {
param->numelt = 0;
}
break;
}
case TYPE_UINTARRAY: {
if (node[optname].IsSequence() && node[optname].size() > 0) {
param->numelt = node[optname].size();
param->uptr =
(uint32_t *)config_allocate_new(cfg, param->numelt * sizeof(*param->uptr), !(param->paramflags & PARAMFLAG_NOFREE));
for (int i = 0; i < param->numelt; i++) {
param->uptr[i] = node[optname][i].as<uint32_t>();
}
} else {
param->numelt = 0;
}
break;
}
default:
AssertFatal(false, "Unhandled type %d", param->type);
}
param->paramflags |= PARAMFLAG_PARAMSET;
}
void GetParams(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *params, int num_params)
{
for (auto i = 0; i < num_params; i++) {
if (node && node[std::string(params[i].optname)]) {
SetNonDefault(cfg, node, &params[i]);
} else {
SetDefault(cfg, &params[i]);
}
}
}
static YamlConfig *config;
static YAML::Node invalid_node;
} // namespace config_yaml
extern "C" int config_yaml_init(configmodule_interface_t *cfg)
{
char **cfgP = cfg->cfgP;
cfg->numptrs = 0;
pthread_mutex_init(&cfg->memBlocks_mutex, NULL);
memset(cfg->oneBlock, 0, sizeof(cfg->oneBlock));
config_yaml::config = new config_yaml::YamlConfig(std::string(cfgP[0]));
return 0;
}
extern "C" void config_yaml_end(configmodule_interface_t *cfg)
{
delete config_yaml::config;
}
YAML::Node find_node(const std::string &prefix, YAML::Node node)
{
// Iterate through each key in the prefix
std::stringstream ss(prefix);
std::string key;
YAML::Node current = node;
while (std::getline(ss, key, '.')) {
if (key.at(0) == '[' && key.back() == ']') {
// The key is an index to a sequence
if (!current.IsSequence()) {
throw std::invalid_argument("Incorrect yaml file structure");
}
int index = std::stoi(key.substr(1, key.size() - 2));
current = current[index];
continue;
}
if (!current.IsMap()) {
throw std::invalid_argument("Incorrect yaml file structure");
}
if (!current[key]) {
return config_yaml::invalid_node;
}
current = current[key];
}
return current;
}
extern "C" int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix)
{
std::string p;
if (prefix != nullptr) {
p = std::string(prefix);
}
auto node = find_node(p, YAML::Clone(config_yaml::config->config));
if (node == config_yaml::invalid_node) {
return -1;
}
for (auto i = 0; i < numoptions; i++) {
if (cfgoptions[i].type != TYPE_STRING && cfgoptions[i].type != TYPE_INTARRAY && cfgoptions[i].type != TYPE_UINTARRAY
&& cfgoptions[i].voidptr == nullptr) {
config_check_valptr(cfg, &cfgoptions[i], sizeof(void *), 1);
}
}
config_yaml::GetParams(cfg, node, cfgoptions, numoptions);
return 0;
}
extern "C" int config_yaml_getlist(configmodule_interface_t *cfg,
paramlist_def_t *ParamList,
paramdef_t *params,
int numparams,
char *prefix)
{
char path[512];
if (prefix != nullptr) {
sprintf(path, "%s.%s", prefix, ParamList->listname);
} else {
sprintf(path, "%s", ParamList->listname);
}
ParamList->numelt = 0;
auto node = find_node(path, YAML::Clone(config_yaml::config->config));
if (node == config_yaml::invalid_node) {
return -1;
}
if (!node.IsSequence()) {
return -1;
}
ParamList->numelt = node.size();
if (ParamList->numelt > 0 && params != NULL) {
ParamList->paramarray = static_cast<paramdef_t **>(config_allocate_new(cfg, ParamList->numelt * sizeof(paramdef_t *), true));
for (int i = 0; i < ParamList->numelt; i++) {
ParamList->paramarray[i] = static_cast<paramdef *>(config_allocate_new(cfg, numparams * sizeof(paramdef_t), true));
memcpy(ParamList->paramarray[i], params, sizeof(paramdef_t) * numparams);
for (int j = 0; j < numparams; j++) {
ParamList->paramarray[i][j].strptr = NULL;
if (ParamList->paramarray[i][j].type != TYPE_STRING) {
config_check_valptr(cfg, &ParamList->paramarray[i][j], sizeof(void *), 1);
}
}
config_yaml::GetParams(cfg, node[i], ParamList->paramarray[i], numparams);
}
}
return ParamList->numelt;
}
extern "C" void config_yaml_write_parsedcfg(configmodule_interface_t *cfg)
{
(void)cfg;
}
extern "C" int config_yaml_set(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix)
{
(void)cfg;
(void)cfgoptions;
(void)numoptions;
(void)prefix;
return 0;
}
add_executable(test_yaml_config test_yaml_config.cpp)
target_link_libraries(test_yaml_config PRIVATE params_yaml_static GTest::gtest)
add_dependencies(tests test_yaml_config)
add_test(NAME test_yaml_config
COMMAND ./test_yaml_config)
configure_file(test1.yaml test1.yaml COPYONLY)
configure_file(test_recursion.yaml test_recursion.yaml COPYONLY)
configure_file(test_list.yaml test_list.yaml COPYONLY)
configure_file(test_string.yaml test_string.yaml COPYONLY)
configure_file(test_list_of_mappings.yml test_list_of_mappings.yml COPYONLY)
configure_file(test_int_array.yaml test_int_array.yaml COPYONLY)
test:
value1: 1
value2: 2
value3: 3
test:
array: [1, 2, 3, 4]
array2:
- 1
- 2
- 3
test:
-
value1: 1
value2: 2
value3: 3
-
value1: 4
value2: 5
value3: 6
-
value1: 7
value2: 8
value3: 9
test:
list:
- value1: 1
value2: 3
list:
- value1
- value2
- value3
- value: 2
value2: 6
list:
- value4
- value5
- value6
test:
test1:
test2:
test3:
test4:
value1: 1
value2: 2
value3: 3
test:
stringvalue: testvalue
stringlist:
- testvalue1
- testvalue2
- testvalue3
/*
* 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 "gtest/gtest.h"
extern "C" {
#include "common/config/config_paramdesc.h"
// TODO: Should use minimal_lib for this but for some reason it doesn't link properly
uint64_t get_softmodem_optmask(void)
{
return 0;
}
configmodule_interface_t *uniqCfg;
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (assert) {
abort();
} else {
exit(EXIT_SUCCESS);
}
}
#include "common/utils/LOG/log.h"
#include "common/config/config_load_configmodule.h"
#include "common/config/config_userapi.h"
}
#include <cstdio>
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm>
extern "C" {
int config_yaml_init(configmodule_interface_t *cfg);
void config_yaml_end(configmodule_interface_t *cfg);
int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix);
int config_yaml_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, char *prefix);
void config_yaml_write_parsedcfg(configmodule_interface_t *cfg);
int config_yaml_set(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix);
}
TEST(yaml_config, yaml_basic) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test1.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, yaml_get_existing_values) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test1.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
// Testing paremters present in the test node
paramdef_t p = {0};
for (auto i = 1; i <= 3; i++) {
sprintf(p.optname, "%s%d", "value", i);
uint16_t value;
p.type = TYPE_UINT16;
p.u16ptr = &value;
char prefix[] = "test";
config_yaml_get(cfg, &p, 1, prefix);
EXPECT_EQ(value, i);
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, yaml_get_non_existing_values) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test1.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
// Testing paremters present in the test node
paramdef_t p = {0};
for (auto i = 4; i <= 5; i++) {
sprintf(p.optname, "%s%d", "value", i);
uint16_t value;
p.type = TYPE_UINT16;
p.u16ptr = &value;
p.defuintval = i;
char prefix[] = "test";
config_yaml_get(cfg, &p, 1, prefix);
EXPECT_EQ(value, i);
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_high_recusion) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_recursion.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
// Testing paremters present in the test node
paramdef_t p = {0};
for (auto i = 1; i <= 3; i++) {
sprintf(p.optname, "%s%d", "value", i);
uint16_t value;
p.type = TYPE_UINT16;
p.u16ptr = &value;
char prefix[] = "test.test1.test2.test3.test4";
EXPECT_EQ(config_yaml_get(cfg, &p, 1, prefix), 0);
EXPECT_EQ(value, i);
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_list) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_list.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramlist_def_t param_list = {0};
sprintf(param_list.listname, "%s", "test");
paramdef_t params[3] = {0};
uint16_t value[3];
for (auto i = 0; i < 3; i++) {
sprintf(params[i].optname, "%s%d", "value", i+1);
params[i].type = TYPE_UINT16;
params[i].u16ptr = &value[i];
}
config_yaml_getlist(cfg, &param_list, params, 3, nullptr);
for (auto i = 0; i < 3; i++) {
for (auto j = 0; j < 3; j++) {
EXPECT_EQ(*param_list.paramarray[i][j].u16ptr, i * 3 + j + 1);
}
}
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_auto_alloc) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// Test automatic allocation of strings
char prefix[] = "test";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0);
EXPECT_EQ(cfg->numptrs, 2);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_no_realloc) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// check that if we at least have a non-null pointer to pointer, only one buffer is allocated
char prefix[] = "test";
char* non_null_pointer_to_pointer = nullptr;
param.strptr = &non_null_pointer_to_pointer;
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_EQ(param.strptr, &non_null_pointer_to_pointer);
EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0);
EXPECT_EQ(cfg->numptrs, 1);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_pointer_available) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// Test that if a strptr is provided, config module doesnt reallocate it
char prefix[] = "test";
char *container = (char *)malloc(sizeof(char) * 30);
param.strptr = &container;
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_EQ(param.strptr, &container);
EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0);
EXPECT_EQ(cfg->numptrs, 0);
free(container);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_string_default_value) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRING;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue");
param.defstrval = nullptr;
// Test that if defstrval is not null and value is missing in yaml defstrval is set
char prefix[] = "test";
char default_value[] = "default";
param.defstrval = default_value;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringvalue_missing");
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_EQ(strcmp(*param.strptr, "default"), 0);
EXPECT_EQ(cfg->numptrs, 2) << " 2 pointers required, 1 for the string, one for the pointer-to string";
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_stringlist) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_string.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRINGLIST;
param.strptr = nullptr;
sprintf(param.optname, "%s", "stringlist");
param.defstrval = nullptr;
// Test automatic allocation of string lists
char prefix[] = "test";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.strptr, nullptr);
for (auto i = 0; i < param.numelt; i++) {
std::cout << (param.strlistptr)[i] << std::endl;
}
// config_check_valptr allocates maximum list size regardless of the number of elements in list
EXPECT_EQ(cfg->numptrs, MAX_LIST_SIZE + 1);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_list_of_mappings) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_list_of_mappings.yml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_STRINGLIST;
param.strlistptr = nullptr;
sprintf(param.optname, "%s", "list");
param.defstrval = nullptr;
// Test automatic allocation of string lists
char prefix1[] = "test.list.[0]";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix1), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_STREQ("value1", param.strlistptr[0]);
EXPECT_STREQ("value2", param.strlistptr[1]);
EXPECT_STREQ("value3", param.strlistptr[2]);
char prefix2[] = "test.list.[1]";
param.strlistptr = nullptr;
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix2), 0);
EXPECT_NE(param.strptr, nullptr);
EXPECT_STREQ("value4", param.strlistptr[0]);
EXPECT_STREQ("value5", param.strlistptr[1]);
EXPECT_STREQ("value6", param.strlistptr[2]);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
TEST(yaml_config, test_int_array) {
configmodule_interface_t *cfg = static_cast<configmodule_interface_t*>(calloc(1, sizeof(*cfg)));
cfg->cfgP[0] = strdup("test_int_array.yaml");
EXPECT_EQ(config_yaml_init(cfg), 0);
paramdef_t param = {0};
param.type = TYPE_INTARRAY;
param.iptr = nullptr;
sprintf(param.optname, "%s", "array");
param.defintarrayval = nullptr;
// Test automatic allocation of int arrays
char prefix[] = "test";
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.iptr, nullptr);
ASSERT_EQ(param.numelt, 4);
EXPECT_EQ(1, param.iptr[0]);
EXPECT_EQ(2, param.iptr[1]);
EXPECT_EQ(3, param.iptr[2]);
EXPECT_EQ(4, param.iptr[3]);
param.uptr = nullptr;
param.numelt = 0;
sprintf(param.optname, "%s", "array2");
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_NE(param.uptr, nullptr);
ASSERT_EQ(param.numelt, 3);
EXPECT_EQ(1U, param.uptr[0]);
EXPECT_EQ(2U, param.uptr[1]);
EXPECT_EQ(3U, param.uptr[2]);
param.uptr = nullptr;
param.numelt = 0;
sprintf(param.optname, "%s", "non-existent-array");
EXPECT_EQ(config_yaml_get(cfg, &param, 1, prefix), 0);
EXPECT_EQ(param.uptr, nullptr);
ASSERT_EQ(param.numelt, 0);
config_yaml_end(cfg);
free(cfg->cfgP[0]);
end_configmodule(cfg);
}
int main(int argc, char** argv)
{
logInit();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Active_gNBs:
- gNB-OAI
Asn1_verbosity: none
gNBs:
# Identification parameters:
- gNB_ID: 0xe00
gNB_name: gNB-OAI
# Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code: 1
plmn_list:
-
mcc: 001
mnc: 01
mnc_length: 2
snssaiList:
-
sst: 1
nr_cellid: 12345678
# Physical parameters:
do_CSIRS: 1
do_SRS: 1
servingCellConfigCommon:
#spCellConfigCommon
- physCellId: 0
# downlinkConfigCommon
#frequencyInfoDL
# this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
absoluteFrequencySSB: 641280
dl_frequencyBand: 78
# this is 3600 MHz
dl_absoluteFrequencyPointA: 640008
#scs-SpecificCarrierList
dl_offstToCarrier: 0
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing: 1
dl_carrierBandwidth: 106
#initialDownlinkBWP
#genericParameters
# this is RBstart=27,L=48 (275*(L-1))+RBstart
initialDLBWPlocationAndBandwidth: 28875 # 6366 12925 12956 28875 12952
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing: 1
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero: 12
initialDLBWPsearchSpaceZero: 0
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand: 78
#scs-SpecificCarrierList
ul_offstToCarrier: 0
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing: 1
ul_carrierBandwidth: 106
pMax: 20
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth: 28875
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing: 1
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex: 98
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM: 0
prach_msg1_FrequencyStart: 0
zeroCorrelationZoneConfig: 13
preambleReceivedTargetPower: -96
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax: 6
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep: 1
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow: 4
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4
#oneHalf (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB: 14
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer: 7
rsrp_ThresholdSSB: 19
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR: 2
prach_RootSequenceIndex: 1
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
msg1_SubcarrierSpacing: 1
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig: 0
msg3_DeltaPreamble: 1
p0_NominalWithGrant: -90
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping: 0
hoppingId: 40
p0_nominal: -90
# ssb_PositionsInBurs_BitmapPR
# 1=short, 2=medium, 3=long
ssb_PositionsInBurst_PR: 2
ssb_PositionsInBurst_Bitmap: 1
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell: 2
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position: 0
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing: 1
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing: 1
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity: 6
nrofDownlinkSlots: 7
nrofDownlinkSymbols: 6
nrofUplinkSlots: 2
nrofUplinkSymbols: 4
ssPBCH_BlockPower: -25
SCTP:
SCTP_INSTREAMS: 2
SCTP_OUTSTREAMS: 2
# AMF parameters:
amf_ip_address:
ipv4: 192.168.70.132
NETWORK_INTERFACES:
GNB_IPV4_ADDRESS_FOR_NG_AMF: 192.168.70.129
GNB_IPV4_ADDRESS_FOR_NGU: 192.168.70.129
GNB_PORT_FOR_S1U: 2152 # Spec 2152
MACRLCs:
-
num_cc: 1
tr_s_preference: local_L1
tr_n_preference: local_RRC
pusch_TargetSNRx10: 150
pucch_TargetSNRx10: 200
L1s:
-
num_cc: 1
tr_n_preference: local_mac
prach_dtx_threshold: 120
pucch0_dtx_threshold: 100
ofdm_offset_divisor: 8 #set this to UINT_MAX for offset 0
RUs:
-
local_rf: yes
nb_tx: 1
nb_rx: 1
att_tx: 12
att_rx: 12
bands: [78]
max_pdschReferenceSignalPower: -27
max_rxgain: 114
eNB_instances: [0]
bf_weights: [0x00007fff, 0x0000, 0x0000, 0x0000]
clock_src: internal
rfsimulator:
serveraddr: server
serverport: 4043
options: [] #("saviq"); or/and "chanmod"
modelname: AWGN
IQfile: /tmp/rfsimulator.iqs
security:
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms: [nea0]
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms: [nia2, nia0]
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering: yes
drb_integrity: no
log_config:
global_log_level: info
hw_log_level: info
phy_log_level: info
mac_log_level: info
rlc_log_level: info
pdcp_log_level: info
rrc_log_level: info
ngap_log_level: debug
f1ap_log_level: debug
e2_agent:
near_ric_ip_addr: 127.0.0.1
#sm_dir = /path/where/the/SMs/are/located/
sm_dir: /usr/local/lib/flexric/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment