moved all the parsing of the libconfig files to separate functions that can be called from individual tests. Created several stack layer dummy classes for testing. Extended the rrc_mobility test to check correctness of RRC HOPreparation struct

This commit is contained in:
Francisco Paisana 2019-12-05 16:15:15 +00:00
parent b792a3158c
commit a18a7e307e
11 changed files with 1116 additions and 777 deletions

View File

@ -134,9 +134,8 @@ public:
// eNodeB metrics interface
bool get_metrics(enb_metrics_t* m);
private:
static enb *instance;
static enb* instance;
const static int ENB_POOL_SIZE = 1024*10;
@ -169,18 +168,7 @@ private:
srslte::LOG_LEVEL_ENUM level(std::string l);
// bool check_srslte_version();
int parse_sib1(std::string filename, asn1::rrc::sib_type1_s* data);
int parse_sib2(std::string filename, asn1::rrc::sib_type2_s* data);
int parse_sib3(std::string filename, asn1::rrc::sib_type3_s* data);
int parse_sib4(std::string filename, asn1::rrc::sib_type4_s* data);
int parse_sib7(std::string filename, asn1::rrc::sib_type7_s* data);
int parse_sib9(std::string filename, asn1::rrc::sib_type9_s* data);
int parse_sib13(std::string filename, asn1::rrc::sib_type13_r9_s* data);
int parse_sibs(all_args_t* args, rrc_cfg_t* rrc_cfg, phy_cfg_t* phy_config_common);
int parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg);
int parse_drb(all_args_t* args, rrc_cfg_t* rrc_cfg);
bool sib_is_present(const asn1::rrc::sched_info_list_l& l, asn1::rrc::sib_type_e sib_num);
int parse_cell_cfg(all_args_t* args, srslte_cell_t* cell);
int parse_cell_cfg(all_args_t* args, srslte_cell_t* cell);
std::string get_build_mode();
std::string get_build_info();

View File

@ -35,15 +35,15 @@
#include "txrx.h"
namespace srsenb {
typedef struct {
struct phy_cfg_t {
srslte_cell_t cell;
asn1::rrc::prach_cfg_sib_s prach_cnfg;
asn1::rrc::pdsch_cfg_common_s pdsch_cnfg;
asn1::rrc::pusch_cfg_common_s pusch_cnfg;
asn1::rrc::pucch_cfg_common_s pucch_cnfg;
asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg;
} phy_cfg_t;
};
class phy : public enb_phy_base, public phy_interface_stack_lte, public srslte::phy_interface_radio
{

View File

@ -146,15 +146,15 @@ public:
rrc();
~rrc();
void init(rrc_cfg_t* cfg,
phy_interface_stack_lte* phy,
mac_interface_rrc* mac,
rlc_interface_rrc* rlc,
pdcp_interface_rrc* pdcp,
s1ap_interface_rrc* s1ap,
gtpu_interface_rrc* gtpu,
srslte::timer_handler* timers_,
srslte::log* log_rrc);
void init(rrc_cfg_t* cfg,
phy_interface_rrc_lte* phy,
mac_interface_rrc* mac,
rlc_interface_rrc* rlc,
pdcp_interface_rrc* pdcp,
s1ap_interface_rrc* s1ap,
gtpu_interface_rrc* gtpu,
srslte::timer_handler* timers_,
srslte::log* log_rrc);
void stop();
void get_metrics(rrc_metrics_t& m);
@ -342,7 +342,7 @@ private:
// args
srslte::timer_handler* timers = nullptr;
srslte::byte_buffer_pool* pool = nullptr;
phy_interface_stack_lte* phy = nullptr;
phy_interface_rrc_lte* phy = nullptr;
mac_interface_rrc* mac = nullptr;
rlc_interface_rrc* rlc = nullptr;
pdcp_interface_rrc* pdcp = nullptr;
@ -407,7 +407,7 @@ private:
sr_sched_t sr_sched = {};
sr_sched_t cqi_sched = {};
asn1::rrc::mcch_msg_s mcch;
bool enable_mbms = false;
bool enable_mbms = false;
rrc_cfg_t cfg = {};
uint32_t nof_si_messages = 0;
asn1::rrc::sib_type2_s sib2;

View File

@ -33,8 +33,9 @@ if (RPATH)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif (RPATH)
add_library(enb_cfg_parser parser.cc enb_cfg_parser.cc)
add_executable(srsenb main.cc enb.cc parser.cc enb_cfg_parser.cc metrics_stdout.cc metrics_csv.cc)
add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc)
target_link_libraries(srsenb srsenb_radio
srsenb_phy
srsenb_stack
@ -46,6 +47,7 @@ target_link_libraries(srsenb srsenb_radio
srslte_upper
srslte_radio
rrc_asn1
enb_cfg_parser
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
${SEC_LIBRARIES}

View File

@ -22,6 +22,7 @@
#include "srsenb/hdr/enb.h"
#include "srsenb/hdr/radio/enb_radio_multi.h"
#include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srsenb/src/enb_cfg_parser.h"
#include "srslte/build_info.h"
#include <boost/algorithm/string.hpp>
#include <iostream>
@ -39,7 +40,7 @@ enb* enb::get_instance()
instance = new enb();
}
pthread_mutex_unlock(&enb_instance_mutex);
return(instance);
return (instance);
}
void enb::cleanup()
{
@ -61,10 +62,7 @@ enb::enb() : started(false), pool(srslte::byte_buffer_pool::get_instance(ENB_POO
srslte_dft_load();
}
enb::~enb()
{
}
enb::~enb() {}
int enb::init(const all_args_t& args_)
{
@ -164,115 +162,16 @@ int enb::parse_args(const all_args_t& args_)
{
// set member variable
args = args_;
// Parse config files
srslte_cell_t cell_cfg = {};
if (parse_cell_cfg(&args, &cell_cfg)) {
fprintf(stderr, "Error parsing Cell configuration\n");
return SRSLTE_ERROR;
}
if (parse_sibs(&args, &rrc_cfg, &phy_cfg)) {
fprintf(stderr, "Error parsing SIB configuration\n");
return SRSLTE_ERROR;
}
if (parse_rr(&args, &rrc_cfg)) {
fprintf(stderr, "Error parsing Radio Resources configuration\n");
return SRSLTE_ERROR;
}
if (parse_drb(&args, &rrc_cfg)) {
fprintf(stderr, "Error parsing DRB configuration\n");
return SRSLTE_ERROR;
}
if (args.enb.transmission_mode == 1) {
phy_cfg.pdsch_cnfg.p_b = 0; // Default TM1
rrc_cfg.sibs[1].sib2().rr_cfg_common.pdsch_cfg_common.p_b = 0;
} else {
phy_cfg.pdsch_cnfg.p_b = 1; // Default TM2,3,4
rrc_cfg.sibs[1].sib2().rr_cfg_common.pdsch_cfg_common.p_b = 1;
}
rrc_cfg.inactivity_timeout_ms = args.general.rrc_inactivity_timer;
rrc_cfg.enable_mbsfn = args.stack.embms.enable;
rrc_cfg.dl_earfcn = args.enb.dl_earfcn;
rrc_cfg.pci = args.enb.pci;
// Check number of control symbols
if (cell_cfg.nof_prb < 50 && args.stack.mac.sched.nof_ctrl_symbols != 3) {
args.stack.mac.sched.nof_ctrl_symbols = 3;
fprintf(stdout,
"Setting number of control symbols to %d for %d PRB cell.\n",
args.stack.mac.sched.nof_ctrl_symbols,
cell_cfg.nof_prb);
}
// Parse EEA preference list
std::vector<std::string> eea_pref_list;
boost::split(eea_pref_list, args.general.eea_pref_list, boost::is_any_of(","));
int i = 0;
for (auto it = eea_pref_list.begin(); it != eea_pref_list.end() && i < srslte::CIPHERING_ALGORITHM_ID_N_ITEMS; it++) {
boost::trim_left(*it);
if ((*it) == "EEA0") {
rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_EEA0;
i++;
} else if ((*it) == "EEA1") {
rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA1;
i++;
} else if ((*it) == "EEA2") {
rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA2;
i++;
} else if ((*it) == "EEA3") {
rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA3;
i++;
} else {
fprintf(stderr, "Failed to parse EEA prefence list %s \n", args.general.eea_pref_list.c_str());
return SRSLTE_ERROR;
}
}
// Parse EIA preference list
std::vector<std::string> eia_pref_list;
boost::split(eia_pref_list, args.general.eia_pref_list, boost::is_any_of(","));
i = 0;
for (auto it = eia_pref_list.begin(); it != eia_pref_list.end() && i < srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS; it++) {
boost::trim_left(*it);
if ((*it) == "EIA0") {
rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_EIA0;
i++;
} else if ((*it) == "EIA1") {
rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1;
i++;
} else if ((*it) == "EIA2") {
rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA2;
i++;
} else if ((*it) == "EIA3") {
rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA3;
i++;
} else {
fprintf(stderr, "Failed to parse EIA prefence list %s \n", args.general.eia_pref_list.c_str());
return SRSLTE_ERROR;
}
}
// Copy cell struct to rrc and phy
rrc_cfg.cell = cell_cfg;
phy_cfg.cell = cell_cfg;
// Patch certain args that are not exposed yet
args.rf.nof_radios = 1;
args.rf.nof_rf_channels = args.phy.nof_carriers;
args.rf.nof_rx_ant = args.enb.nof_ports;
return SRSLTE_SUCCESS;
return enb_conf_sections::parse_cfg_files(&args, &rrc_cfg, &phy_cfg);
}
void enb::start_plot() {
void enb::start_plot()
{
phy->start_plot();
}
void enb::print_pool() {
void enb::print_pool()
{
srslte::byte_buffer_pool::get_instance()->print_all_buffers();
}
@ -288,17 +187,17 @@ bool enb::get_metrics(enb_metrics_t* m)
srslte::LOG_LEVEL_ENUM enb::level(std::string l)
{
boost::to_upper(l);
if("NONE" == l){
if ("NONE" == l) {
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
} else if ("ERROR" == l) {
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
} else if ("WARNING" == l) {
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
} else if ("INFO" == l) {
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
} else if ("DEBUG" == l) {
return srslte::LOG_LEVEL_DEBUG;
}else{
} else {
return srslte::LOG_LEVEL_NONE;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,61 @@ namespace srsenb {
using namespace libconfig;
class all_args_t;
struct all_args_t;
struct phy_cfg_t;
bool sib_is_present(const asn1::rrc::sched_info_list_l& l, asn1::rrc::sib_type_e sib_num);
// enb.conf parsing
namespace enb_conf_sections {
int parse_cell_cfg(all_args_t* args_, srslte_cell_t* cell);
int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_);
int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_, srslte_cell_t* cell_cfg_);
} // namespace enb_conf_sections
// sib.conf parsing
namespace sib_sections {
int parse_sib1(std::string filename, asn1::rrc::sib_type1_s* data);
int parse_sib2(std::string filename, asn1::rrc::sib_type2_s* data);
int parse_sib3(std::string filename, asn1::rrc::sib_type3_s* data);
int parse_sib4(std::string filename, asn1::rrc::sib_type4_s* data);
int parse_sib7(std::string filename, asn1::rrc::sib_type7_s* data);
int parse_sib9(std::string filename, asn1::rrc::sib_type9_s* data);
int parse_sib13(std::string filename, asn1::rrc::sib_type13_r9_s* data);
int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_config_common);
} // namespace sib_sections
// drb.conf parsing
namespace drb_sections {
int parse_drb(all_args_t* args, rrc_cfg_t* rrc_cfg);
} // namespace drb_sections
// rr.conf parsing
namespace rr_sections {
int parse_rr(all_args_t* args_, rrc_cfg_t* rrc_cfg_);
// rrc_cnfg
class cell_list_section final : public parser::field_itf
{
public:
explicit cell_list_section(all_args_t* all_args_, rrc_cfg_t* rrc_cfg_) : args(all_args_), rrc_cfg(rrc_cfg_) {}
int parse(Setting& root) override;
const char* get_name() override { return "meas_cell_list"; }
private:
rrc_cfg_t* rrc_cfg;
all_args_t* args;
};
} // namespace rr_sections
class field_sched_info final : public parser::field_itf
{
@ -111,26 +165,6 @@ private:
rrc_cfg_qci_t* cfg;
};
namespace rr_sections {
// rrc_cnfg
class cell_list_section final : public parser::field_itf
{
public:
explicit cell_list_section(all_args_t* all_args_, rrc_cfg_t* rrc_cfg_) : args(all_args_), rrc_cfg(rrc_cfg_) {}
int parse(Setting& root) override;
const char* get_name() override { return "meas_cell_list"; }
private:
rrc_cfg_t* rrc_cfg;
all_args_t* args;
};
} // namespace rr_sections
// ASN1 parsers
class field_asn1 : public parser::field_itf

View File

@ -45,15 +45,15 @@ rrc::rrc() : cnotifier(nullptr), nof_si_messages(0)
rrc::~rrc() {}
void rrc::init(rrc_cfg_t* cfg_,
phy_interface_stack_lte* phy_,
mac_interface_rrc* mac_,
rlc_interface_rrc* rlc_,
pdcp_interface_rrc* pdcp_,
s1ap_interface_rrc* s1ap_,
gtpu_interface_rrc* gtpu_,
srslte::timer_handler* timers_,
srslte::log* log_rrc)
void rrc::init(rrc_cfg_t* cfg_,
phy_interface_rrc_lte* phy_,
mac_interface_rrc* mac_,
rlc_interface_rrc* rlc_,
pdcp_interface_rrc* pdcp_,
s1ap_interface_rrc* s1ap_,
gtpu_interface_rrc* gtpu_,
srslte::timer_handler* timers_,
srslte::log* log_rrc)
{
phy = phy_;
mac = mac_;
@ -1208,9 +1208,10 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
}
break;
case ul_dcch_msg_type_c::c1_c_::types::meas_report:
printf("Received MEASUREMENT REPORT!\n");
if (mobility_handler != nullptr) {
mobility_handler->handle_ue_meas_report(ul_dcch_msg.msg.c1().meas_report());
} else {
parent->rrc_log->warning("Received MeasReport but no mobility configuration is available\n");
}
break;
default:

View File

@ -0,0 +1,112 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_DUMMY_CLASSES_H
#define SRSLTE_DUMMY_CLASSES_H
#include "srslte/interfaces/enb_interfaces.h"
namespace srsenb {
class rlc_dummy : public rlc_interface_rrc
{
public:
void clear_buffer(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srslte::rlc_config_t cnfg) override {}
void add_bearer_mrb(uint16_t rnti, uint32_t lcid) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override {}
bool has_bearer(uint16_t rnti, uint32_t lcid) override { return false; }
};
class pdcp_dummy : public pdcp_interface_rrc
{
public:
void reset(uint16_t rnti) override {}
void add_user(uint16_t rnti) override {}
void rem_user(uint16_t rnti) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override {}
void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) override {}
void config_security(uint16_t rnti,
uint32_t lcid,
uint8_t* k_rrc_enc_,
uint8_t* k_rrc_int_,
uint8_t* k_up_enc_,
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo_,
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo_) override
{
}
void enable_integrity(uint16_t rnti, uint32_t lcid) override {}
void enable_encryption(uint16_t rnti, uint32_t lcid) override {}
};
class s1ap_dummy : public s1ap_interface_rrc
{
public:
void
initial_ue(uint16_t rnti, LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause, srslte::unique_byte_buffer_t pdu) override
{
}
void initial_ue(uint16_t rnti,
LIBLTE_S1AP_RRC_ESTABLISHMENT_CAUSE_ENUM cause,
srslte::unique_byte_buffer_t pdu,
uint32_t m_tmsi,
uint8_t mmec) override
{
}
void write_pdu(uint16_t rnti, srslte::unique_byte_buffer_t pdu) override {}
bool user_exists(uint16_t rnti) override { return true; }
bool user_release(uint16_t rnti, LIBLTE_S1AP_CAUSERADIONETWORK_ENUM cause_radio) override { return true; }
void ue_ctxt_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT* res) override {}
void ue_erab_setup_complete(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT* res) override {}
bool is_mme_connected() override { return true; }
bool send_ho_required(uint16_t rnti,
uint32_t target_eci,
srslte::plmn_id_t target_plmn,
srslte::unique_byte_buffer_t rrc_container) override
{
return true;
}
};
class phy_dummy : public phy_interface_rrc_lte
{
public:
void
configure_mbsfn(asn1::rrc::sib_type2_s* sib2, asn1::rrc::sib_type13_r9_s* sib13, asn1::rrc::mcch_msg_s mcch) override
{
}
void set_config_dedicated(uint16_t rnti, asn1::rrc::phys_cfg_ded_s* dedicated) override {}
};
class gtpu_dummy : public gtpu_interface_rrc
{
public:
void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t* teid_in) {}
void rem_bearer(uint16_t rnti, uint32_t lcid) {}
void rem_user(uint16_t rnti) {}
};
} // namespace srsenb
#endif // SRSLTE_DUMMY_CLASSES_H

View File

@ -23,4 +23,6 @@ add_executable(plmn_test plmn_test.cc)
target_link_libraries(plmn_test rrc_asn1)
add_executable(rrc_mobility_test rrc_mobility_test.cc)
target_link_libraries(rrc_mobility_test srsenb_rrc rrc_asn1 srslte_common srslte_asn1)
target_link_libraries(rrc_mobility_test srsenb_rrc rrc_asn1 srslte_common srslte_asn1 enb_cfg_parser ${LIBCONFIGPP_LIBRARIES})
add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)

View File

@ -19,7 +19,10 @@
*
*/
#include "srsenb/hdr/enb.h"
#include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srsenb/src/enb_cfg_parser.h"
#include "srsenb/test/common/dummy_classes.h"
#include "srslte/asn1/rrc_asn1_utils.h"
#include "srslte/common/test_common.h"
#include <iostream>
@ -28,7 +31,67 @@
using namespace srsenb;
using namespace asn1::rrc;
srslte::log_filter log_h("ALL");
srslte::scoped_tester_log log_h("ALL");
namespace argparse {
std::string repository_dir;
srslte::LOG_LEVEL_ENUM log_level;
void usage(char* prog)
{
printf("Usage: %s [v] -i repository_dir\n", prog);
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char** argv)
{
int opt;
while ((opt = getopt(argc, argv, "i")) != -1) {
switch (opt) {
case 'i':
repository_dir = argv[optind];
break;
case 'v':
log_level = srslte::LOG_LEVEL_DEBUG;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (repository_dir.empty()) {
usage(argv[0]);
exit(-1);
}
}
} // namespace argparse
namespace test_dummies {
class s1ap_mobility_dummy : public s1ap_dummy
{
public:
struct ho_req_data {
uint16_t rnti;
uint32_t target_eci;
srslte::plmn_id_t target_plmn;
srslte::unique_byte_buffer_t rrc_container;
} last_ho_required;
bool send_ho_required(uint16_t rnti,
uint32_t target_eci,
srslte::plmn_id_t target_plmn,
srslte::unique_byte_buffer_t rrc_container) final
{
last_ho_required = ho_req_data{rnti, target_eci, target_plmn, std::move(rrc_container)};
return true;
}
};
} // namespace test_dummies
class mac_dummy : public mac_interface_rrc
{
@ -254,61 +317,173 @@ int test_correct_meascfg_calculation()
return SRSLTE_SUCCESS;
}
int test_mobility_class()
int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args)
{
srslte::scoped_tester_log log_test("MOBILITY_TEST");
args = {};
*rrc_cfg = {};
args.enb_files.sib_config = argparse::repository_dir + "/sib.conf.example";
args.enb_files.rr_config = argparse::repository_dir + "/rr.conf.example";
args.enb_files.drb_config = argparse::repository_dir + "/drb.conf.example";
log_h.debug("sib file path=%s\n", args.enb_files.sib_config.c_str());
rrc_cfg_t cfg;
cfg.sib1.cell_access_related_info.plmn_id_list.push_back({});
cfg.sib1.cell_access_related_info.plmn_id_list[0].plmn_id.mnc.resize(2);
cfg.sib1.cell_access_related_info.plmn_id_list[0].cell_reserved_for_oper.value =
plmn_id_info_s::cell_reserved_for_oper_opts::not_reserved;
cfg.sib1.cell_access_related_info.cell_barred.value =
sib_type1_s::cell_access_related_info_s_::cell_barred_opts::not_barred;
cfg.sib1.cell_access_related_info.intra_freq_resel.value =
sib_type1_s::cell_access_related_info_s_::intra_freq_resel_opts::allowed;
cfg.sib1.si_win_len.value = sib_type1_s::si_win_len_opts::ms5;
cfg.sib1.sched_info_list.push_back({});
cfg.sib1.sched_info_list[0].si_periodicity.value = sched_info_s::si_periodicity_opts::rf8;
auto& sib2 = cfg.sibs[1].set_sib2();
sib2.rr_cfg_common.rach_cfg_common.preamb_info.nof_ra_preambs.value =
rach_cfg_common_s::preamb_info_s_::nof_ra_preambs_opts::n4;
sib2.rr_cfg_common.rach_cfg_common.pwr_ramp_params.pwr_ramp_step.value = pwr_ramp_params_s::pwr_ramp_step_opts::db0;
sib2.rr_cfg_common.rach_cfg_common.pwr_ramp_params.preamb_init_rx_target_pwr.value =
pwr_ramp_params_s::preamb_init_rx_target_pwr_opts::dbm_minus90;
sib2.rr_cfg_common.rach_cfg_common.ra_supervision_info.preamb_trans_max.value = preamb_trans_max_opts::n4;
sib2.rr_cfg_common.rach_cfg_common.ra_supervision_info.ra_resp_win_size.value =
rach_cfg_common_s::ra_supervision_info_s_::ra_resp_win_size_opts::sf2;
sib2.rr_cfg_common.rach_cfg_common.ra_supervision_info.mac_contention_resolution_timer.value =
rach_cfg_common_s::ra_supervision_info_s_::mac_contention_resolution_timer_opts::sf8;
sib2.rr_cfg_common.bcch_cfg.mod_period_coeff.value = bcch_cfg_s::mod_period_coeff_opts::n4;
sib2.rr_cfg_common.pcch_cfg.default_paging_cycle.value = pcch_cfg_s::default_paging_cycle_opts::rf32;
sib2.rr_cfg_common.pcch_cfg.nb.value = pcch_cfg_s::nb_opts::four_t;
sib2.rr_cfg_common.pusch_cfg_common.pusch_cfg_basic.hop_mode.value =
pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_opts::inter_sub_frame;
sib2.rr_cfg_common.pucch_cfg_common.delta_pucch_shift.value = pucch_cfg_common_s::delta_pucch_shift_opts::ds1;
sib2.rr_cfg_common.srs_ul_cfg_common.set(setup_opts::release);
sib2.rr_cfg_common.ul_pwr_ctrl_common.alpha.value = alpha_r12_opts::al0;
bzero(&sib2.rr_cfg_common.ul_pwr_ctrl_common.delta_flist_pucch,
sizeof(sib2.rr_cfg_common.ul_pwr_ctrl_common.delta_flist_pucch));
sib2.rr_cfg_common.ul_cp_len.value = ul_cp_len_opts::len1;
bzero(&sib2.ue_timers_and_consts, sizeof(sib2.ue_timers_and_consts));
sib2.time_align_timer_common.value = time_align_timer_opts::sf500;
report_cfg_eutra_s rep = generate_rep1();
args.enb.dl_earfcn = 3400;
args.enb.n_prb = 50;
TESTASSERT(srslte::string_to_mcc("001", &args.stack.s1ap.mcc));
TESTASSERT(srslte::string_to_mnc("01", &args.stack.s1ap.mnc));
args.enb.transmission_mode = 1;
args.enb.nof_ports = 1;
args.general.eia_pref_list = "EIA2, EIA1, EIA0";
args.general.eea_pref_list = "EEA0, EEA2, EEA1";
phy_cfg_t phy_cfg;
return enb_conf_sections::parse_cfg_files(&args, rrc_cfg, &phy_cfg);
}
struct mobility_test_params {
enum class test_fail_at { never, wrong_measreport } fail_at;
};
int test_mobility_class(mobility_test_params test_params)
{
log_h.info("----- TEST: test_mobility_class() -----\n");
srslte::log_filter s1ap_log("S1AP");
srslte::scoped_tester_log rrc_log("RRC ");
srslte::timer_handler timers;
srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance();
srslte::unique_byte_buffer_t pdu;
auto copy_msg_to_buffer = [pool](srslte::unique_byte_buffer_t& pdu, uint8_t* msg, size_t nof_bytes) {
pdu = srslte::allocate_unique_buffer(*pool, true);
memcpy(pdu->msg, msg, nof_bytes);
pdu->N_bytes = nof_bytes;
};
srsenb::all_args_t args;
rrc_cfg_t cfg;
TESTASSERT(parse_default_cfg(&cfg, args) == SRSLTE_SUCCESS);
report_cfg_eutra_s rep = generate_rep1();
cfg.meas_cfg.meas_reports.push_back(rep);
meas_cell_cfg_t cell2 = generate_cell1();
cell2.pci = 2;
cell2.eci = 0x19C02;
cfg.meas_cfg.meas_cells.push_back(cell2);
srsenb::rrc rrc;
mac_dummy mac;
// rrc.init(&cfg, nullptr, &mac, nullptr, nullptr, nullptr, nullptr, &log_h);
srsenb::rrc rrc;
mac_dummy mac;
rlc_dummy rlc;
pdcp_dummy pdcp;
phy_dummy phy;
test_dummies::s1ap_mobility_dummy s1ap;
gtpu_dummy gtpu;
rrc_log.set_level(srslte::LOG_LEVEL_INFO);
rrc_log.set_hex_limit(1024);
s1ap_log.set_level(srslte::LOG_LEVEL_INFO);
s1ap_log.set_hex_limit(1024);
rrc.init(&cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &timers, &rrc_log);
auto tic = [&timers, &rrc] {
timers.step_all();
rrc.tti_clock();
};
uint16_t rnti = 0x46;
rrc.add_user(rnti);
// Send RRCConnectionRequest
uint8_t rrc_conn_request[] = {0x40, 0x12, 0xf6, 0xfb, 0xe2, 0xc6};
copy_msg_to_buffer(pdu, rrc_conn_request, sizeof(rrc_conn_request));
rrc.write_pdu(rnti, 0, std::move(pdu));
tic();
// Send RRCConnectionSetupComplete
uint8_t rrc_conn_setup_complete[] = {0x20, 0x00, 0x40, 0x2e, 0x90, 0x50, 0x49, 0xe8, 0x06, 0x0e, 0x82, 0xa2,
0x17, 0xec, 0x13, 0xe2, 0x0f, 0x00, 0x02, 0x02, 0x5e, 0xdf, 0x7c, 0x58,
0x05, 0xc0, 0xc0, 0x00, 0x08, 0x04, 0x03, 0xa0, 0x23, 0x23, 0xc0};
copy_msg_to_buffer(pdu, rrc_conn_setup_complete, sizeof(rrc_conn_setup_complete));
rrc.write_pdu(rnti, 1, std::move(pdu));
tic();
// S1AP receives InitialContextSetupRequest and forwards it to RRC
uint8_t s1ap_init_ctxt_setup_req[] = {
0x00, 0x09, 0x00, 0x80, 0xc6, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x64, 0x00, 0x08, 0x00, 0x02, 0x00,
0x01, 0x00, 0x42, 0x00, 0x0a, 0x18, 0x3b, 0x9a, 0xca, 0x00, 0x60, 0x3b, 0x9a, 0xca, 0x00, 0x00, 0x18, 0x00, 0x78,
0x00, 0x00, 0x34, 0x00, 0x73, 0x45, 0x00, 0x09, 0x3c, 0x0f, 0x80, 0x0a, 0x00, 0x21, 0xf0, 0xb7, 0x36, 0x1c, 0x56,
0x64, 0x27, 0x3e, 0x5b, 0x04, 0xb7, 0x02, 0x07, 0x42, 0x02, 0x3e, 0x06, 0x00, 0x09, 0xf1, 0x07, 0x00, 0x07, 0x00,
0x37, 0x52, 0x66, 0xc1, 0x01, 0x09, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63,
0x30, 0x37, 0x30, 0x06, 0x6d, 0x63, 0x63, 0x39, 0x30, 0x31, 0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0xc0, 0xa8,
0x03, 0x02, 0x27, 0x0e, 0x80, 0x80, 0x21, 0x0a, 0x03, 0x00, 0x00, 0x0a, 0x81, 0x06, 0x08, 0x08, 0x08, 0x08, 0x50,
0x0b, 0xf6, 0x09, 0xf1, 0x07, 0x80, 0x01, 0x01, 0xf6, 0x7e, 0x72, 0x69, 0x13, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x23,
0x05, 0xf4, 0xf6, 0x7e, 0x72, 0x69, 0x00, 0x6b, 0x00, 0x05, 0x18, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x20,
0x45, 0x25, 0xe4, 0x9a, 0x77, 0xc8, 0xd5, 0xcf, 0x26, 0x33, 0x63, 0xeb, 0x5b, 0xb9, 0xc3, 0x43, 0x9b, 0x9e, 0xb3,
0x86, 0x1f, 0xa8, 0xa7, 0xcf, 0x43, 0x54, 0x07, 0xae, 0x42, 0x2b, 0x63, 0xb9};
LIBLTE_S1AP_S1AP_PDU_STRUCT s1ap_pdu;
LIBLTE_BYTE_MSG_STRUCT byte_buf;
byte_buf.N_bytes = sizeof(s1ap_init_ctxt_setup_req);
memcpy(byte_buf.msg, s1ap_init_ctxt_setup_req, byte_buf.N_bytes);
liblte_s1ap_unpack_s1ap_pdu(&byte_buf, &s1ap_pdu);
rrc.setup_ue_ctxt(rnti, &s1ap_pdu.choice.initiatingMessage.choice.InitialContextSetupRequest);
tic();
// Send SecurityModeComplete
uint8_t sec_mode_complete[] = {0x28, 0x00};
copy_msg_to_buffer(pdu, sec_mode_complete, sizeof(sec_mode_complete));
rrc.write_pdu(rnti, 1, std::move(pdu));
tic();
/* Receive MeasReport from UE (correct if PCI=2) */
if (test_params.fail_at == mobility_test_params::test_fail_at::wrong_measreport) {
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x0D, 0xBC, 0x80}; // PCI == 3
copy_msg_to_buffer(pdu, meas_report, sizeof(meas_report));
} else {
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x09, 0xBC, 0x80}; // PCI == 2
copy_msg_to_buffer(pdu, meas_report, sizeof(meas_report));
}
rrc.write_pdu(rnti, 1, std::move(pdu));
tic();
if (test_params.fail_at == mobility_test_params::test_fail_at::wrong_measreport) {
TESTASSERT(s1ap.last_ho_required.rrc_container == nullptr);
TESTASSERT(rrc_log.error_counter == 1);
return SRSLTE_SUCCESS;
}
// Check HO Required was sent to S1AP
TESTASSERT(s1ap.last_ho_required.rnti == rnti);
TESTASSERT(s1ap.last_ho_required.target_eci == cell2.eci);
TESTASSERT(s1ap.last_ho_required.target_plmn.to_string() == "00101");
{
asn1::bit_ref bref(s1ap.last_ho_required.rrc_container->msg, s1ap.last_ho_required.rrc_container->N_bytes);
asn1::rrc::ho_prep_info_s hoprep;
TESTASSERT(hoprep.unpack(bref) == asn1::SRSASN_SUCCESS);
ho_prep_info_r8_ies_s& hoprepr8 = hoprep.crit_exts.c1().ho_prep_info_r8();
TESTASSERT(hoprepr8.as_cfg_present);
// Check if RRC sends the current active bearers
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list_present);
TESTASSERT(hoprepr8.as_cfg.source_rr_cfg.drb_to_add_mod_list[0].drb_id == 1);
}
// MME returns back an HandoverCommand
// TODO
TESTASSERT(rrc_log.error_counter == 0);
return SRSLTE_SUCCESS;
}
int main()
int main(int argc, char** argv)
{
log_h.set_level(srslte::LOG_LEVEL_INFO);
if (argc < 3) {
argparse::usage(argv[0]);
return -1;
}
argparse::parse_args(argc, argv);
TESTASSERT(test_correct_insertion() == 0);
TESTASSERT(test_correct_meascfg_calculation() == 0);
TESTASSERT(test_mobility_class() == 0);
TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::never}) == 0);
TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::wrong_measreport}) == 0);
printf("Success\n");