reorganized enb to mirror ue director/class structure with a stack class

master
Francisco Paisana 6 years ago committed by Andre Puschmann
parent d67d18cc6b
commit 415d3418b6

@ -37,7 +37,7 @@
namespace srsenb { namespace srsenb {
/* Interface PHY -> MAC */ /* Interface PHY -> MAC */
class mac_interface_phy class mac_interface_phy_lte
{ {
public: public:
const static int MAX_GRANTS = 64; const static int MAX_GRANTS = 64;
@ -98,7 +98,7 @@ public:
}; };
/* Interface MAC -> PHY */ /* Interface MAC -> PHY */
class phy_interface_mac class phy_interface_mac_lte
{ {
public: public:
@ -109,7 +109,7 @@ public:
}; };
/* Interface RRC -> PHY */ /* Interface RRC -> PHY */
class phy_interface_rrc class phy_interface_rrc_lte
{ {
public: public:
struct phy_cfg_mbsfn_t { struct phy_cfg_mbsfn_t {
@ -305,6 +305,32 @@ public:
virtual bool is_mme_connected() = 0; virtual bool is_mme_connected() = 0;
}; };
// Combined interface for PHY to access stack (MAC and RRC)
class stack_interface_phy_lte : public mac_interface_phy_lte
{
};
// Combined interface for stack (MAC and RRC) to access PHY
class phy_interface_stack_lte : public phy_interface_mac_lte, public phy_interface_rrc_lte
{
};
typedef struct {
uint32_t enb_id; // 20-bit id (lsb bits)
uint8_t cell_id; // 8-bit cell id
uint16_t tac; // 16-bit tac
uint16_t mcc; // BCD-coded with 0xF filler
uint16_t mnc; // BCD-coded with 0xF filler
std::string mme_addr;
std::string gtp_bind_addr;
std::string s1c_bind_addr;
std::string enb_name;
} s1ap_args_t;
typedef struct {
sched_interface::sched_args_t sched;
int link_failure_nof_err;
} mac_args_t;
} }
#endif // SRSLTE_ENB_INTERFACES_H #endif // SRSLTE_ENB_INTERFACES_H

@ -24,11 +24,11 @@
#include <stdint.h> #include <stdint.h>
#include "srsenb/hdr/mac/mac_metrics.h"
#include "srsenb/hdr/phy/phy_metrics.h" #include "srsenb/hdr/phy/phy_metrics.h"
#include "srsenb/hdr/upper/common_enb.h" #include "srsenb/hdr/stack/mac/mac_metrics.h"
#include "srsenb/hdr/upper/rrc_metrics.h" #include "srsenb/hdr/stack/rrc/rrc_metrics.h"
#include "srsenb/hdr/upper/s1ap_metrics.h" #include "srsenb/hdr/stack/upper/common_enb.h"
#include "srsenb/hdr/stack/upper/s1ap_metrics.h"
#include "srslte/common/metrics_hub.h" #include "srslte/common/metrics_hub.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include "srsue/hdr/stack/upper/gw_metrics.h" #include "srsue/hdr/stack/upper/gw_metrics.h"
@ -42,12 +42,16 @@ typedef struct {
bool rf_error; bool rf_error;
}rf_metrics_t; }rf_metrics_t;
typedef struct { struct stack_metrics_t {
rf_metrics_t rf;
phy_metrics_t phy[ENB_METRICS_MAX_USERS];
mac_metrics_t mac[ENB_METRICS_MAX_USERS]; mac_metrics_t mac[ENB_METRICS_MAX_USERS];
rrc_metrics_t rrc; rrc_metrics_t rrc;
s1ap_metrics_t s1ap; s1ap_metrics_t s1ap;
};
typedef struct {
rf_metrics_t rf;
phy_metrics_t phy[ENB_METRICS_MAX_USERS];
stack_metrics_t stack;
bool running; bool running;
}enb_metrics_t; }enb_metrics_t;

@ -47,11 +47,6 @@ typedef enum {
AUTH_SYNCH_FAILURE AUTH_SYNCH_FAILURE
} auth_result_t; } auth_result_t;
// UE interface
class ue_interface
{
};
// USIM interface for NAS // USIM interface for NAS
class usim_interface_nas class usim_interface_nas
{ {

@ -47,8 +47,7 @@ public:
virtual ~rlc(); virtual ~rlc();
void init(srsue::pdcp_interface_rlc* pdcp_, void init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsue::ue_interface* ue_, log* rlc_log_,
srslte::log* log_,
mac_interface_timers* mac_timers_, mac_interface_timers* mac_timers_,
uint32_t lcid_); uint32_t lcid_);
void stop(); void stop();
@ -95,7 +94,6 @@ private:
srsue::pdcp_interface_rlc *pdcp; srsue::pdcp_interface_rlc *pdcp;
srsue::rrc_interface_rlc *rrc; srsue::rrc_interface_rlc *rrc;
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
srsue::ue_interface *ue;
typedef std::map<uint16_t, rlc_common*> rlc_map_t; typedef std::map<uint16_t, rlc_common*> rlc_map_t;
typedef std::pair<uint16_t, rlc_common*> rlc_map_pair_t; typedef std::pair<uint16_t, rlc_common*> rlc_map_pair_t;

@ -80,7 +80,10 @@ void logger_file::run_thread() {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
while(buffer.empty()) { while(buffer.empty()) {
pthread_cond_wait(&not_empty, &mutex); pthread_cond_wait(&not_empty, &mutex);
if(!is_running) return; // Thread done. Messages in buffer will be handled in flush. if (!is_running) {
pthread_mutex_unlock(&mutex);
return; // Thread done. Messages in buffer will be handled in flush.
}
} }
str_ptr s = buffer.front(); str_ptr s = buffer.front();
int n = 0; int n = 0;

@ -35,7 +35,6 @@ rlc::rlc()
pdcp = NULL; pdcp = NULL;
rrc = NULL; rrc = NULL;
mac_timers = NULL; mac_timers = NULL;
ue = NULL;
bzero(metrics_time, sizeof(metrics_time)); bzero(metrics_time, sizeof(metrics_time));
pthread_rwlock_init(&rwlock, NULL); pthread_rwlock_init(&rwlock, NULL);
} }
@ -60,14 +59,12 @@ rlc::~rlc()
void rlc::init(srsue::pdcp_interface_rlc* pdcp_, void rlc::init(srsue::pdcp_interface_rlc* pdcp_,
srsue::rrc_interface_rlc* rrc_, srsue::rrc_interface_rlc* rrc_,
srsue::ue_interface* ue_,
log* rlc_log_, log* rlc_log_,
mac_interface_timers* mac_timers_, mac_interface_timers* mac_timers_,
uint32_t lcid_) uint32_t lcid_)
{ {
pdcp = pdcp_; pdcp = pdcp_;
rrc = rrc_; rrc = rrc_;
ue = ue_;
rlc_log = rlc_log_; rlc_log = rlc_log_;
mac_timers = mac_timers_; mac_timers = mac_timers_;
default_lcid = lcid_; default_lcid = lcid_;

@ -343,10 +343,9 @@ void stress_test(stress_test_args_t args)
rlc_tester tester1(&rlc1, "tester1", args, lcid); rlc_tester tester1(&rlc1, "tester1", args, lcid);
rlc_tester tester2(&rlc2, "tester2", args, lcid); rlc_tester tester2(&rlc2, "tester2", args, lcid);
mac_dummy mac(&rlc1, &rlc2, args, lcid, &stack, &pcap); mac_dummy mac(&rlc1, &rlc2, args, lcid, &stack, &pcap);
ue_interface ue;
rlc1.init(&tester1, &tester1, &ue, &log1, &stack, 0); rlc1.init(&tester1, &tester1, &log1, &stack, 0);
rlc2.init(&tester2, &tester2, &ue, &log2, &stack, 0); rlc2.init(&tester2, &tester2, &log2, &stack, 0);
// only add AM and UM bearers // only add AM and UM bearers
if (args.mode != "TM") { if (args.mode != "TM") {

@ -33,24 +33,20 @@
#include <pthread.h> #include <pthread.h>
#include "phy/phy.h" #include "phy/phy.h"
#include "mac/mac.h" #include "srsenb/hdr/stack/rrc/rrc.h"
#include "upper/rrc.h"
#include "upper/gtpu.h"
#include "upper/s1ap.h"
#include "upper/rlc.h"
#include "upper/pdcp.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include "srslte/common/security.h" #include "srsenb/hdr/stack/enb_stack_base.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
#include "srslte/interfaces/sched_interface.h" #include "srslte/common/security.h"
#include "srslte/interfaces/enb_metrics_interface.h" #include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/interfaces/sched_interface.h"
#include "srslte/interfaces/ue_interfaces.h"
namespace srsenb { namespace srsenb {
@ -58,20 +54,20 @@ namespace srsenb {
eNodeB Parameters eNodeB Parameters
*******************************************************************************/ *******************************************************************************/
typedef struct { struct enb_args_t {
s1ap_args_t s1ap; s1ap_args_t s1ap;
uint32_t n_prb; uint32_t n_prb;
uint32_t pci; uint32_t pci;
uint32_t nof_ports; uint32_t nof_ports;
uint32_t transmission_mode; uint32_t transmission_mode;
float p_a; float p_a;
}enb_args_t; };
typedef struct { struct enb_files_t {
std::string sib_config; std::string sib_config;
std::string rr_config; std::string rr_config;
std::string drb_config; std::string drb_config;
} enb_files_t; };
typedef struct { typedef struct {
uint32_t dl_earfcn; uint32_t dl_earfcn;
@ -113,11 +109,11 @@ typedef struct {
std::string filename; std::string filename;
}log_args_t; }log_args_t;
typedef struct { struct gui_args_t {
bool enable; bool enable;
}gui_args_t; };
typedef struct { struct expert_args_t {
phy_args_t phy; phy_args_t phy;
mac_args_t mac; mac_args_t mac;
uint32_t rrc_inactivity_timer; uint32_t rrc_inactivity_timer;
@ -130,9 +126,9 @@ typedef struct {
std::string m1u_if_addr; std::string m1u_if_addr;
std::string eia_pref_list; std::string eia_pref_list;
std::string eea_pref_list; std::string eea_pref_list;
}expert_args_t; };
typedef struct { struct all_args_t {
enb_args_t enb; enb_args_t enb;
enb_files_t enb_files; enb_files_t enb_files;
rf_args_t rf; rf_args_t rf;
@ -140,14 +136,14 @@ typedef struct {
log_args_t log; log_args_t log;
gui_args_t gui; gui_args_t gui;
expert_args_t expert; expert_args_t expert;
}all_args_t; };
/******************************************************************************* /*******************************************************************************
Main eNB class Main eNB class
*******************************************************************************/ *******************************************************************************/
class enb class enb : public enb_metrics_interface
:public enb_metrics_interface { {
public: public:
static enb *get_instance(void); static enb *get_instance(void);
@ -178,15 +174,9 @@ private:
virtual ~enb(); virtual ~enb();
std::unique_ptr<enb_stack_base> stack;
srslte::radio radio; srslte::radio radio;
srsenb::phy phy; srsenb::phy phy;
srsenb::mac mac;
srslte::mac_pcap mac_pcap;
srsenb::rlc rlc;
srsenb::pdcp pdcp;
srsenb::rrc rrc;
srsenb::gtpu gtpu;
srsenb::s1ap s1ap;
srslte::logger_stdout logger_stdout; srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file; srslte::logger_file logger_file;
@ -194,12 +184,6 @@ private:
srslte::log_filter rf_log; srslte::log_filter rf_log;
std::vector<srslte::log_filter*> phy_log; std::vector<srslte::log_filter*> phy_log;
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter gtpu_log;
srslte::log_filter s1ap_log;
srslte::log_filter pool_log; srslte::log_filter pool_log;
srslte::byte_buffer_pool *pool; srslte::byte_buffer_pool *pool;
@ -218,8 +202,8 @@ private:
int parse_sib9(std::string filename, asn1::rrc::sib_type9_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_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_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_rr(all_args_t* args, rrc_cfg_t* rrc_cfg);
int parse_drb(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); 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);

@ -43,14 +43,21 @@ typedef struct {
asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg; asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg;
} phy_cfg_t; } phy_cfg_t;
class phy : public phy_interface_mac, class phy : public phy_interface_stack_lte
public phy_interface_rrc
{ {
public: public:
phy(); phy();
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log_filter* log_h); bool init(phy_args_t* args,
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, std::vector<srslte::log_filter *> log_vec); phy_cfg_t* common_cfg,
srslte::radio* radio_handler,
stack_interface_phy_lte* stack,
srslte::log_filter* log_h);
bool init(phy_args_t* args,
phy_cfg_t* common_cfg,
srslte::radio* radio_handler,
stack_interface_phy_lte* stack,
std::vector<srslte::log_filter*> log_vec);
void stop(); void stop();
/* MAC->PHY interface */ /* MAC->PHY interface */

@ -54,7 +54,7 @@ public:
void set_nof_workers(uint32_t nof_workers); void set_nof_workers(uint32_t nof_workers);
bool init(srslte_cell_t *cell, srslte::radio *radio_handler, mac_interface_phy *mac); bool init(srslte_cell_t* cell, srslte::radio* radio_handler, stack_interface_phy_lte* mac);
void reset(); void reset();
void stop(); void stop();
@ -71,11 +71,11 @@ public:
srslte_dl_cfg_t dl_cfg_com; srslte_dl_cfg_t dl_cfg_com;
srslte::radio *radio; srslte::radio *radio;
mac_interface_phy *mac; stack_interface_phy_lte* stack;
// Common objects for schedulign grants // Common objects for schedulign grants
mac_interface_phy::ul_sched_t ul_grants[TTIMOD_SZ]; stack_interface_phy_lte::ul_sched_t ul_grants[TTIMOD_SZ];
mac_interface_phy::dl_sched_t dl_grants[TTIMOD_SZ]; stack_interface_phy_lte::dl_sched_t dl_grants[TTIMOD_SZ];
// Map of pending ACKs for each user // Map of pending ACKs for each user
typedef struct { typedef struct {
@ -103,7 +103,7 @@ public:
void ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb); void ue_db_set_last_ul_tb(uint16_t rnti, uint32_t pid, srslte_ra_tb_t tb);
srslte_ra_tb_t ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid); srslte_ra_tb_t ue_db_get_last_ul_tb(uint16_t rnti, uint32_t pid);
void configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t *cfg); void configure_mbsfn(phy_interface_stack_lte::phy_cfg_mbsfn_t* cfg);
void build_mch_table(); void build_mch_table();
void build_mcch_table(); void build_mcch_table();
bool is_mbsfn_sf(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti); bool is_mbsfn_sf(srslte_mbsfn_cfg_t* cfg, uint32_t phy_tti);
@ -122,7 +122,7 @@ private:
bool have_mtch_stop; bool have_mtch_stop;
pthread_mutex_t mtch_mutex; pthread_mutex_t mtch_mutex;
pthread_cond_t mtch_cvar; pthread_cond_t mtch_cvar;
phy_interface_rrc::phy_cfg_mbsfn_t mbsfn; phy_interface_stack_lte::phy_cfg_mbsfn_t mbsfn;
bool sib13_configured; bool sib13_configured;
bool mcch_configured; bool mcch_configured;
uint8_t mch_table[40]; uint8_t mch_table[40];

@ -44,7 +44,7 @@ public:
thread("PRACH_WORKER") thread("PRACH_WORKER")
{ {
log_h = NULL; log_h = NULL;
mac = NULL; stack = NULL;
bzero(&prach, sizeof(srslte_prach_t)); bzero(&prach, sizeof(srslte_prach_t));
bzero(&prach_indices, sizeof(prach_indices)); bzero(&prach_indices, sizeof(prach_indices));
bzero(&prach_offsets, sizeof(prach_offsets)); bzero(&prach_offsets, sizeof(prach_offsets));
@ -53,7 +53,11 @@ public:
bzero(&prach_cfg, sizeof(prach_cfg)); bzero(&prach_cfg, sizeof(prach_cfg));
} }
int init(srslte_cell_t *cell, srslte_prach_cfg_t *prach_cfg, mac_interface_phy *mac, srslte::log *log_h, int priority); int init(srslte_cell_t* cell,
srslte_prach_cfg_t* prach_cfg,
stack_interface_phy_lte* mac,
srslte::log* log_h,
int priority);
int new_tti(uint32_t tti, cf_t *buffer); int new_tti(uint32_t tti, cf_t *buffer);
void set_max_prach_offset_us(float delay_us); void set_max_prach_offset_us(float delay_us);
void stop(); void stop();
@ -93,7 +97,7 @@ private:
sf_buffer* current_buffer; sf_buffer* current_buffer;
srslte::log* log_h; srslte::log* log_h;
mac_interface_phy *mac; stack_interface_phy_lte* stack;
float max_prach_offset_us; float max_prach_offset_us;
bool initiated; bool initiated;
bool running; bool running;

@ -63,12 +63,12 @@ private:
void work_imp(); void work_imp();
int encode_pdsch(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants); int encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, uint32_t nof_grants);
int encode_pmch(mac_interface_phy::dl_sched_grant_t* grant, srslte_mbsfn_cfg_t* mbsfn_cfg); int encode_pmch(stack_interface_phy_lte::dl_sched_grant_t* grant, srslte_mbsfn_cfg_t* mbsfn_cfg);
int decode_pusch(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_pusch); int decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_pusch);
int encode_phich(mac_interface_phy::ul_sched_ack_t* acks, uint32_t nof_acks); int encode_phich(stack_interface_phy_lte::ul_sched_ack_t* acks, uint32_t nof_acks);
int encode_pdcch_dl(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants); int encode_pdcch_dl(stack_interface_phy_lte::dl_sched_grant_t* grants, uint32_t nof_grants);
int encode_pdcch_ul(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_grants); int encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_grants);
int decode_pucch(); int decode_pucch();
void send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value); void send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value);

@ -0,0 +1,46 @@
/*
* 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_ENB_STACK_BASE_H
#define SRSLTE_ENB_STACK_BASE_H
#include <string>
namespace srsenb {
struct stack_metrics_t;
class enb_stack_base
{
public:
virtual ~enb_stack_base() = default;
virtual std::string get_type() = 0;
virtual void stop() = 0;
// eNB metrics interface
virtual bool get_metrics(stack_metrics_t* metrics) = 0;
};
} // namespace srsenb
#endif // SRSLTE_ENB_STACK_BASE_H

@ -0,0 +1,130 @@
/*
* 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/.
*
*/
/******************************************************************************
* File: enb_stack_lte.h
* Description: L2/L3 LTE eNB stack class.
*****************************************************************************/
#ifndef SRSLTE_ENB_STACK_LTE_H
#define SRSLTE_ENB_STACK_LTE_H
#include "mac/mac.h"
#include "rrc/rrc.h"
#include "upper/gtpu.h"
#include "upper/pdcp.h"
#include "upper/rlc.h"
#include "upper/s1ap.h"
#include "srslte/common/log_filter.h"
#include "enb_stack_base.h"
#include "srsenb/hdr/enb.h"
#include "srslte/interfaces/enb_interfaces.h"
namespace srsenb {
class enb_stack_lte final : public enb_stack_base, public stack_interface_phy_lte
{
public:
struct args_t {
struct stack_expert_args_t {
mac_args_t mac;
bool enable_mbsfn;
std::string m1u_multiaddr;
std::string m1u_if_addr;
};
enb_args_t enb;
pcap_args_t pcap;
log_args_t log;
stack_expert_args_t expert;
};
enb_stack_lte();
~enb_stack_lte() final;
// eNB stack base interface
int init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::logger* logger_, phy_interface_stack_lte* phy_);
int init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::logger* logger_);
void stop() final;
std::string get_type() final;
bool get_metrics(stack_metrics_t* metrics) final;
/* PHY-MAC interface */
int sr_detected(uint32_t tti, uint16_t rnti) final { return mac.sr_detected(tti, rnti); }
int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) final
{
return mac.rach_detected(tti, preamble_idx, time_adv);
}
int ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) final { return mac.ri_info(tti, rnti, ri_value); }
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) final { return mac.pmi_info(tti, rnti, pmi_value); }
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) final { return mac.cqi_info(tti, rnti, cqi_value); }
int snr_info(uint32_t tti, uint16_t rnti, float snr_db) final { return mac.snr_info(tti, rnti, snr_db); }
int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) final
{
return mac.ack_info(tti, rnti, tb_idx, ack);
}
int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) final
{
return mac.crc_info(tti, rnti, nof_bytes, crc_res);
}
int get_dl_sched(uint32_t tti, dl_sched_t* dl_sched_res) final { return mac.get_dl_sched(tti, dl_sched_res); }
int get_mch_sched(uint32_t tti, bool is_mcch, dl_sched_t* dl_sched_res) final
{
return mac.get_mch_sched(tti, is_mcch, dl_sched_res);
}
int get_ul_sched(uint32_t tti, ul_sched_t* ul_sched_res) final { return mac.get_ul_sched(tti, ul_sched_res); }
// Radio-Link status
void rl_failure(uint16_t rnti) final { mac.rl_failure(rnti); }
void rl_ok(uint16_t rnti) final { mac.rl_ok(rnti); }
void tti_clock() final { mac.tti_clock(); }
private:
args_t args;
rrc_cfg_t rrc_cfg;
bool started;
srsenb::mac mac;
srslte::mac_pcap mac_pcap;
srsenb::rlc rlc;
srsenb::pdcp pdcp;
srsenb::rrc rrc;
srsenb::gtpu gtpu;
srsenb::s1ap s1ap;
srslte::logger* logger;
// Radio and PHY log are in enb.cc
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter s1ap_log;
srslte::log_filter gtpu_log;
// RAT-specific interfaces
phy_interface_stack_lte* phy;
};
} // namespace srsenb
#endif // SRSLTE_ENB_STACK_LTE_H

@ -44,13 +44,7 @@ public:
virtual bool process_pdus() = 0; virtual bool process_pdus() = 0;
}; };
typedef struct { class mac : public mac_interface_phy_lte,
sched_interface::sched_args_t sched;
int link_failure_nof_err;
} mac_args_t;
class mac
:public mac_interface_phy,
public mac_interface_rlc, public mac_interface_rlc,
public mac_interface_rrc, public mac_interface_rrc,
public srslte::mac_interface_timers, public srslte::mac_interface_timers,
@ -59,14 +53,19 @@ class mac
public: public:
mac(); mac();
~mac(); ~mac();
bool init(mac_args_t *args, srslte_cell_t *cell, phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h); bool init(const mac_args_t& args_,
srslte_cell_t* cell,
phy_interface_stack_lte* phy,
rlc_interface_mac* rlc,
rrc_interface_mac* rrc,
srslte::log* log_h);
void stop(); void stop();
void start_pcap(srslte::mac_pcap* pcap_); void start_pcap(srslte::mac_pcap* pcap_);
/******** Interface from PHY (PHY -> MAC) ****************/ /******** Interface from PHY (PHY -> MAC) ****************/
int sr_detected(uint32_t tti, uint16_t rnti); int sr_detected(uint32_t tti, uint16_t rnti) final;
int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv); int rach_detected(uint32_t tti, uint32_t preamble_idx, uint32_t time_adv) final;
int set_dl_ant_info(uint16_t rnti, asn1::rrc::phys_cfg_ded_s::ant_info_c_* dl_ant_info); int set_dl_ant_info(uint16_t rnti, asn1::rrc::phys_cfg_ded_s::ant_info_c_* dl_ant_info);
@ -125,10 +124,10 @@ private:
pthread_rwlock_t rwlock; pthread_rwlock_t rwlock;
// Interaction with PHY // Interaction with PHY
phy_interface_mac *phy_h; phy_interface_stack_lte* phy_h;
rlc_interface_mac *rlc_h; rlc_interface_mac* rlc_h;
rrc_interface_mac *rrc_h; rrc_interface_mac* rrc_h;
srslte::log *log_h; srslte::log* log_h;
srslte_cell_t cell; srslte_cell_t cell;
mac_args_t args; mac_args_t args;

@ -22,9 +22,9 @@
#ifndef SRSENB_SCHEDULER_H #ifndef SRSENB_SCHEDULER_H
#define SRSENB_SCHEDULER_H #define SRSENB_SCHEDULER_H
#include "scheduler_grid.h"
#include "scheduler_harq.h" #include "scheduler_harq.h"
#include "scheduler_ue.h" #include "scheduler_ue.h"
#include "srsenb/hdr/mac/scheduler_grid.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/sched_interface.h" #include "srslte/interfaces/sched_interface.h"

@ -23,7 +23,7 @@
#define SRSLTE_SCHEDULER_GRID_H #define SRSLTE_SCHEDULER_GRID_H
#include "lib/include/srslte/interfaces/sched_interface.h" #include "lib/include/srslte/interfaces/sched_interface.h"
#include "srsenb/hdr/mac/scheduler_ue.h" #include "scheduler_ue.h"
#include "srslte/common/bounded_bitset.h" #include "srslte/common/bounded_bitset.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include <vector> #include <vector>

@ -22,8 +22,8 @@
#ifndef SRSENB_RRC_H #ifndef SRSENB_RRC_H
#define SRSENB_RRC_H #define SRSENB_RRC_H
#include "common_enb.h"
#include "rrc_metrics.h" #include "rrc_metrics.h"
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srslte/asn1/rrc_asn1.h" #include "srslte/asn1/rrc_asn1.h"
#include "srslte/common/block_queue.h" #include "srslte/common/block_queue.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
@ -128,14 +128,14 @@ public:
bzero(&cfg.cell, sizeof(cfg.cell)); bzero(&cfg.cell, sizeof(cfg.cell));
} }
void init(rrc_cfg_t *cfg, void init(rrc_cfg_t* cfg,
phy_interface_rrc *phy, phy_interface_stack_lte* phy,
mac_interface_rrc *mac, mac_interface_rrc* mac,
rlc_interface_rrc *rlc, rlc_interface_rrc* rlc,
pdcp_interface_rrc *pdcp, pdcp_interface_rrc* pdcp,
s1ap_interface_rrc *s1ap, s1ap_interface_rrc* s1ap,
gtpu_interface_rrc *gtpu, gtpu_interface_rrc* gtpu,
srslte::log *log_rrc); srslte::log* log_rrc);
void stop(); void stop();
void get_metrics(rrc_metrics_t &m); void get_metrics(rrc_metrics_t &m);
@ -343,7 +343,7 @@ private:
srslte::byte_buffer_pool* pool; srslte::byte_buffer_pool* pool;
srslte::byte_buffer_t byte_buf_paging; srslte::byte_buffer_t byte_buf_paging;
phy_interface_rrc* phy; phy_interface_stack_lte* phy;
mac_interface_rrc* mac; mac_interface_rrc* mac;
rlc_interface_rrc* rlc; rlc_interface_rrc* rlc;
pdcp_interface_rrc* pdcp; pdcp_interface_rrc* pdcp;

@ -22,7 +22,7 @@
#ifndef SRSENB_RRC_METRICS_H #ifndef SRSENB_RRC_METRICS_H
#define SRSENB_RRC_METRICS_H #define SRSENB_RRC_METRICS_H
#include "common_enb.h" #include "srsenb/hdr/stack/upper/common_enb.h"
namespace srsenb { namespace srsenb {

@ -66,10 +66,7 @@ public:
void read_pdu_pcch(uint8_t *payload, uint32_t buffer_size); void read_pdu_pcch(uint8_t *payload, uint32_t buffer_size);
private: private:
class user_interface : public srsue::pdcp_interface_rlc, public srsue::rrc_interface_rlc
class user_interface : public srsue::pdcp_interface_rlc,
public srsue::rrc_interface_rlc,
public srsue::ue_interface
{ {
public: public:
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu); void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu);
@ -83,12 +80,10 @@ private:
srsenb::pdcp_interface_rlc *pdcp; srsenb::pdcp_interface_rlc *pdcp;
srsenb::rrc_interface_rlc *rrc; srsenb::rrc_interface_rlc *rrc;
srslte::rlc *rlc; std::unique_ptr<srslte::rlc> rlc;
srsenb::rlc *parent; srsenb::rlc *parent;
}; };
void clear_user(user_interface *ue);
pthread_rwlock_t rwlock; pthread_rwlock_t rwlock;
std::map<uint32_t,user_interface> users; std::map<uint32_t,user_interface> users;

@ -36,18 +36,6 @@
namespace srsenb { namespace srsenb {
typedef struct {
uint32_t enb_id; // 20-bit id (lsb bits)
uint8_t cell_id; // 8-bit cell id
uint16_t tac; // 16-bit tac
uint16_t mcc; // BCD-coded with 0xF filler
uint16_t mnc; // BCD-coded with 0xF filler
std::string mme_addr;
std::string gtp_bind_addr;
std::string s1c_bind_addr;
std::string enb_name;
}s1ap_args_t;
typedef struct { typedef struct {
uint32_t rnti; uint32_t rnti;
uint32_t eNB_UE_S1AP_ID; uint32_t eNB_UE_S1AP_ID;

@ -19,8 +19,7 @@
# #
add_subdirectory(phy) add_subdirectory(phy)
add_subdirectory(mac) add_subdirectory(stack)
add_subdirectory(upper)
# Link libstdc++ and libgcc # Link libstdc++ and libgcc
@ -35,9 +34,11 @@ endif (RPATH)
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 parser.cc enb_cfg_parser.cc metrics_stdout.cc metrics_csv.cc)
target_link_libraries(srsenb srsenb_upper target_link_libraries(srsenb srsenb_phy
srsenb_stack
srsenb_upper
srsenb_mac srsenb_mac
srsenb_phy srsenb_rrc
srslte_common srslte_common
srslte_phy srslte_phy
srslte_upper srslte_upper
@ -53,8 +54,6 @@ if (RPATH)
set_target_properties(srsenb PROPERTIES INSTALL_RPATH ".") set_target_properties(srsenb PROPERTIES INSTALL_RPATH ".")
endif (RPATH) endif (RPATH)
install(TARGETS srsenb DESTINATION ${RUNTIME_DIR})
######################################################################## ########################################################################
# Option to run command after build (useful for remote builds) # Option to run command after build (useful for remote builds)
######################################################################## ########################################################################

@ -19,9 +19,10 @@
* *
*/ */
#include <boost/algorithm/string.hpp>
#include "srsenb/hdr/enb.h" #include "srsenb/hdr/enb.h"
#include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srslte/build_info.h" #include "srslte/build_info.h"
#include <boost/algorithm/string.hpp>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -94,12 +95,6 @@ bool enb::init(all_args_t *args_)
mylog->init(tmp, logger, true); mylog->init(tmp, logger, true);
phy_log.push_back(mylog); phy_log.push_back(mylog);
} }
mac_log.init("MAC ", logger, true);
rlc_log.init("RLC ", logger);
pdcp_log.init("PDCP", logger);
rrc_log.init("RRC ", logger);
gtpu_log.init("GTPU", logger);
s1ap_log.init("S1AP", logger);
pool_log.init("POOL", logger); pool_log.init("POOL", logger);
pool_log.set_level(srslte::LOG_LEVEL_ERROR); pool_log.set_level(srslte::LOG_LEVEL_ERROR);
@ -110,22 +105,10 @@ bool enb::init(all_args_t *args_)
for (int i=0;i<args->expert.phy.nof_phy_threads;i++) { for (int i=0;i<args->expert.phy.nof_phy_threads;i++) {
((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level));
} }
mac_log.set_level(level(args->log.mac_level));
rlc_log.set_level(level(args->log.rlc_level));
pdcp_log.set_level(level(args->log.pdcp_level));
rrc_log.set_level(level(args->log.rrc_level));
gtpu_log.set_level(level(args->log.gtpu_level));
s1ap_log.set_level(level(args->log.s1ap_level));
for (int i=0;i<args->expert.phy.nof_phy_threads;i++) { for (int i=0;i<args->expert.phy.nof_phy_threads;i++) {
((srslte::log_filter*) phy_log[i])->set_hex_limit(args->log.phy_hex_limit); ((srslte::log_filter*) phy_log[i])->set_hex_limit(args->log.phy_hex_limit);
} }
mac_log.set_hex_limit(args->log.mac_hex_limit);
rlc_log.set_hex_limit(args->log.rlc_hex_limit);
pdcp_log.set_hex_limit(args->log.pdcp_hex_limit);
rrc_log.set_hex_limit(args->log.rrc_hex_limit);
gtpu_log.set_hex_limit(args->log.gtpu_hex_limit);
s1ap_log.set_hex_limit(args->log.s1ap_hex_limit);
// Parse config files // Parse config files
srslte_cell_t cell_cfg; srslte_cell_t cell_cfg;
@ -155,42 +138,14 @@ bool enb::init(all_args_t *args_)
phy_cfg.pdsch_cnfg.p_b = 1; // Default TM2,3,4 phy_cfg.pdsch_cnfg.p_b = 1; // Default TM2,3,4
} }
uint32_t prach_freq_offset = rrc_cfg.sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset;
if (cell_cfg.nof_prb > 10) {
uint32_t lower_bound = SRSLTE_MAX(rrc_cfg.sr_cfg.nof_prb, rrc_cfg.cqi_cfg.nof_prb);
uint32_t upper_bound = cell_cfg.nof_prb - lower_bound;
if (prach_freq_offset + 6 > upper_bound or prach_freq_offset < lower_bound) {
fprintf(stderr,
"ERROR: Invalid PRACH configuration - prach_freq_offset=%d collides with PUCCH.\n",
prach_freq_offset);
fprintf(stderr,
" Consider changing \"prach_freq_offset\" in sib.conf to a value between %d and %d.\n",
lower_bound,
upper_bound);
return false;
}
} else { // 6 PRB case
if (prach_freq_offset + 6 > cell_cfg.nof_prb) {
fprintf(stderr,
"ERROR: Invalid PRACH configuration - prach=(%d, %d) does not fit into the eNB PRBs=(0, %d).\n",
prach_freq_offset,
prach_freq_offset + 6,
cell_cfg.nof_prb);
fprintf(
stderr,
" Consider changing the \"prach_freq_offset\" value to 0 in the sib.conf file when using 6 PRBs.\n");
return false;
}
}
rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer; rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer;
rrc_cfg.enable_mbsfn = args->expert.enable_mbsfn; rrc_cfg.enable_mbsfn = args->expert.enable_mbsfn;
// Check number of control symbols // Check number of control symbols
if (cell_cfg.nof_prb < 50 && args->expert.mac.sched.nof_ctrl_symbols != 3) { if (cell_cfg.nof_prb < 50 && args->expert.mac.sched.nof_ctrl_symbols != 3) {
args->expert.mac.sched.nof_ctrl_symbols = 3; args->expert.mac.sched.nof_ctrl_symbols = 3;
mac_log.info("Setting number of control symbols to %d for %d PRB cell.\n", fprintf(stdout,
"Setting number of control symbols to %d for %d PRB cell.\n",
args->expert.mac.sched.nof_ctrl_symbols, args->expert.mac.sched.nof_ctrl_symbols,
cell_cfg.nof_prb); cell_cfg.nof_prb);
} }
@ -245,13 +200,6 @@ bool enb::init(all_args_t *args_)
memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t)); memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t));
memcpy(&phy_cfg.cell, &cell_cfg, sizeof(srslte_cell_t)); memcpy(&phy_cfg.cell, &cell_cfg, sizeof(srslte_cell_t));
// Set up pcap and trace
if(args->pcap.enable)
{
mac_pcap.open(args->pcap.filename.c_str());
mac.start_pcap(&mac_pcap);
}
// Init layers // Init layers
/* Start Radio */ /* Start Radio */
@ -288,14 +236,23 @@ bool enb::init(all_args_t *args_)
radio.register_error_handler(rf_msg); radio.register_error_handler(rf_msg);
// Setup Stack Args
enb_stack_lte::args_t stack_args;
stack_args.enb = args->enb;
stack_args.expert.mac = args->expert.mac;
stack_args.expert.enable_mbsfn = args->expert.enable_mbsfn;
stack_args.expert.m1u_if_addr = args->expert.m1u_if_addr;
stack_args.expert.m1u_multiaddr = args->expert.m1u_multiaddr;
stack_args.log = args->log;
stack_args.pcap = args->pcap;
// Init all layers // Init all layers
phy.init(&args->expert.phy, &phy_cfg, &radio, &mac, phy_log); std::unique_ptr<enb_stack_lte> lte_stack(new enb_stack_lte());
mac.init(&args->expert.mac, &cell_cfg, &phy, &rlc, &rrc, &mac_log); phy.init(&args->expert.phy, &phy_cfg, &radio, lte_stack.get(), phy_log);
rlc.init(&pdcp, &rrc, &mac, &mac, &rlc_log); if (lte_stack->init(stack_args, rrc_cfg, logger, &phy) != SRSLTE_SUCCESS) {
pdcp.init(&rlc, &rrc, &gtpu, &pdcp_log); return false;
rrc.init(&rrc_cfg, &phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &rrc_log); }
s1ap.init(args->enb.s1ap, &rrc, &s1ap_log); stack = std::move(lte_stack);
gtpu.init(args->enb.s1ap.gtp_bind_addr, args->enb.s1ap.mme_addr, args->expert.m1u_multiaddr, args->expert.m1u_if_addr, &pdcp, &gtpu_log, args->expert.enable_mbsfn);
started = true; started = true;
return true; return true;
@ -305,21 +262,8 @@ void enb::stop()
{ {
if(started) if(started)
{ {
s1ap.stop();
gtpu.stop();
phy.stop(); phy.stop();
mac.stop(); stack->stop();
usleep(50000);
rlc.stop();
pdcp.stop();
rrc.stop();
usleep(10000);
if(args->pcap.enable)
{
mac_pcap.close();
}
radio.stop(); radio.stop();
started = false; started = false;
} }
@ -340,9 +284,7 @@ bool enb::get_metrics(enb_metrics_t* m)
rf_metrics.rf_error = false; // Reset error flag rf_metrics.rf_error = false; // Reset error flag
phy.get_metrics(m->phy); phy.get_metrics(m->phy);
mac.get_metrics(m->mac); stack->get_metrics(&m->stack);
rrc.get_metrics(m->rrc);
s1ap.get_metrics(m->s1ap);
m->running = started; m->running = started;
return true; return true;

@ -30,7 +30,7 @@
#include <iostream> #include <iostream>
#include "srsenb/hdr/parser.h" #include "srsenb/hdr/parser.h"
#include "srsenb/hdr/upper/rrc.h" #include "srsenb/hdr/stack/rrc/rrc.h"
#include "srslte/asn1/asn1_utils.h" #include "srslte/asn1/asn1_utils.h"
namespace srsenb { namespace srsenb {

@ -73,13 +73,13 @@ void metrics_csv::set_metrics(enb_metrics_t &metrics, const uint32_t period_usec
file << (metrics_report_period*n_reports) << ";"; file << (metrics_report_period*n_reports) << ";";
// UEs // UEs
file << (metrics.rrc.n_ues) << ";"; file << (metrics.stack.rrc.n_ues) << ";";
// Sum up rates for all UEs // Sum up rates for all UEs
float dl_rate_sum = 0.0, ul_rate_sum = 0.0; float dl_rate_sum = 0.0, ul_rate_sum = 0.0;
for (int i = 0; i < metrics.rrc.n_ues; i++) { for (int i = 0; i < metrics.stack.rrc.n_ues; i++) {
dl_rate_sum += metrics.mac[i].tx_brate; dl_rate_sum += metrics.stack.mac[i].tx_brate;
ul_rate_sum += metrics.mac[i].rx_brate; ul_rate_sum += metrics.stack.mac[i].rx_brate;
} }
// DL rate // DL rate

@ -62,7 +62,7 @@ void metrics_stdout::toggle_print(bool b)
void metrics_stdout::set_metrics(enb_metrics_t &metrics, const uint32_t period_usec) void metrics_stdout::set_metrics(enb_metrics_t &metrics, const uint32_t period_usec)
{ {
if (!do_print || enb == NULL || metrics.rrc.n_ues == 0) { if (!do_print || enb == NULL || metrics.stack.rrc.n_ues == 0) {
return; return;
} }
@ -75,29 +75,30 @@ void metrics_stdout::set_metrics(enb_metrics_t &metrics, const uint32_t period_u
cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl; cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl;
} }
for (int i = 0; i < metrics.rrc.n_ues; i++) { for (int i = 0; i < metrics.stack.rrc.n_ues; i++) {
if (metrics.mac[i].tx_errors > metrics.mac[i].tx_pkts) { if (metrics.stack.mac[i].tx_errors > metrics.stack.mac[i].tx_pkts) {
printf("tx caution errors %d > %d\n", metrics.mac[i].tx_errors, metrics.mac[i].tx_pkts); printf("tx caution errors %d > %d\n", metrics.stack.mac[i].tx_errors, metrics.stack.mac[i].tx_pkts);
} }
if (metrics.mac[i].rx_errors > metrics.mac[i].rx_pkts) { if (metrics.stack.mac[i].rx_errors > metrics.stack.mac[i].rx_pkts) {
printf("rx caution errors %d > %d\n", metrics.mac[i].rx_errors, metrics.mac[i].rx_pkts); printf("rx caution errors %d > %d\n", metrics.stack.mac[i].rx_errors, metrics.stack.mac[i].rx_pkts);
} }
cout << std::hex << metrics.mac[i].rnti << " "; cout << std::hex << metrics.stack.mac[i].rnti << " ";
cout << float_to_string(SRSLTE_MAX(0.1, metrics.mac[i].dl_cqi), 2); cout << float_to_string(SRSLTE_MAX(0.1, metrics.stack.mac[i].dl_cqi), 2);
cout << float_to_string(metrics.mac[i].dl_ri, 1); cout << float_to_string(metrics.stack.mac[i].dl_ri, 1);
if (not isnan(metrics.phy[i].dl.mcs)) { if (not isnan(metrics.phy[i].dl.mcs)) {
cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].dl.mcs), 2); cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].dl.mcs), 2);
} else { } else {
cout << float_to_string(0, 2); cout << float_to_string(0, 2);
} }
if (metrics.mac[i].tx_brate > 0) { if (metrics.stack.mac[i].tx_brate > 0) {
cout << float_to_eng_string(SRSLTE_MAX(0.1, (float)metrics.mac[i].tx_brate / period_usec * 1e6), 2); cout << float_to_eng_string(SRSLTE_MAX(0.1, (float)metrics.stack.mac[i].tx_brate / period_usec * 1e6), 2);
} else { } else {
cout << float_to_string(0, 2) << ""; cout << float_to_string(0, 2) << "";
} }
if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) { if (metrics.stack.mac[i].tx_pkts > 0 && metrics.stack.mac[i].tx_errors) {
cout << float_to_string(SRSLTE_MAX(0.1, (float)100 * metrics.mac[i].tx_errors / metrics.mac[i].tx_pkts), 1) cout << float_to_string(
SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].tx_errors / metrics.stack.mac[i].tx_pkts), 1)
<< "%"; << "%";
} else { } else {
cout << float_to_string(0, 1) << "%"; cout << float_to_string(0, 1) << "%";
@ -107,24 +108,25 @@ void metrics_stdout::set_metrics(enb_metrics_t &metrics, const uint32_t period_u
} else { } else {
cout << float_to_string(0, 2); cout << float_to_string(0, 2);
} }
cout << float_to_string(metrics.mac[i].phr, 2); cout << float_to_string(metrics.stack.mac[i].phr, 2);
if (not isnan(metrics.phy[i].ul.mcs)) { if (not isnan(metrics.phy[i].ul.mcs)) {
cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.mcs), 2); cout << float_to_string(SRSLTE_MAX(0.1, metrics.phy[i].ul.mcs), 2);
} else { } else {
cout << float_to_string(0, 2); cout << float_to_string(0, 2);
} }
if (metrics.mac[i].rx_brate > 0) { if (metrics.stack.mac[i].rx_brate > 0) {
cout << float_to_eng_string(SRSLTE_MAX(0.1, (float)metrics.mac[i].rx_brate / period_usec * 1e6), 2); cout << float_to_eng_string(SRSLTE_MAX(0.1, (float)metrics.stack.mac[i].rx_brate / period_usec * 1e6), 2);
} else { } else {
cout << float_to_string(0, 2) << ""; cout << float_to_string(0, 2) << "";
} }
if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) { if (metrics.stack.mac[i].rx_pkts > 0 && metrics.stack.mac[i].rx_errors > 0) {
cout << float_to_string(SRSLTE_MAX(0.1, (float)100 * metrics.mac[i].rx_errors / metrics.mac[i].rx_pkts), 1) cout << float_to_string(
SRSLTE_MAX(0.1, (float)100 * metrics.stack.mac[i].rx_errors / metrics.stack.mac[i].rx_pkts), 1)
<< "%"; << "%";
} else { } else {
cout << float_to_string(0, 1) << "%"; cout << float_to_string(0, 1) << "%";
} }
cout << float_to_eng_string(metrics.mac[i].ul_buffer, 2); cout << float_to_eng_string(metrics.stack.mac[i].ul_buffer, 2);
cout << endl; cout << endl;
} }

@ -98,10 +98,10 @@ void phy::parse_config(phy_cfg_t* cfg)
workers_common.dl_cfg_com.pdsch.meas_time_en = true; workers_common.dl_cfg_com.pdsch.meas_time_en = true;
} }
bool phy::init(phy_args_t *args, bool phy::init(phy_args_t* args,
phy_cfg_t *cfg, phy_cfg_t* cfg,
srslte::radio* radio_handler_, srslte::radio* radio_handler_,
mac_interface_phy *mac, stack_interface_phy_lte* stack_,
srslte::log_filter* log_h) srslte::log_filter* log_h)
{ {
@ -110,14 +110,14 @@ bool phy::init(phy_args_t *args,
for (int i=0;i<args->nof_phy_threads;i++) { for (int i=0;i<args->nof_phy_threads;i++) {
log_vec.push_back(log_h); log_vec.push_back(log_h);
} }
init(args, cfg, radio_handler_, mac, log_vec); init(args, cfg, radio_handler_, stack_, log_vec);
return true; return true;
} }
bool phy::init(phy_args_t *args, bool phy::init(phy_args_t* args,
phy_cfg_t *cfg, phy_cfg_t* cfg,
srslte::radio* radio_handler_, srslte::radio* radio_handler_,
mac_interface_phy *mac, stack_interface_phy_lte* stack_,
std::vector<srslte::log_filter*> log_vec) std::vector<srslte::log_filter*> log_vec)
{ {
@ -128,7 +128,7 @@ bool phy::init(phy_args_t *args,
this->log_h = (srslte::log*)log_vec[0]; this->log_h = (srslte::log*)log_vec[0];
workers_common.params = *args; workers_common.params = *args;
workers_common.init(&cfg->cell, radio_handler, mac); workers_common.init(&cfg->cell, radio_handler, stack_);
parse_config(cfg); parse_config(cfg);
@ -138,7 +138,7 @@ bool phy::init(phy_args_t *args,
workers_pool.init_worker(i, &workers[i], WORKERS_THREAD_PRIO); workers_pool.init_worker(i, &workers[i], WORKERS_THREAD_PRIO);
} }
prach.init(&cfg->cell, &prach_cfg, mac, (srslte::log*) log_vec[0], PRACH_WORKER_THREAD_PRIO); prach.init(&cfg->cell, &prach_cfg, stack_, (srslte::log*)log_vec[0], PRACH_WORKER_THREAD_PRIO);
prach.set_max_prach_offset_us(args->max_prach_offset_us); prach.set_max_prach_offset_us(args->max_prach_offset_us);
// Warning this must be initialized after all workers have been added to the pool // Warning this must be initialized after all workers have been added to the pool

@ -42,7 +42,7 @@ phy_common::phy_common(uint32_t max_workers) : tx_sem(max_workers)
this->nof_workers = nof_workers; this->nof_workers = nof_workers;
params.max_prach_offset_us = 20; params.max_prach_offset_us = 20;
radio = NULL; radio = NULL;
mac = NULL; stack = NULL;
is_first_tx = false; is_first_tx = false;
is_first_of_burst = false; is_first_of_burst = false;
have_mtch_stop = false; have_mtch_stop = false;
@ -71,14 +71,14 @@ void phy_common::set_nof_workers(uint32_t nof_workers)
void phy_common::reset() void phy_common::reset()
{ {
bzero(ul_grants, sizeof(mac_interface_phy::ul_sched_t)*TTIMOD_SZ); bzero(ul_grants, sizeof(stack_interface_phy_lte::ul_sched_t) * TTIMOD_SZ);
bzero(dl_grants, sizeof(mac_interface_phy::dl_sched_t)*TTIMOD_SZ); bzero(dl_grants, sizeof(stack_interface_phy_lte::dl_sched_t) * TTIMOD_SZ);
} }
bool phy_common::init(srslte_cell_t* cell_, srslte::radio* radio_h_, mac_interface_phy* mac_) bool phy_common::init(srslte_cell_t* cell_, srslte::radio* radio_h_, stack_interface_phy_lte* stack_)
{ {
radio = radio_h_; radio = radio_h_;
mac = mac_; stack = stack_;
memcpy(&cell, cell_, sizeof(srslte_cell_t)); memcpy(&cell, cell_, sizeof(srslte_cell_t));
pthread_mutex_init(&user_mutex, NULL); pthread_mutex_init(&user_mutex, NULL);
@ -129,7 +129,7 @@ void phy_common::worker_end(uint32_t tti,
sem_post(&tx_sem[(tti+1)%nof_workers]); sem_post(&tx_sem[(tti+1)%nof_workers]);
// Trigger MAC clock // Trigger MAC clock
mac->tti_clock(); stack->tti_clock();
} }
void phy_common::ue_db_clear(uint32_t tti) void phy_common::ue_db_clear(uint32_t tti)
@ -246,7 +246,7 @@ void phy_common::set_mch_period_stop(uint32_t stop)
pthread_mutex_unlock(&mtch_mutex); pthread_mutex_unlock(&mtch_mutex);
} }
void phy_common::configure_mbsfn(phy_interface_rrc::phy_cfg_mbsfn_t* cfg) void phy_common::configure_mbsfn(phy_interface_stack_lte::phy_cfg_mbsfn_t* cfg)
{ {
mbsfn = *cfg; mbsfn = *cfg;

@ -24,10 +24,14 @@
namespace srsenb { namespace srsenb {
int prach_worker::init(srslte_cell_t *cell_, srslte_prach_cfg_t *prach_cfg_, mac_interface_phy* mac_, srslte::log* log_h_, int priority) int prach_worker::init(srslte_cell_t* cell_,
srslte_prach_cfg_t* prach_cfg_,
stack_interface_phy_lte* stack_,
srslte::log* log_h_,
int priority)
{ {
log_h = log_h_; log_h = log_h_;
mac = mac_; stack = stack_;
memcpy(&prach_cfg, prach_cfg_, sizeof(srslte_prach_cfg_t)); memcpy(&prach_cfg, prach_cfg_, sizeof(srslte_prach_cfg_t));
memcpy(&cell, cell_, sizeof(srslte_cell_t)); memcpy(&cell, cell_, sizeof(srslte_cell_t));
@ -127,7 +131,7 @@ int prach_worker::run_tti(sf_buffer *b)
i, prach_nof_det, prach_indices[i], prach_offsets[i]*1e6, prach_p2avg[i], max_prach_offset_us); i, prach_nof_det, prach_indices[i], prach_offsets[i]*1e6, prach_p2avg[i], max_prach_offset_us);
if (prach_offsets[i]*1e6 < max_prach_offset_us) { if (prach_offsets[i]*1e6 < max_prach_offset_us) {
mac->rach_detected(b->tti, prach_indices[i], (uint32_t) (prach_offsets[i]*1e6)); stack->rach_detected(b->tti, prach_indices[i], (uint32_t)(prach_offsets[i] * 1e6));
} }
} }
} }

@ -362,9 +362,9 @@ void sf_worker::work_imp()
srslte_mbsfn_cfg_t mbsfn_cfg; srslte_mbsfn_cfg_t mbsfn_cfg;
srslte_sf_t sf_type = phy->is_mbsfn_sf(&mbsfn_cfg, tti_tx_dl) ? SRSLTE_SF_MBSFN : SRSLTE_SF_NORM; srslte_sf_t sf_type = phy->is_mbsfn_sf(&mbsfn_cfg, tti_tx_dl) ? SRSLTE_SF_MBSFN : SRSLTE_SF_NORM;
mac_interface_phy::ul_sched_t* ul_grants = phy->ul_grants; stack_interface_phy_lte::ul_sched_t* ul_grants = phy->ul_grants;
mac_interface_phy::dl_sched_t* dl_grants = phy->dl_grants; stack_interface_phy_lte::dl_sched_t* dl_grants = phy->dl_grants;
mac_interface_phy* mac = phy->mac; stack_interface_phy_lte* stack = phy->stack;
log_h->step(tti_rx); log_h->step(tti_rx);
@ -391,13 +391,13 @@ void sf_worker::work_imp()
// Get DL scheduling for the TX TTI from MAC // Get DL scheduling for the TX TTI from MAC
if (sf_type == SRSLTE_SF_NORM) { if (sf_type == SRSLTE_SF_NORM) {
if (mac->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) { if (stack->get_dl_sched(tti_tx_dl, &dl_grants[t_tx_dl]) < 0) {
Error("Getting DL scheduling from MAC\n"); Error("Getting DL scheduling from MAC\n");
goto unlock; goto unlock;
} }
} else { } else {
dl_grants[t_tx_dl].cfi = mbsfn_cfg.non_mbsfn_region_length; dl_grants[t_tx_dl].cfi = mbsfn_cfg.non_mbsfn_region_length;
if (mac->get_mch_sched(tti_tx_dl, mbsfn_cfg.is_mcch, &dl_grants[t_tx_dl])) { if (stack->get_mch_sched(tti_tx_dl, mbsfn_cfg.is_mcch, &dl_grants[t_tx_dl])) {
Error("Getting MCH packets from MAC\n"); Error("Getting MCH packets from MAC\n");
goto unlock; goto unlock;
} }
@ -409,7 +409,7 @@ void sf_worker::work_imp()
} }
// Get UL scheduling for the TX TTI from MAC // Get UL scheduling for the TX TTI from MAC
if (mac->get_ul_sched(tti_tx_ul, &ul_grants[t_tx_ul]) < 0) { if (stack->get_ul_sched(tti_tx_ul, &ul_grants[t_tx_ul]) < 0) {
Error("Getting UL scheduling from MAC\n"); Error("Getting UL scheduling from MAC\n");
goto unlock; goto unlock;
} }
@ -513,7 +513,7 @@ void sf_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
{ {
// Notify SR // Notify SR
if (uci_cfg->is_scheduling_request_tti && uci_value->scheduling_request) { if (uci_cfg->is_scheduling_request_tti && uci_value->scheduling_request) {
phy->mac->sr_detected(tti_rx, rnti); phy->stack->sr_detected(tti_rx, rnti);
} }
/* If only one ACK is required, it can be for TB0 or TB1 */ /* If only one ACK is required, it can be for TB0 or TB1 */
@ -522,7 +522,7 @@ void sf_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
if (uci_cfg->ack.pending_tb[tb]) { if (uci_cfg->ack.pending_tb[tb]) {
bool ack = uci_value->ack.ack_value[ack_idx]; bool ack = uci_value->ack.ack_value[ack_idx];
bool valid = uci_value->ack.valid; bool valid = uci_value->ack.valid;
phy->mac->ack_info(tti_rx, rnti, tb, ack && valid); phy->stack->ack_info(tti_rx, rnti, tb, ack && valid);
ack_idx++; ack_idx++;
} }
} }
@ -545,10 +545,10 @@ void sf_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
cqi_value = uci_value->cqi.subband_ue.wideband_cqi; cqi_value = uci_value->cqi.subband_ue.wideband_cqi;
break; break;
} }
phy->mac->cqi_info(tti_rx, rnti, cqi_value); phy->stack->cqi_info(tti_rx, rnti, cqi_value);
} }
if (uci_cfg->cqi.ri_len) { if (uci_cfg->cqi.ri_len) {
phy->mac->ri_info(tti_rx, rnti, uci_value->ri); phy->stack->ri_info(tti_rx, rnti, uci_value->ri);
phy->ue_db_set_ri(rnti, uci_value->ri); phy->ue_db_set_ri(rnti, uci_value->ri);
} }
if (uci_cfg->cqi.pmi_present) { if (uci_cfg->cqi.pmi_present) {
@ -564,12 +564,12 @@ void sf_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
Error("CQI type=%d not implemented for PMI\n", uci_cfg->cqi.type); Error("CQI type=%d not implemented for PMI\n", uci_cfg->cqi.type);
break; break;
} }
phy->mac->pmi_info(tti_rx, rnti, pmi_value); phy->stack->pmi_info(tti_rx, rnti, pmi_value);
} }
} }
} }
int sf_worker::decode_pusch(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_pusch) int sf_worker::decode_pusch(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_pusch)
{ {
srslte_pusch_res_t pusch_res; srslte_pusch_res_t pusch_res;
@ -614,20 +614,20 @@ int sf_worker::decode_pusch(mac_interface_phy::ul_sched_grant_t* grants, uint32_
// Notify MAC of RL status // Notify MAC of RL status
if (snr_db >= PUSCH_RL_SNR_DB_TH) { if (snr_db >= PUSCH_RL_SNR_DB_TH) {
phy->mac->snr_info(tti_rx, rnti, snr_db); phy->stack->snr_info(tti_rx, rnti, snr_db);
if (grants[i].dci.tb.rv == 0) { if (grants[i].dci.tb.rv == 0) {
if (!pusch_res.crc) { if (!pusch_res.crc) {
Debug("PUSCH: Radio-Link failure snr=%.1f dB\n", snr_db); Debug("PUSCH: Radio-Link failure snr=%.1f dB\n", snr_db);
phy->mac->rl_failure(rnti); phy->stack->rl_failure(rnti);
} else { } else {
phy->mac->rl_ok(rnti); phy->stack->rl_ok(rnti);
} }
} }
} }
// Notify MAC new received data and HARQ Indication value // Notify MAC new received data and HARQ Indication value
phy->mac->crc_info(tti_rx, rnti, grant->tb.tbs / 8, pusch_res.crc); phy->stack->crc_info(tti_rx, rnti, grant->tb.tbs / 8, pusch_res.crc);
// Send UCI data to MAC // Send UCI data to MAC
send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pusch.uci_cfg, &pusch_res.uci); send_uci_data(rnti, &ue_db[rnti]->ul_cfg.pusch.uci_cfg, &pusch_res.uci);
@ -666,9 +666,9 @@ int sf_worker::decode_pucch()
if (!ue_db[rnti]->ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) { if (!ue_db[rnti]->ul_cfg.pucch.uci_cfg.is_scheduling_request_tti) {
if (pucch_res.correlation < PUCCH_RL_CORR_TH) { if (pucch_res.correlation < PUCCH_RL_CORR_TH) {
Debug("PUCCH: Radio-Link failure corr=%.1f\n", pucch_res.correlation); Debug("PUCCH: Radio-Link failure corr=%.1f\n", pucch_res.correlation);
phy->mac->rl_failure(rnti); phy->stack->rl_failure(rnti);
} else { } else {
phy->mac->rl_ok(rnti); phy->stack->rl_ok(rnti);
} }
} }
@ -685,7 +685,7 @@ int sf_worker::decode_pucch()
return 0; return 0;
} }
int sf_worker::encode_phich(mac_interface_phy::ul_sched_ack_t* acks, uint32_t nof_acks) int sf_worker::encode_phich(stack_interface_phy_lte::ul_sched_ack_t* acks, uint32_t nof_acks)
{ {
for (uint32_t i = 0; i < nof_acks; i++) { for (uint32_t i = 0; i < nof_acks; i++) {
if (acks[i].rnti && ue_db.count(acks[i].rnti)) { if (acks[i].rnti && ue_db.count(acks[i].rnti)) {
@ -702,7 +702,7 @@ int sf_worker::encode_phich(mac_interface_phy::ul_sched_ack_t* acks, uint32_t no
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int sf_worker::encode_pdcch_ul(mac_interface_phy::ul_sched_grant_t* grants, uint32_t nof_grants) int sf_worker::encode_pdcch_ul(stack_interface_phy_lte::ul_sched_grant_t* grants, uint32_t nof_grants)
{ {
for (uint32_t i = 0; i < nof_grants; i++) { for (uint32_t i = 0; i < nof_grants; i++) {
if (grants[i].needs_pdcch) { if (grants[i].needs_pdcch) {
@ -720,7 +720,7 @@ int sf_worker::encode_pdcch_ul(mac_interface_phy::ul_sched_grant_t* grants, uint
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int sf_worker::encode_pdcch_dl(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants) int sf_worker::encode_pdcch_dl(stack_interface_phy_lte::dl_sched_grant_t* grants, uint32_t nof_grants)
{ {
for (uint32_t i = 0; i < nof_grants; i++) { for (uint32_t i = 0; i < nof_grants; i++) {
uint16_t rnti = grants[i].dci.rnti; uint16_t rnti = grants[i].dci.rnti;
@ -741,7 +741,7 @@ int sf_worker::encode_pdcch_dl(mac_interface_phy::dl_sched_grant_t* grants, uint
return 0; return 0;
} }
int sf_worker::encode_pmch(mac_interface_phy::dl_sched_grant_t* grant, srslte_mbsfn_cfg_t* mbsfn_cfg) int sf_worker::encode_pmch(stack_interface_phy_lte::dl_sched_grant_t* grant, srslte_mbsfn_cfg_t* mbsfn_cfg)
{ {
srslte_pmch_cfg_t pmch_cfg; srslte_pmch_cfg_t pmch_cfg;
ZERO_OBJECT(pmch_cfg); ZERO_OBJECT(pmch_cfg);
@ -765,7 +765,7 @@ int sf_worker::encode_pmch(mac_interface_phy::dl_sched_grant_t* grant, srslte_mb
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int sf_worker::encode_pdsch(mac_interface_phy::dl_sched_grant_t* grants, uint32_t nof_grants) int sf_worker::encode_pdsch(stack_interface_phy_lte::dl_sched_grant_t* grants, uint32_t nof_grants)
{ {
/* Scales the Resources Elements affected by the power allocation (p_b) */ /* Scales the Resources Elements affected by the power allocation (p_b) */

@ -0,0 +1,31 @@
#
# 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/.
#
add_subdirectory(mac)
add_subdirectory(rrc)
add_subdirectory(upper)
set(SOURCES enb_stack_lte.cc)
add_library(srsenb_stack STATIC ${SOURCES})
target_link_libraries(srsenb_stack)
install(TARGETS srsenb_stack DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,166 @@
/*
* 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/enb_stack_lte.h"
#include "srsenb/hdr/enb.h"
#include "srslte/srslte.h"
#include <srslte/interfaces/enb_metrics_interface.h>
using namespace srslte;
namespace srsenb {
enb_stack_lte::enb_stack_lte() : args(), started(false), logger(nullptr), phy(nullptr) {}
enb_stack_lte::~enb_stack_lte()
{
stop();
}
std::string enb_stack_lte::get_type()
{
return "lte";
}
int enb_stack_lte::init(const args_t& args_,
const rrc_cfg_t& rrc_cfg_,
srslte::logger* logger_,
phy_interface_stack_lte* phy_)
{
phy = phy_;
if (init(args_, rrc_cfg_, logger_)) {
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int enb_stack_lte::init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::logger* logger_)
{
args = args_;
rrc_cfg = rrc_cfg_;
logger = logger_;
// setup logging for each layer
mac_log.init("MAC ", logger, true);
rlc_log.init("RLC ", logger);
pdcp_log.init("PDCP", logger);
rrc_log.init("RRC ", logger);
gtpu_log.init("GTPU", logger);
s1ap_log.init("S1AP", logger);
// Init logs
mac_log.set_level(args.log.mac_level);
rlc_log.set_level(args.log.rlc_level);
pdcp_log.set_level(args.log.pdcp_level);
rrc_log.set_level(args.log.rrc_level);
gtpu_log.set_level(args.log.gtpu_level);
s1ap_log.set_level(args.log.s1ap_level);
mac_log.set_hex_limit(args.log.mac_hex_limit);
rlc_log.set_hex_limit(args.log.rlc_hex_limit);
pdcp_log.set_hex_limit(args.log.pdcp_hex_limit);
rrc_log.set_hex_limit(args.log.rrc_hex_limit);
gtpu_log.set_hex_limit(args.log.gtpu_hex_limit);
s1ap_log.set_hex_limit(args.log.s1ap_hex_limit);
// Set up pcap and trace
if (args.pcap.enable) {
mac_pcap.open(args.pcap.filename.c_str());
mac.start_pcap(&mac_pcap);
}
// verify configuration correctness
uint32_t prach_freq_offset = rrc_cfg.sibs[1].sib2().rr_cfg_common.prach_cfg.prach_cfg_info.prach_freq_offset;
srslte_cell_t& cell_cfg = rrc_cfg.cell;
if (cell_cfg.nof_prb > 10) {
uint32_t lower_bound = SRSLTE_MAX(rrc_cfg.sr_cfg.nof_prb, rrc_cfg.cqi_cfg.nof_prb);
uint32_t upper_bound = cell_cfg.nof_prb - lower_bound;
if (prach_freq_offset + 6 > upper_bound or prach_freq_offset < lower_bound) {
fprintf(stderr,
"ERROR: Invalid PRACH configuration - prach_freq_offset=%d collides with PUCCH.\n",
prach_freq_offset);
fprintf(stderr,
" Consider changing \"prach_freq_offset\" in sib.conf to a value between %d and %d.\n",
lower_bound,
upper_bound);
return false;
}
} else { // 6 PRB case
if (prach_freq_offset + 6 > cell_cfg.nof_prb) {
fprintf(stderr,
"ERROR: Invalid PRACH configuration - prach=(%d, %d) does not fit into the eNB PRBs=(0, %d).\n",
prach_freq_offset,
prach_freq_offset + 6,
cell_cfg.nof_prb);
fprintf(
stderr,
" Consider changing the \"prach_freq_offset\" value to 0 in the sib.conf file when using 6 PRBs.\n");
return false;
}
}
// Init all layers
mac.init(args.expert.mac, &cell_cfg, phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, &mac, &mac, &rlc_log);
pdcp.init(&rlc, &rrc, &gtpu, &pdcp_log);
rrc.init(&rrc_cfg, phy, &mac, &rlc, &pdcp, &s1ap, &gtpu, &rrc_log);
s1ap.init(args.enb.s1ap, &rrc, &s1ap_log);
gtpu.init(args.enb.s1ap.gtp_bind_addr,
args.enb.s1ap.mme_addr,
args.expert.m1u_multiaddr,
args.expert.m1u_if_addr,
&pdcp,
&gtpu_log,
args.expert.enable_mbsfn);
started = true;
return SRSLTE_SUCCESS;
}
void enb_stack_lte::stop()
{
if (started) {
s1ap.stop();
gtpu.stop();
mac.stop();
usleep(50000);
rlc.stop();
pdcp.stop();
rrc.stop();
usleep(10000);
if (args.pcap.enable) {
mac_pcap.close();
}
started = false;
}
}
bool enb_stack_lte::get_metrics(stack_metrics_t* metrics)
{
mac.get_metrics(metrics->mac);
rrc.get_metrics(metrics->rrc);
s1ap.get_metrics(metrics->s1ap);
return true;
}
} // namespace srsenb

@ -30,8 +30,8 @@
#include <unistd.h> #include <unistd.h>
#include <srslte/interfaces/sched_interface.h> #include <srslte/interfaces/sched_interface.h>
#include "srsenb/hdr/stack/mac/mac.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srsenb/hdr/mac/mac.h"
//#define WRITE_SIB_PCAP //#define WRITE_SIB_PCAP
using namespace asn1::rrc; using namespace asn1::rrc;
@ -67,18 +67,23 @@ mac::~mac()
pthread_rwlock_destroy(&rwlock); pthread_rwlock_destroy(&rwlock);
} }
bool mac::init(mac_args_t *args_, srslte_cell_t *cell_, phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_) bool mac::init(const mac_args_t& args_,
srslte_cell_t* cell_,
phy_interface_stack_lte* phy,
rlc_interface_mac* rlc,
rrc_interface_mac* rrc,
srslte::log* log_h_)
{ {
started = false; started = false;
if (cell_ && phy && rlc && log_h_ && args_) { if (cell_ && phy && rlc && log_h_) {
phy_h = phy; phy_h = phy;
rlc_h = rlc; rlc_h = rlc;
rrc_h = rrc; rrc_h = rrc;
log_h = log_h_; log_h = log_h_;
memcpy(&args, args_, sizeof(mac_args_t)); args = args_;
memcpy(&cell, cell_, sizeof(srslte_cell_t)); cell = *cell_;
scheduler.init(rrc, log_h); scheduler.init(rrc, log_h);
// Set default scheduler (RR) // Set default scheduler (RR)

@ -19,12 +19,12 @@
* *
*/ */
#include <srsenb/hdr/mac/scheduler_ue.h> #include <srsenb/hdr/stack/mac/scheduler_ue.h>
#include <string.h> #include <string.h>
#include "srslte/srslte.h" #include "srsenb/hdr/stack/mac/scheduler.h"
#include "srslte/common/pdu.h" #include "srslte/common/pdu.h"
#include "srsenb/hdr/mac/scheduler.h" #include "srslte/srslte.h"
#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) #define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)

@ -19,8 +19,8 @@
* *
*/ */
#include "srsenb/hdr/mac/scheduler_grid.h" #include "srsenb/hdr/stack/mac/scheduler_grid.h"
#include "srsenb/hdr/mac/scheduler.h" #include "srsenb/hdr/stack/mac/scheduler.h"
#include <srslte/interfaces/sched_interface.h> #include <srslte/interfaces/sched_interface.h>
namespace srsenb { namespace srsenb {

@ -21,9 +21,9 @@
#include <string.h> #include <string.h>
#include "srslte/srslte.h" #include "srsenb/hdr/stack/mac/scheduler.h"
#include "srslte/common/pdu.h" #include "srslte/common/pdu.h"
#include "srsenb/hdr/mac/scheduler.h" #include "srslte/srslte.h"
#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) #define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)

@ -19,9 +19,9 @@
* *
*/ */
#include "srsenb/hdr/stack/mac/scheduler_metric.h"
#include "srsenb/hdr/stack/mac/scheduler_harq.h"
#include <string.h> #include <string.h>
#include "srsenb/hdr/mac/scheduler_harq.h"
#include "srsenb/hdr/mac/scheduler_metric.h"
#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) #define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)

@ -21,10 +21,10 @@
#include <string.h> #include <string.h>
#include "srslte/srslte.h" #include "srsenb/hdr/stack/mac/scheduler.h"
#include "srsenb/hdr/stack/mac/scheduler_ue.h"
#include "srslte/common/pdu.h" #include "srslte/common/pdu.h"
#include "srsenb/hdr/mac/scheduler_ue.h" #include "srslte/srslte.h"
#include "srsenb/hdr/mac/scheduler.h"
#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) #define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)

@ -22,8 +22,8 @@
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
#include "srsenb/hdr/stack/mac/ue.h"
#include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_interfaces.h"
#include "srsenb/hdr/mac/ue.h"
#define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__) #define Error(fmt, ...) log_h->error(fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) log_h->warning(fmt, ##__VA_ARGS__)

@ -0,0 +1,25 @@
#
# 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/.
#
set(SOURCES rrc.cc)
add_library(srsenb_rrc STATIC ${SOURCES})
install(TARGETS srsenb_rrc DESTINATION ${LIBRARY_DIR})

@ -19,7 +19,7 @@
* *
*/ */
#include "srsenb/hdr/upper/rrc.h" #include "srsenb/hdr/stack/rrc/rrc.h"
#include "srslte/asn1/asn1_utils.h" #include "srslte/asn1/asn1_utils.h"
#include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/liblte_mme.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
@ -36,12 +36,12 @@ using namespace asn1::rrc;
namespace srsenb { namespace srsenb {
void rrc::init(rrc_cfg_t *cfg_, void rrc::init(rrc_cfg_t* cfg_,
phy_interface_rrc* phy_, phy_interface_stack_lte* phy_,
mac_interface_rrc* mac_, mac_interface_rrc* mac_,
rlc_interface_rrc* rlc_, rlc_interface_rrc* rlc_,
pdcp_interface_rrc* pdcp_, pdcp_interface_rrc* pdcp_,
s1ap_interface_rrc *s1ap_, s1ap_interface_rrc* s1ap_,
gtpu_interface_rrc* gtpu_, gtpu_interface_rrc* gtpu_,
srslte::log* log_rrc) srslte::log* log_rrc)
{ {

@ -19,11 +19,11 @@
* *
*/ */
#include "srslte/upper/gtpu.h" #include "srslte/upper/gtpu.h"
#include "srsenb/hdr/upper/gtpu.h" #include "srsenb/hdr/stack/upper/gtpu.h"
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <unistd.h>
using namespace srslte; using namespace srslte;
namespace srsenb { namespace srsenb {

@ -19,8 +19,8 @@
* *
*/ */
#include "srsenb/hdr/upper/pdcp.h" #include "srsenb/hdr/stack/upper/pdcp.h"
#include "srsenb/hdr/upper/common_enb.h" #include "srsenb/hdr/stack/upper/common_enb.h"
namespace srsenb { namespace srsenb {

@ -19,8 +19,8 @@
* *
*/ */
#include "srsenb/hdr/upper/rlc.h" #include "srsenb/hdr/stack/upper/rlc.h"
#include "srsenb/hdr/upper/common_enb.h" #include "srsenb/hdr/stack/upper/common_enb.h"
namespace srsenb { namespace srsenb {
@ -41,8 +41,8 @@ void rlc::init(pdcp_interface_rlc* pdcp_, rrc_interface_rlc* rrc_, mac_interface
void rlc::stop() void rlc::stop()
{ {
pthread_rwlock_wrlock(&rwlock); pthread_rwlock_wrlock(&rwlock);
for(std::map<uint32_t, user_interface>::iterator iter=users.begin(); iter!=users.end(); ++iter) { for (auto& user : users) {
clear_user(&iter->second); user.second.rlc->stop();
} }
users.clear(); users.clear();
pthread_rwlock_unlock(&rwlock); pthread_rwlock_unlock(&rwlock);
@ -53,29 +53,22 @@ void rlc::add_user(uint16_t rnti)
{ {
pthread_rwlock_rdlock(&rwlock); pthread_rwlock_rdlock(&rwlock);
if (users.count(rnti) == 0) { if (users.count(rnti) == 0) {
srslte::rlc *obj = new srslte::rlc; std::unique_ptr<srslte::rlc> obj(new srslte::rlc);
obj->init(&users[rnti], &users[rnti], &users[rnti], log_h, mac_timers, RB_ID_SRB0); obj->init(&users[rnti], &users[rnti], log_h, mac_timers, RB_ID_SRB0);
users[rnti].rnti = rnti; users[rnti].rnti = rnti;
users[rnti].pdcp = pdcp; users[rnti].pdcp = pdcp;
users[rnti].rrc = rrc; users[rnti].rrc = rrc;
users[rnti].rlc = obj; users[rnti].rlc = std::move(obj);
users[rnti].parent = this; users[rnti].parent = this;
} }
pthread_rwlock_unlock(&rwlock); pthread_rwlock_unlock(&rwlock);
} }
// Private unlocked deallocation of user
void rlc::clear_user(user_interface *ue)
{
ue->rlc->stop();
delete ue->rlc;
ue->rlc = NULL;
}
void rlc::rem_user(uint16_t rnti) void rlc::rem_user(uint16_t rnti)
{ {
pthread_rwlock_wrlock(&rwlock); pthread_rwlock_wrlock(&rwlock);
if (users.count(rnti)) { if (users.count(rnti)) {
clear_user(&users[rnti]); users[rnti].rlc->stop();
users.erase(rnti); users.erase(rnti);
} else { } else {
log_h->error("Removing rnti=0x%x. Already removed\n", rnti); log_h->error("Removing rnti=0x%x. Already removed\n", rnti);

@ -19,8 +19,8 @@
* *
*/ */
#include "srsenb/hdr/upper/s1ap.h" #include "srsenb/hdr/stack/upper/s1ap.h"
#include "srsenb/hdr/upper/common_enb.h" #include "srsenb/hdr/stack/upper/common_enb.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include "srslte/common/int_helpers.h" #include "srslte/common/int_helpers.h"

@ -21,8 +21,8 @@
#include <unistd.h> #include <unistd.h>
#include "srsenb/hdr/mac/mac.h"
#include "srsenb/hdr/phy/phy.h" #include "srsenb/hdr/phy/phy.h"
#include "srsenb/hdr/stack/mac/mac.h"
#include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/sched_interface.h" #include "srslte/interfaces/sched_interface.h"

@ -19,18 +19,17 @@
* *
*/ */
#include "srsenb/hdr/stack/mac/scheduler.h"
#include "srsenb/hdr/stack/mac/scheduler_ue.h"
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <random> #include <random>
#include <set> #include <set>
#include <srsenb/hdr/mac/scheduler.h>
#include <srsenb/hdr/mac/scheduler_ue.h>
#include <srslte/interfaces/sched_interface.h>
#include <srslte/srslte.h> #include <srslte/srslte.h>
#include <unistd.h> #include <unistd.h>
#include "srsenb/hdr/mac/mac.h"
#include "srsenb/hdr/phy/phy.h" #include "srsenb/hdr/phy/phy.h"
#include "srsenb/hdr/stack/mac/mac.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_interfaces.h"

@ -19,7 +19,7 @@
* *
*/ */
#include "srsenb/hdr/upper/common_enb.h" #include "srsenb/hdr/stack/upper/common_enb.h"
#include "srslte/asn1/rrc_asn1.h" #include "srslte/asn1/rrc_asn1.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include <iostream> #include <iostream>

@ -25,20 +25,57 @@
#include "srslte/common/logger.h" #include "srslte/common/logger.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/ue_metrics_interface.h" #include "srsue/hdr/ue_metrics_interface.h"
#include "srsue/hdr/ue_stack_interface.h"
#include <memory> #include "rrc/rrc.h"
#include "upper/gw.h"
#include "upper/usim.h"
namespace srsue { namespace srsue {
class ue_stack_base : public ue_interface typedef struct {
bool enable;
std::string filename;
bool nas_enable;
std::string nas_filename;
} pcap_args_t;
typedef struct {
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gw_level;
std::string nas_level;
std::string usim_level;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gw_hex_limit;
int nas_hex_limit;
int usim_hex_limit;
} stack_log_args_t;
typedef struct {
std::string type;
pcap_args_t pcap;
stack_log_args_t log;
usim_args_t usim;
rrc_args_t rrc;
std::string ue_category_str;
nas_args_t nas;
gw_args_t gw;
} stack_args_t;
class ue_stack_base
{ {
public: public:
ue_stack_base(){}; ue_stack_base() = default;
virtual ~ue_stack_base(){}; virtual ~ue_stack_base() = default;
virtual std::string get_type() = 0; virtual std::string get_type() = 0;
virtual int init(const stack_args_t& args_, srslte::logger* logger_) = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual bool switch_on() = 0; virtual bool switch_on() = 0;
virtual bool switch_off() = 0; virtual bool switch_off() = 0;

@ -35,7 +35,6 @@
#include "phy/ue_phy_base.h" #include "phy/ue_phy_base.h"
#include "radio/ue_radio_base.h" #include "radio/ue_radio_base.h"
#include "stack/ue_stack_base.h" #include "stack/ue_stack_base.h"
#include "ue_stack_interface.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/logger_file.h" #include "srslte/common/logger_file.h"
@ -88,7 +87,7 @@ typedef struct {
Main UE class Main UE class
*******************************************************************************/ *******************************************************************************/
class ue : public ue_interface, public ue_metrics_interface class ue : public ue_metrics_interface
{ {
public: public:
ue(); ue();

@ -1,90 +0,0 @@
/*
* 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/.
*
*/
/******************************************************************************
* File: ue_stack_interface.h
* Description: Pure virtual interface to the UE stack.
*****************************************************************************/
#ifndef SRSUE_UE_STACK_INTERFACE_H
#define SRSUE_UE_STACK_INTERFACE_H
#include "srslte/common/logger.h"
#include "stack/rrc/rrc.h"
#include "stack/upper/gw.h"
#include "stack/upper/nas.h"
#include "stack/upper/usim.h"
#include "ue_metrics_interface.h"
namespace srsue {
typedef struct {
bool enable;
std::string filename;
bool nas_enable;
std::string nas_filename;
} pcap_args_t;
typedef struct {
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gw_level;
std::string nas_level;
std::string usim_level;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gw_hex_limit;
int nas_hex_limit;
int usim_hex_limit;
} stack_log_args_t;
typedef struct {
std::string type;
pcap_args_t pcap;
stack_log_args_t log;
usim_args_t usim;
rrc_args_t rrc;
std::string ue_category_str;
nas_args_t nas;
gw_args_t gw;
} stack_args_t;
class ue_stack_interface
{
public:
virtual bool init(stack_args_t args_, srslte::logger* logger_) = 0;
virtual void stop() = 0;
virtual bool switch_on() = 0;
virtual bool switch_off() = 0;
virtual bool get_metrics(ue_metrics_t* metrics) = 0;
virtual bool is_rrc_connected() = 0;
};
} // namespace srsue
#endif // SRSUE_UE_STACK_INTERFACE_H

@ -101,7 +101,7 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
} }
mac.init(phy, &rlc, &rrc, &mac_log); mac.init(phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, NULL, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); rlc.init(&pdcp, &rrc, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
nas.init(usim.get(), &rrc, &gw, &nas_log, args.nas); nas.init(usim.get(), &rrc, &gw, &nas_log, args.nas);
gw.init(&pdcp, &nas, &gw_log, args.gw); gw.init(&pdcp, &nas, &gw_log, args.gw);

@ -73,7 +73,7 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_)
// Instantiate layers and stack together our UE // Instantiate layers and stack together our UE
if (args.stack.type == "lte") { if (args.stack.type == "lte") {
std::unique_ptr<ue_stack_lte> lte_stack = std::unique_ptr<ue_stack_lte>(new ue_stack_lte()); std::unique_ptr<ue_stack_lte> lte_stack(new ue_stack_lte());
if (!lte_stack) { if (!lte_stack) {
log.console("Error creating LTE stack instance.\n"); log.console("Error creating LTE stack instance.\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;

Loading…
Cancel
Save