added parser for rrc_cnfg section of rr.conf file, and dummy rrc_mobility class

master
Francisco Paisana 5 years ago
parent 2ec62f7fa9
commit 7e62d6d1f9

@ -4971,6 +4971,7 @@ LIBLTE_ERROR_ENUM liblte_s1ap_unpack_timetowait(uint8_t** ptr, LIBLTE_S1AP_TIMET
/*******************************************************************************
/* ProtocolIE UE_HistoryInformation DYNAMIC SEQUENCE OF
********************************************************************************/
#define LIBLTE_S1AP_UE_HISTORYINFORMATION_BIT_STRING_LEN 32 // FIXME: Check if this size is adequate
// lb:1, ub:16
typedef struct {
uint32_t len;

@ -22,17 +22,18 @@
#ifndef SRSENB_PARSER_H
#define SRSENB_PARSER_H
#include <stdarg.h>
#include <string>
#include "srslte/asn1/asn1_utils.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <libconfig.h++>
#include <list>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <typeinfo>
#include <libconfig.h++>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <string>
#include <typeinfo>
namespace srsenb {
@ -41,11 +42,10 @@ using namespace libconfig;
class parser
{
public:
class field_itf
{
public:
virtual ~field_itf(){}
virtual ~field_itf() = default;
virtual int parse(Setting& root) = 0;
virtual const char* get_name() = 0;
};
@ -303,10 +303,113 @@ public:
return r;
}
private:
std::list<section*> sections;
std::string filename;
};
template <typename T>
int parse_opt_field(T& obj, bool& flag, const char* field_name, Setting& root)
{
flag = root.lookupValue(field_name, obj);
return 0;
}
template <typename T, typename Parser>
int parse_opt_field(T& obj, bool& flag, const char* field_name, Setting& root, Parser field_parser)
{
flag = false;
if (root.exists(field_name)) {
flag = true;
return field_parser(obj, root[field_name]);
}
return 0;
}
namespace asn1_parsers {
template <class EnumType>
bool nowhitespace_string_to_enum(EnumType& e, const std::string& s)
{
std::string s_nows = s;
std::transform(s_nows.begin(), s_nows.end(), s_nows.begin(), ::tolower);
s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), ' '), s_nows.end());
s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), '-'), s_nows.end());
for (uint32_t i = 0; i < EnumType::nof_types; ++i) {
e = (typename EnumType::options)i;
std::string s_nows2 = e.to_string();
std::transform(s_nows2.begin(), s_nows2.end(), s_nows2.begin(), ::tolower);
s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), ' '), s_nows2.end());
s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), '-'), s_nows2.end());
if (s_nows2 == s_nows) {
return true;
}
}
return false;
}
template <class EnumType>
int str_to_enum(EnumType& enum_val, Setting& root)
{
std::string val = root;
bool found = nowhitespace_string_to_enum(enum_val, val);
if (not found) {
fprintf(stderr, "PARSER ERROR: Invalid option: \"%s\" for asn1 enum type\n", val.c_str());
fprintf(stderr, "Valid options: \"%s\"", EnumType((typename EnumType::options)0).to_string().c_str());
for (uint32_t i = 1; i < EnumType::nof_types; i++) {
fprintf(stderr, ", \"%s\"", EnumType((typename EnumType::options)i).to_string().c_str());
}
fprintf(stderr, "\n");
}
return found ? 0 : -1;
}
template <typename EnumType>
int opt_str_to_enum(EnumType& enum_val, bool& presence_flag, Setting& root, const char* name)
{
return parse_opt_field(enum_val, presence_flag, name, root, str_to_enum<EnumType>);
}
template <typename EnumType>
int number_to_enum(EnumType& enum_val, Setting& root)
{
if (root.isNumber()) {
typename EnumType::number_type val;
if (root.getType() == Setting::TypeInt64) {
val = (long int)root;
} else if (root.getType() == Setting::TypeInt) {
val = (int)root;
}
bool found = asn1::number_to_enum(enum_val, val);
if (not found) {
std::ostringstream ss;
ss << val;
fprintf(stderr, "Invalid option: %s for enum field \"%s\"\n", ss.str().c_str(), root.getName());
ss.str("");
ss << EnumType((typename EnumType::options)0).to_number();
fprintf(stderr, "Valid options: %s", ss.str().c_str());
for (uint32_t i = 1; i < EnumType::nof_types; i++) {
ss.str("");
ss << EnumType((typename EnumType::options)i).to_number();
fprintf(stderr, ", %s", ss.str().c_str());
}
fprintf(stderr, "\n");
}
return found ? 0 : -1;
} else {
std::string str_val = root;
fprintf(stderr, "Expected a number for enum field %s but received a string %s\n", root.getName(), str_val.c_str());
}
return -1;
}
template <typename EnumType>
int opt_number_to_enum(EnumType& enum_val, bool& presence_flag, Setting& root, const char* name)
{
return parse_opt_field(enum_val, presence_flag, name, root, number_to_enum<EnumType>);
}
} // namespace asn1_parsers
} // namespace srsenb
#endif // PARSER_H

@ -70,9 +70,28 @@ typedef struct {
asn1::rrc::rlc_cfg_c rlc_cfg;
} rrc_cfg_qci_t;
// structure used to parse the cfg file.
struct meas_cell_cfg_t {
uint32_t earfcn;
uint16_t pci;
uint32_t cell_id;
float q_offset;
};
// neigh measurement Cell info
struct rrc_meas_cfg_t {
std::vector<meas_cell_cfg_t> meas_cells;
std::vector<asn1::rrc::report_cfg_eutra_s> meas_reports;
asn1::rrc::quant_cfg_eutra_s quant_cfg;
// uint32_t nof_meas_ids;
// srslte::rrc_meas_id_t meas_ids[LIBLTE_RRC_MAX_MEAS_ID];
// FIXME: Add blacklist cells
// FIXME: Add multiple meas configs
};
#define MAX_NOF_QCI 10
typedef struct {
struct rrc_cfg_t {
asn1::rrc::sib_type1_s sib1;
asn1::rrc::sib_info_item_c sibs[ASN1_RRC_MAX_SIB];
asn1::rrc::mac_main_cfg_s mac_cnfg;
@ -86,18 +105,20 @@ typedef struct {
srslte_cell_t cell;
bool enable_mbsfn;
uint32_t inactivity_timeout_ms;
srslte::CIPHERING_ALGORITHM_ID_ENUM
eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS];
srslte::INTEGRITY_ALGORITHM_ID_ENUM
eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS];
} rrc_cfg_t;
srslte::CIPHERING_ALGORITHM_ID_ENUM eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS];
srslte::INTEGRITY_ALGORITHM_ID_ENUM eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS];
bool meas_cfg_present = false;
rrc_meas_cfg_t meas_cfg;
uint32_t pci; // TODO: add this to srslte_cell_t?
uint32_t dl_earfcn; // TODO: add this to srslte_cell_t?
};
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
"WAIT FOR CON SETUP COMPLETE",
"WAIT FOR SECURITY MODE COMPLETE",
"WAIT FOR UE CAPABILITIY INFORMATION",
"WAIT FOR CON RECONF COMPLETE",
"RRC CONNECTED"
"RRC CONNECTED",
"RELEASE REQUEST"};
class rrc : public rrc_interface_pdcp,
@ -107,27 +128,8 @@ class rrc : public rrc_interface_pdcp,
public thread
{
public:
rrc() : act_monitor(this), cnotifier(NULL), running(false), nof_si_messages(0), thread("RRC")
{
users.clear();
pending_paging.clear();
pool = NULL;
phy = NULL;
mac = NULL;
rlc = NULL;
pdcp = NULL;
gtpu = NULL;
s1ap = NULL;
rrc_log = NULL;
bzero(&sr_sched, sizeof(sr_sched));
bzero(&cqi_sched, sizeof(cqi_sched));
bzero(&cfg.sr_cfg, sizeof(cfg.sr_cfg));
bzero(&cfg.cqi_cfg, sizeof(cfg.cqi_cfg));
bzero(&cfg.qci_cfg, sizeof(cfg.qci_cfg));
bzero(&cfg.cell, sizeof(cfg.cell));
}
rrc();
~rrc();
void init(rrc_cfg_t* cfg,
phy_interface_stack_lte* phy,
@ -194,7 +196,9 @@ public:
class ue
{
public:
ue();
class rrc_mobility;
ue(rrc* outer_rrc = nullptr, uint16_t rnti = 0);
bool is_connected();
bool is_idle();
bool is_timeout();
@ -230,8 +234,10 @@ public:
bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT* e);
bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT* e);
void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos,
LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out,
void setup_erab(uint8_t id,
LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT* qos,
LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT* addr,
uint32_t teid_out,
LIBLTE_S1AP_NAS_PDU_STRUCT* nas_pdu);
bool release_erabs();
@ -262,10 +268,11 @@ public:
private:
srslte::byte_buffer_pool* pool;
struct timeval t_last_activity;
struct timeval t_ue_init;
asn1::rrc::establishment_cause_e establishment_cause;
std::unique_ptr<rrc_mobility> mobility_handler;
// S-TMSI for this UE
bool has_tmsi;
@ -386,6 +393,9 @@ private:
asn1::rrc::sib_type2_s sib2;
asn1::rrc::sib_type7_s sib7;
class mobility_cfg;
std::unique_ptr<mobility_cfg> enb_mobility_cfg;
void run_thread();
void rem_user_thread(uint16_t rnti);
pthread_mutex_t user_mutex;

@ -0,0 +1,53 @@
/*
* 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 SRSENB_RRC_MOBILITY_H
#define SRSENB_RRC_MOBILITY_H
#include "rrc.h"
#include <map>
namespace srsenb {
class rrc::mobility_cfg
{
public:
explicit mobility_cfg(rrc* outer_rrc);
private:
rrc* rrc_enb = nullptr;
};
class rrc::ue::rrc_mobility
{
public:
rrc_mobility(srsenb::rrc::ue* outer_ue);
private:
rrc::ue* rrc_ue;
rrc* rrc_enb;
rrc::mobility_cfg* cfg;
srslte::byte_buffer_pool* pool;
srslte::log* rrc_log;
};
} // namespace srsenb
#endif // SRSENB_RRC_MOBILITY_H

@ -196,6 +196,9 @@ int enb::parse_args(const all_args_t& args_)
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;

@ -21,9 +21,15 @@
#include "enb_cfg_parser.h"
#include "srsenb/hdr/cfg_parser.h"
#include "srslte/asn1/rrc_asn1_utils.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/srslte.h"
#include "srslte/asn1/rrc_asn1_utils.h"
#define HANDLEPARSERCODE(cond) \
if ((cond) != 0) { \
printf("[%d][%s()] Parser Error detected\n", __LINE__, __FUNCTION__); \
return -1; \
}
using namespace asn1::rrc;
@ -940,10 +946,16 @@ int enb::parse_rr(all_args_t* args, rrc_cfg_t* rrc_cfg)
cqi_report_cnfg.add_field(new parser::field<bool>("simultaneousAckCQI", &rrc_cfg->cqi_cfg.simultaneousAckCQI));
cqi_report_cnfg.add_field(new field_sf_mapping(rrc_cfg->cqi_cfg.sf_mapping, &rrc_cfg->cqi_cfg.nof_subframes));
/* RRC config section */
parser::section rrc_cnfg("rrc_cnfg");
rrc_cnfg.set_optional(&rrc_cfg->meas_cfg_present);
rrc_cnfg.add_field(new rr_sections::rrc_cnfg_section(&rrc_cfg->meas_cfg));
// Run parser with two sections
parser p(args->enb_files.rr_config);
p.add_section(&mac_cnfg);
p.add_section(&phy_cfg);
p.add_section(&rrc_cnfg);
return p.parse();
}
@ -1147,4 +1159,59 @@ int field_qci::parse(libconfig::Setting& root)
return 0;
}
namespace rr_sections {
static int parse_meas_cell_list(rrc_meas_cfg_t* meas_cfg, Setting& root)
{
meas_cfg->meas_cells.resize(root.getLength());
for (uint32_t i = 0; i < meas_cfg->meas_cells.size(); ++i) {
meas_cfg->meas_cells[i].earfcn = root[i]["dl_earfcn"];
meas_cfg->meas_cells[i].pci = (unsigned int)root[i]["pci"] % 504;
meas_cfg->meas_cells[i].cell_id = (unsigned int)root[i]["cell_idx"];
meas_cfg->meas_cells[i].q_offset = 0; // LIBLTE_RRC_Q_OFFSET_RANGE_DB_0; // TODO
// // FIXME: TEMP
// printf("PARSER: neighbor cell: {dl_earfcn=%d pci=%d cell_idx=0x%x}\n",
// meas_cfg->meas_cells[i].earfcn,
// meas_cfg->meas_cells[i].pci,
// meas_cfg->meas_cells[i].cell_id);
}
return 0;
}
static int parse_meas_report_desc(rrc_meas_cfg_t* meas_cfg, Setting& root)
{
// NOTE: For now, only support one meas_report for all cells.
// TODO: for a1
// TODO: for a2
// meas report parsing
meas_cfg->meas_reports.resize(1);
asn1::rrc::report_cfg_eutra_s& meas_item = meas_cfg->meas_reports[0];
HANDLEPARSERCODE(asn1_parsers::str_to_enum(meas_item.trigger_quant, root["a3_report_type"]));
auto& event = meas_item.trigger_type.set_event();
event.event_id.set_event_a3().report_on_leave = false;
event.event_id.event_a3().a3_offset = (int)root["a3_offset"];
event.hysteresis = (int)root["a3_hysteresis"];
meas_item.max_report_cells = 1; // TODO: parse
meas_item.report_amount.value = report_cfg_eutra_s::report_amount_e_::r1; // TODO: parse
meas_item.report_interv.value = report_interv_e::ms120; // TODO: parse
// quant coeff parsing
auto& quant = meas_cfg->quant_cfg;
HANDLEPARSERCODE(asn1_parsers::number_to_enum(event.time_to_trigger, root["a3_time_to_trigger"]));
HANDLEPARSERCODE(
asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrp, quant.filt_coef_rsrp_present, root, "rsrp_config"));
HANDLEPARSERCODE(
asn1_parsers::opt_number_to_enum(quant.filt_coef_rsrq, quant.filt_coef_rsrq_present, root, "rsrq_config"));
return 0;
}
int rrc_cnfg_section::parse(libconfig::Setting& root)
{
HANDLEPARSERCODE(parse_meas_cell_list(meas_cfg, root["meas_cell_list"]));
HANDLEPARSERCODE(parse_meas_report_desc(meas_cfg, root["meas_report_desc"]));
return 0;
}
} // namespace rr_sections
} // namespace srsenb

@ -113,15 +113,59 @@ class field_qci : public parser::field_itf
public:
field_qci(rrc_cfg_qci_t *cfg_) { cfg = cfg_; }
~field_qci(){}
const char* get_name() {
return "field_cqi";
}
const char* get_name() { return "field_cqi"; }
int parse(Setting& root);
private:
rrc_cfg_qci_t* cfg;
};
namespace rr_sections {
// rrc_cnfg
class rrc_cnfg_section final : public parser::field_itf
{
public:
explicit rrc_cnfg_section(rrc_meas_cfg_t* meas_cfg_) : meas_cfg(meas_cfg_) {}
int parse(Setting& root) override;
const char* get_name() override { return "meas_cell_list"; }
private:
rrc_meas_cfg_t* meas_cfg;
};
class field_meas_cell_list final : public parser::field_itf
{
public:
explicit field_meas_cell_list(rrc_meas_cfg_t* meas_cfg_) : meas_cfg(meas_cfg_) {}
int parse(Setting& root) override;
const char* get_name() override { return "meas_cell_list"; }
private:
rrc_meas_cfg_t* meas_cfg;
};
class field_meas_report_desc final : public parser::field_itf
{
public:
explicit field_meas_report_desc(rrc_meas_cfg_t* meas_cfg_) : meas_cfg(meas_cfg_) {}
int parse(Setting& root) override;
const char* get_name() override { return "meas_report_desc"; }
private:
rrc_meas_cfg_t* meas_cfg;
};
} // namespace rr_sections
// ASN1 parsers
class field_asn1 : public parser::field_itf
@ -275,32 +319,12 @@ bool parse_enum_by_number_str(EnumType& enum_val, const char* name, Setting& roo
return false;
}
template <class EnumType>
bool nowhitespace_string_to_enum(EnumType& e, const std::string& s)
{
std::string s_nows = s;
std::transform(s_nows.begin(), s_nows.end(), s_nows.begin(), ::tolower);
s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), ' '), s_nows.end());
s_nows.erase(std::remove(s_nows.begin(), s_nows.end(), '-'), s_nows.end());
for (uint32_t i = 0; i < EnumType::nof_types; ++i) {
e = (typename EnumType::options)i;
std::string s_nows2 = e.to_string();
std::transform(s_nows2.begin(), s_nows2.end(), s_nows2.begin(), ::tolower);
s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), ' '), s_nows2.end());
s_nows2.erase(std::remove(s_nows2.begin(), s_nows2.end(), '-'), s_nows2.end());
if (s_nows2 == s_nows) {
return true;
}
}
return false;
}
template <class EnumType>
bool parse_enum_by_str(EnumType& enum_val, const char* name, Setting& root)
{
std::string val;
if (root.lookupValue(name, val)) {
bool found = nowhitespace_string_to_enum(enum_val, val);
bool found = asn1_parsers::nowhitespace_string_to_enum(enum_val, val);
if (not found) {
fprintf(stderr, "PARSER ERROR: Invalid option: \"%s\" for field \"%s\"\n", val.c_str(), name);
fprintf(stderr, "Valid options: \"%s\"", EnumType((typename EnumType::options)0).to_string().c_str());

@ -18,7 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
set(SOURCES rrc.cc)
set(SOURCES rrc.cc rrc_mobility.cc)
add_library(srsenb_rrc STATIC ${SOURCES})

@ -20,6 +20,7 @@
*/
#include "srsenb/hdr/stack/rrc/rrc.h"
#include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srslte/asn1/asn1_utils.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/rrc_asn1_utils.h"
@ -37,6 +38,30 @@ using namespace asn1::rrc;
namespace srsenb {
rrc::rrc() : act_monitor(this), cnotifier(NULL), running(false), nof_si_messages(0), thread("RRC")
{
users.clear();
pending_paging.clear();
pool = NULL;
phy = NULL;
mac = NULL;
rlc = NULL;
pdcp = NULL;
gtpu = NULL;
s1ap = NULL;
rrc_log = NULL;
bzero(&sr_sched, sizeof(sr_sched));
bzero(&cqi_sched, sizeof(cqi_sched));
bzero(&cfg.sr_cfg, sizeof(cfg.sr_cfg));
bzero(&cfg.cqi_cfg, sizeof(cfg.cqi_cfg));
bzero(&cfg.qci_cfg, sizeof(cfg.qci_cfg));
bzero(&cfg.cell, sizeof(cfg.cell));
}
rrc::~rrc() {}
void rrc::init(rrc_cfg_t* cfg_,
phy_interface_stack_lte* phy_,
mac_interface_rrc* mac_,
@ -67,6 +92,7 @@ void rrc::init(rrc_cfg_t* cfg_,
nof_si_messages = generate_sibs();
config_mac();
enb_mobility_cfg.reset(new mobility_cfg(this));
pthread_mutex_init(&user_mutex, NULL);
pthread_mutex_init(&paging_mutex, NULL);
@ -1002,19 +1028,18 @@ void rrc::activity_monitor::run_thread()
}
}
/*******************************************************************************
UE class
Every function in UE class is called from a mutex environment thus does not
need extra protection.
*******************************************************************************/
rrc::ue::ue()
rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_) :
parent(outer_rrc),
rnti(rnti_),
pool(srslte::byte_buffer_pool::get_instance())
{
parent = NULL;
set_activity();
has_tmsi = false;
connect_notified = false;
@ -1035,7 +1060,8 @@ rrc::ue::ue()
nas_pending = false;
is_csfb = false;
state = RRC_STATE_IDLE;
pool = srslte::byte_buffer_pool::get_instance();
gettimeofday(&t_ue_init, NULL);
mobility_handler.reset(new rrc_mobility(this));
}
rrc_state_t rrc::ue::get_state()
@ -2119,7 +2145,10 @@ void rrc::ue::send_dl_dcch(dl_dcch_msg_s* dl_dcch_msg, srslte::unique_byte_buffe
}
if (pdu) {
asn1::bit_ref bref(pdu->msg, pdu->get_tailroom());
dl_dcch_msg->pack(bref);
if (dl_dcch_msg->pack(bref) == asn1::SRSASN_ERROR_ENCODE_FAIL) {
parent->rrc_log->error("Failed to encode DL-DCCH-Msg\n");
return;
}
pdu->N_bytes = 1u + (uint32_t)bref.distance_bytes(pdu->msg);
// send on SRB2 if user is fully registered (after RRC reconfig complete)

@ -0,0 +1,50 @@
/*
* 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/.
*
*/
#include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/common.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
namespace srsenb {
/*************************************************************************************************
* mobility_cfg class
************************************************************************************************/
rrc::mobility_cfg::mobility_cfg(rrc* outer_rrc) : rrc_enb(outer_rrc) {}
/*************************************************************************************************
* rrc_mobility class
************************************************************************************************/
rrc::ue::rrc_mobility::rrc_mobility(rrc::ue* outer_ue) :
rrc_ue(outer_ue),
rrc_enb(outer_ue->parent),
cfg(outer_ue->parent->enb_mobility_cfg.get()),
pool(outer_ue->pool),
rrc_log(outer_ue->parent->rrc_log)
{
}
} // namespace srsenb
Loading…
Cancel
Save