introduce layerd architecture we use for UE to eNB

- this allows flexible use of different PHYs and radios
- use common radio_multi (moved to lib)
master
Andre Puschmann 6 years ago
parent 2530894374
commit 4e86b2f6b2

@ -28,6 +28,35 @@
namespace srslte {
typedef struct {
std::string phy_level;
std::string phy_lib_level;
int phy_hex_limit;
} phy_log_args_t;
// RF/radio args
typedef struct {
std::string type;
std::string log_level;
float dl_freq;
float ul_freq;
float freq_offset;
float rx_gain;
float tx_gain;
float tx_max_power;
float tx_gain_offset;
float rx_gain_offset;
uint32_t nof_radios;
uint32_t nof_rf_channels; // Number of RF channels per radio
uint32_t nof_rx_ant; // Number of RF channels for MIMO
uint32_t nof_tx_ports; // Number of Tx ports for MIMO
std::string device_name;
std::string device_args[SRSLTE_MAX_RADIOS];
std::string time_adv_nsamples;
std::string burst_preamble;
std::string continuous_tx;
} rf_args_t;
class srslte_gw_config_t
{
public:

@ -0,0 +1,82 @@
/*
* 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: common_interfaces.h
* Description: Common interface for eNB/UE for PHY and radio
*****************************************************************************/
#ifndef SRSLTE_COMMON_INTERFACES_H
#define SRSLTE_COMMON_INTERFACES_H
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/common/timestamp.h"
#include "srslte/phy/rf/rf.h"
namespace srslte {
class radio_interface_phy
{
public:
// trx functions
virtual bool tx(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS],
const uint32_t& nof_samples,
const srslte_timestamp_t& tx_time) = 0;
virtual void tx_end() = 0;
virtual bool rx_now(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS],
const uint32_t& nof_samples,
srslte_timestamp_t* rxd_time) = 0;
// setter
virtual void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0;
virtual void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0;
virtual double set_rx_gain_th(const float& gain) = 0;
virtual void set_rx_gain(const uint32_t& radio_idx, const float& gain) = 0;
virtual void set_tx_srate(const uint32_t& radio_idx, const double& srate) = 0;
virtual void set_rx_srate(const uint32_t& radio_idx, const double& srate) = 0;
// getter
virtual float get_rx_gain(const uint32_t& radio_idx) = 0;
virtual double get_freq_offset() = 0;
virtual double get_tx_freq(const uint32_t& radio_idx) = 0;
virtual double get_rx_freq(const uint32_t& radio_idx) = 0;
virtual float get_max_tx_power() = 0;
virtual float get_tx_gain_offset() = 0;
virtual float get_rx_gain_offset() = 0;
virtual bool is_continuous_tx() = 0;
virtual bool is_init() = 0;
virtual void reset() = 0;
virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0;
};
class phy_interface_radio
{
public:
virtual void radio_overflow() = 0;
virtual void radio_failure() = 0;
};
} // namespace srslte
#endif // SRSLTE_COMMON_INTERFACES_H

@ -30,18 +30,12 @@
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srsenb/hdr/stack/upper/s1ap_metrics.h"
#include "srslte/common/metrics_hub.h"
#include "srslte/radio/radio_metrics.h"
#include "srslte/upper/rlc_metrics.h"
#include "srsue/hdr/stack/upper/gw_metrics.h"
namespace srsenb {
typedef struct {
uint32_t rf_o;
uint32_t rf_u;
uint32_t rf_l;
bool rf_error;
}rf_metrics_t;
struct stack_metrics_t {
mac_metrics_t mac[ENB_METRICS_MAX_USERS];
rrc_metrics_t rrc;
@ -49,7 +43,7 @@ struct stack_metrics_t {
};
typedef struct {
rf_metrics_t rf;
srslte::rf_metrics_t rf;
phy_metrics_t phy[ENB_METRICS_MAX_USERS];
stack_metrics_t stack;
bool running;

@ -669,27 +669,6 @@ public:
virtual void wait_uplink() = 0;
};
// RF/radio args
typedef struct {
std::string type;
std::string log_level;
float freq_offset;
float rx_gain;
float tx_gain;
float tx_max_power;
float tx_gain_offset;
float rx_gain_offset;
uint32_t nof_radios;
uint32_t nof_rf_channels; // Number of RF channels per radio
uint32_t nof_rx_ant; // Number of RF channels for MIMO
std::string device_name;
std::string device_args[SRSLTE_MAX_RADIOS];
std::string time_adv_nsamples;
std::string burst_preamble;
std::string continuous_tx;
} rf_args_t;
/** PHY interface
*
*/
@ -699,15 +678,9 @@ typedef struct {
uint32_t channel_idx;
} carrier_map_t;
typedef struct {
std::string phy_level;
std::string phy_lib_level;
int phy_hex_limit;
} phy_log_args_t;
typedef struct {
std::string type;
phy_log_args_t log;
srslte::phy_log_args_t log;
std::string dl_earfcn; // comma-separated list of EARFCNs
std::vector<uint32_t> earfcn_list; // vectorized version of dl_earfcn that gets populated during init
@ -878,50 +851,6 @@ public:
virtual void enable_pregen_signals(bool enable) = 0;
};
class radio_interface_phy
{
public:
// trx functions
virtual bool tx(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS],
const uint32_t& nof_samples,
const srslte_timestamp_t& tx_time) = 0;
virtual void tx_end() = 0;
virtual bool rx_now(const uint32_t& radio_idx,
cf_t* buffer[SRSLTE_MAX_PORTS],
const uint32_t& nof_samples,
srslte_timestamp_t* rxd_time) = 0;
// setter
virtual void set_tx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0;
virtual void set_rx_freq(const uint32_t& radio_idx, const uint32_t& channel_idx, const double& freq) = 0;
virtual double set_rx_gain_th(const float& gain) = 0;
virtual void set_rx_gain(const uint32_t& radio_idx, const float& gain) = 0;
virtual void set_tx_srate(const uint32_t& radio_idx, const double& srate) = 0;
virtual void set_rx_srate(const uint32_t& radio_idx, const double& srate) = 0;
// getter
virtual float get_rx_gain(const uint32_t& radio_idx) = 0;
virtual double get_freq_offset() = 0;
virtual double get_tx_freq(const uint32_t& radio_idx) = 0;
virtual double get_rx_freq(const uint32_t& radio_idx) = 0;
virtual float get_max_tx_power() = 0;
virtual float get_tx_gain_offset() = 0;
virtual float get_rx_gain_offset() = 0;
virtual bool is_continuous_tx() = 0;
virtual bool is_init() = 0;
virtual void reset() = 0;
virtual srslte_rf_info_t* get_info(const uint32_t& radio_idx) = 0;
};
class phy_interface_radio
{
public:
virtual void radio_overflow() = 0;
virtual void radio_failure() = 0;
};
// STACK interface for GW
class stack_interface_gw : public pdcp_interface_gw
{

@ -121,8 +121,6 @@ class radio {
float get_rssi();
bool has_rssi();
void set_tti(uint32_t tti);
bool is_first_of_burst();
bool is_init();

@ -20,37 +20,34 @@
*/
/******************************************************************************
* File: ue_radio_base.h
* Description: Base class for all UE Radios.
* File: radio_base.h
* Description: Base class for all eNB/UE radios.
*****************************************************************************/
#ifndef SRSUE_UE_RADIO_BASE_H
#define SRSUE_UE_RADIO_BASE_H
#ifndef SRSLTE_RADIO_BASE_H
#define SRSLTE_RADIO_BASE_H
#include "srslte/common/interfaces_common.h"
#include "srslte/common/logger.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/ue_metrics_interface.h"
#include <memory>
#include <vector>
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/radio/radio_metrics.h"
namespace srsue {
namespace srslte {
class ue_radio_base
class radio_base
{
public:
ue_radio_base(){};
virtual ~ue_radio_base(){};
radio_base(srslte::logger* logger_){};
virtual ~radio_base(){};
virtual std::string get_type() = 0;
virtual int init(const srsue::rf_args_t& args_, srslte::logger* logger_) = 0;
virtual int init(const rf_args_t& args_, phy_interface_radio* phy_) = 0;
virtual void stop() = 0;
virtual bool get_metrics(rf_metrics_t* metrics) = 0;
private:
};
} // namespace srsue
} // namespace srslte
#endif // SRSUE_UE_RADIO_BASE_H
#endif // SRSLTE_RADIO_BASE_H

@ -0,0 +1,36 @@
/*
* 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_RADIO_METRICS_H
#define SRSLTE_RADIO_METRICS_H
namespace srslte {
typedef struct {
uint32_t rf_o;
uint32_t rf_u;
uint32_t rf_l;
bool rf_error;
} rf_metrics_t;
} // namespace srslte
#endif // SRSLTE_RADIO_METRICS_H

@ -20,34 +20,31 @@
*/
/******************************************************************************
* File: ue_radio_multi.h
* Description: UE radio module using the srslte_radio_multi() object.
* File: radio_multi.h
* Description: Class for using multiple srslte::radio's for both eNB/UE
*****************************************************************************/
#ifndef SRSUE_UE_RADIO_MULTI_H
#define SRSUE_UE_RADIO_MULTI_H
#ifndef SRSLTE_RADIO_MULTI_H
#define SRSLTE_RADIO_MULTI_H
#include "srslte/common/log_filter.h"
#include "srslte/common/logger.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/phy/rf/rf.h"
#include "srslte/radio/radio.h"
#include "srsue/hdr/radio/ue_radio_base.h"
#include "srsue/hdr/ue_metrics_interface.h"
#include "srslte/radio/radio_base.h"
#include "srslte/radio/radio_metrics.h"
namespace srsue {
namespace srslte {
/*******************************************************************************
Main UE stack class
*******************************************************************************/
class ue_radio : public ue_radio_base, public radio_interface_phy
class radio_multi : public radio_base, public radio_interface_phy
{
public:
ue_radio();
~ue_radio() override;
radio_multi(srslte::logger* logger_);
~radio_multi() override;
std::string get_type() override;
int init(const rf_args_t& args_, srslte::logger* logger_) override;
int init(const rf_args_t& args_, srslte::logger* logger_, phy_interface_radio* phy_);
int init(const rf_args_t& args_, phy_interface_radio* phy_);
void stop() override;
@ -103,19 +100,18 @@ public:
}
srslte_rf_info_t* get_info(const uint32_t& radio_idx) override { return radios.at(radio_idx)->get_info(); }
private:
srsue::rf_args_t args;
protected:
rf_args_t args = {};
std::vector<std::unique_ptr<srslte::radio> > radios;
std::vector<std::unique_ptr<radio> > radios;
srslte::logger* logger;
srslte::logger* logger = nullptr;
srslte::log_filter log;
bool running;
bool running = false;
rf_metrics_t rf_metrics;
phy_interface_radio* phy;
srslte::rf_metrics_t rf_metrics = {};
phy_interface_radio* phy = nullptr;
};
} // namespace srslte
} // namespace srsue
#endif // SRSUE_UE_RADIO_MULTI_H
#endif // SRSLTE_RADIO_MULTI_H

@ -19,7 +19,7 @@
#
if(RF_FOUND)
add_library(srslte_radio STATIC radio.cc)
add_library(srslte_radio STATIC radio.cc radio_multi.cc)
target_link_libraries(srslte_radio srslte_rf)
install(TARGETS srslte_radio DESTINATION ${LIBRARY_DIR})
endif(RF_FOUND)

@ -255,10 +255,6 @@ void radio::tx_end()
}
}
void radio::set_tti(uint32_t tti_) {
tti = tti_;
}
void radio::set_freq_offset(double freq) {
freq_offset = freq;
}

@ -19,47 +19,34 @@
*
*/
#include "srsue/hdr/radio/ue_radio.h"
#include "srslte/radio/radio_multi.h"
#include <mutex>
using namespace srslte;
namespace srslte {
namespace srsue {
std::mutex radio_instance_mutex;
static radio_multi* instance;
std::mutex instance_mutex;
static ue_radio* instance;
ue_radio::ue_radio() : args(), logger(nullptr), running(false), phy(nullptr), rf_metrics(), radios()
radio_multi::radio_multi(srslte::logger* logger_) : logger(logger_), radio_base(logger_)
{
std::lock_guard<std::mutex> lock(instance_mutex);
std::lock_guard<std::mutex> lock(radio_instance_mutex);
instance = this;
}
ue_radio::~ue_radio()
radio_multi::~radio_multi()
{
stop();
}
std::string ue_radio::get_type()
std::string radio_multi::get_type()
{
return "radio";
}
int ue_radio::init(const rf_args_t& args_, srslte::logger* logger_, phy_interface_radio* phy_)
{
if (init(args_, logger_)) {
return SRSLTE_ERROR;
}
phy = phy_;
return SRSLTE_SUCCESS;
return "radio_multi";
}
int ue_radio::init(const rf_args_t& args_, srslte::logger* logger_)
int radio_multi::init(const rf_args_t& args_, phy_interface_radio* phy_)
{
args = args_;
logger = logger_;
phy = phy_;
// Init log
log.init("RF ", logger);
@ -130,10 +117,10 @@ int ue_radio::init(const rf_args_t& args_, srslte::logger* logger_)
return SRSLTE_SUCCESS;
}
void ue_radio::stop()
void radio_multi::stop()
{
if (running) {
std::lock_guard<std::mutex> lock(instance_mutex);
std::lock_guard<std::mutex> lock(radio_instance_mutex);
instance = nullptr;
for (auto& radio : radios) {
@ -144,22 +131,22 @@ void ue_radio::stop()
}
}
bool ue_radio::get_metrics(rf_metrics_t* metrics)
bool radio_multi::get_metrics(rf_metrics_t* metrics)
{
*metrics = rf_metrics;
rf_metrics = {};
return true;
}
void ue_radio::rf_msg(srslte_rf_error_t error)
void radio_multi::rf_msg(srslte_rf_error_t error)
{
std::lock_guard<std::mutex> lock(instance_mutex);
std::lock_guard<std::mutex> lock(radio_instance_mutex);
if (instance) {
instance->handle_rf_msg(error);
}
}
void ue_radio::handle_rf_msg(srslte_rf_error_t error)
void radio_multi::handle_rf_msg(srslte_rf_error_t error)
{
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
rf_metrics.rf_o++;
@ -188,4 +175,4 @@ void ue_radio::handle_rf_msg(srslte_rf_error_t error)
}
}
} // namespace srsue
} // namespace srslte

@ -35,11 +35,15 @@
#include "phy/phy.h"
#include "srsenb/hdr/stack/rrc/rrc.h"
#include "srslte/radio/radio.h"
#include "srslte/radio/radio_base.h"
#include "srsenb/hdr/phy/enb_phy_base.h"
#include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/mac_pcap.h"
@ -55,7 +59,8 @@ namespace srsenb {
*******************************************************************************/
struct enb_args_t {
s1ap_args_t s1ap;
uint32_t dl_earfcn;
uint32_t ul_earfcn;
uint32_t n_prb;
uint32_t pci;
uint32_t nof_ports;
@ -69,41 +74,13 @@ struct enb_files_t {
std::string drb_config;
};
typedef struct {
uint32_t dl_earfcn;
uint32_t ul_earfcn;
float dl_freq;
float ul_freq;
float rx_gain;
float tx_gain;
std::string device_name;
std::string device_args;
std::string time_adv_nsamples;
std::string burst_preamble;
}rf_args_t;
typedef struct {
bool enable;
std::string filename;
}pcap_args_t;
typedef struct {
std::string phy_level;
std::string phy_lib_level;
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gtpu_level;
std::string s1ap_level;
std::string all_level;
int phy_hex_limit;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gtpu_hex_limit;
int s1ap_hex_limit;
int all_hex_limit;
int file_max_size;
std::string filename;
@ -115,7 +92,6 @@ struct gui_args_t {
struct expert_args_t {
phy_args_t phy;
mac_args_t mac;
uint32_t rrc_inactivity_timer;
float metrics_period_secs;
bool metrics_csv_enable;
@ -131,11 +107,12 @@ struct expert_args_t {
struct all_args_t {
enb_args_t enb;
enb_files_t enb_files;
rf_args_t rf;
srslte::rf_args_t rf;
pcap_args_t pcap;
log_args_t log;
gui_args_t gui;
expert_args_t expert;
stack_args_t stack;
};
/*******************************************************************************
@ -149,7 +126,7 @@ public:
static void cleanup(void);
bool init(all_args_t *args_);
int init(const all_args_t& args_);
void stop();
@ -174,23 +151,29 @@ private:
virtual ~enb();
std::unique_ptr<enb_stack_base> stack;
srslte::radio radio;
srsenb::phy phy;
int parse_args(const all_args_t& args_);
// eNB components
std::unique_ptr<enb_stack_base> stack = nullptr;
std::unique_ptr<srslte::radio_base> radio = nullptr;
std::unique_ptr<enb_phy_base> phy = nullptr;
srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file;
srslte::logger *logger;
srslte::logger* logger = nullptr;
srslte::log_filter log; // Own logger for eNB
srslte::log_filter rf_log;
std::vector<srslte::log_filter*> phy_log;
srslte::log_filter pool_log;
srslte::byte_buffer_pool *pool;
srslte::byte_buffer_pool* pool = nullptr;
all_args_t args = {};
bool started = false;
all_args_t *args;
bool started;
rf_metrics_t rf_metrics;
phy_cfg_t phy_cfg = {};
rrc_cfg_t rrc_cfg = {};
srslte::LOG_LEVEL_ENUM level(std::string l);

@ -0,0 +1,52 @@
/*
* 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_lte_phy_base.h
* Description: Base class for eNB LTE PHYs.
*****************************************************************************/
#ifndef SRSENB_LTE_PHY_BASE_H
#define SRSENB_LTE_PHY_BASE_H
#include "srsenb/hdr/phy/enb_phy_base.h"
#include "srslte/interfaces/common_interfaces.h"
namespace srsenb {
class enb_lte_phy_base : public enb_phy_base, public phy_interface_stack_lte, public srslte::phy_interface_radio
{
public:
enb_lte_phy_base(){};
virtual ~enb_lte_phy_base(){};
virtual std::string get_type() = 0;
virtual void stop() = 0;
virtual void start_plot() = 0;
virtual void get_metrics(phy_metrics_t* m) = 0;
};
} // namespace srsenb
#endif // SRSENB_LTE_PHY_BASE_H

@ -0,0 +1,51 @@
/*
* 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_phy_base.h
* Description: Base class for all eNB PHYs.
*****************************************************************************/
#ifndef SRSENB_PHY_BASE_H
#define SRSENB_PHY_BASE_H
#include "srsue/hdr/phy/phy_metrics.h"
namespace srsenb {
class enb_phy_base
{
public:
enb_phy_base(){};
virtual ~enb_phy_base(){};
virtual std::string get_type() = 0;
virtual void stop() = 0;
virtual void start_plot() = 0;
virtual void get_metrics(phy_metrics_t* m) = 0;
};
} // namespace srsenb
#endif // SRSENB_PHY_BASE_H

@ -24,9 +24,11 @@
#include "phy_common.h"
#include "sf_worker.h"
#include "srsenb/hdr/phy/enb_lte_phy_base.h"
#include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/trace.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/radio/radio.h"
@ -43,23 +45,20 @@ typedef struct {
asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg;
} phy_cfg_t;
class phy : public phy_interface_stack_lte
class phy : public enb_lte_phy_base
{
public:
phy(srslte::logger* logger_);
~phy();
phy();
bool init(phy_args_t* args,
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);
int init(const phy_args_t& args,
const phy_cfg_t& cfg,
srslte::radio_interface_phy* radio_,
stack_interface_phy_lte* stack_);
void stop();
std::string get_type() { return "lte"; };
/* MAC->PHY interface */
int add_rnti(uint16_t rnti, bool is_temporal = false);
void rem_rnti(uint16_t rnti);
@ -76,9 +75,12 @@ public:
void get_metrics(phy_metrics_t metrics[ENB_METRICS_MAX_USERS]);
void radio_overflow(){};
void radio_failure(){};
private:
phy_rrc_cfg_t phy_rrc_config;
uint32_t nof_workers;
phy_rrc_cfg_t phy_rrc_config = {};
uint32_t nof_workers = 0;
const static int MAX_WORKERS = 4;
const static int DEFAULT_WORKERS = 2;
@ -87,18 +89,23 @@ private:
const static int SF_RECV_THREAD_PRIO = 1;
const static int WORKERS_THREAD_PRIO = 2;
srslte::radio *radio_handler;
srslte::log *log_h;
srslte::radio_interface_phy* radio = nullptr;
srslte::logger* logger = nullptr;
std::vector<std::unique_ptr<srslte::log_filter> > log_vec;
srslte::log* log_h = nullptr;
srslte::thread_pool workers_pool;
std::vector<sf_worker> workers;
phy_common workers_common;
prach_worker prach;
txrx tx_rx;
txrx tx_rx;
srslte_prach_cfg_t prach_cfg;
bool initialized = false;
void parse_config(phy_cfg_t* cfg);
srslte_prach_cfg_t prach_cfg = {};
void parse_config(const phy_cfg_t& cfg);
};
} // namespace srsenb

@ -22,20 +22,25 @@
#ifndef SRSENB_PHCH_COMMON_H
#define SRSENB_PHCH_COMMON_H
#include <map>
#include <semaphore.h>
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/common/gen_mch_tables.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/common/thread_pool.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/radio/radio.h"
#include <map>
#include <semaphore.h>
#include <string.h>
namespace srsenb {
typedef struct {
std::string type;
srslte::phy_log_args_t log;
float max_prach_offset_us;
int pusch_max_its;
bool pusch_8bit_decoder;
@ -54,7 +59,7 @@ public:
void set_nof_workers(uint32_t nof_workers);
bool init(srslte_cell_t* cell, srslte::radio* radio_handler, stack_interface_phy_lte* mac);
bool init(const srslte_cell_t& cell_, srslte::radio_interface_phy* radio_handler, stack_interface_phy_lte* mac);
void reset();
void stop();
@ -70,7 +75,7 @@ public:
// Physical Downlink Config common
srslte_dl_cfg_t dl_cfg_com;
srslte::radio *radio;
srslte::radio_interface_phy* radio;
stack_interface_phy_lte* stack;
// Common objects for schedulign grants

@ -53,11 +53,11 @@ public:
bzero(&prach_cfg, sizeof(prach_cfg));
}
int init(srslte_cell_t* cell,
srslte_prach_cfg_t* prach_cfg,
stack_interface_phy_lte* mac,
srslte::log* log_h,
int priority);
int init(const srslte_cell_t& cell_,
const 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);
void set_max_prach_offset_us(float delay_us);
void stop();

@ -37,19 +37,18 @@ class txrx : public thread
{
public:
txrx();
bool init(srslte::radio* radio_handler,
srslte::thread_pool* _workers_pool,
phy_common* worker_com,
prach_worker* prach,
srslte::log* log_h,
uint32_t prio);
bool init(srslte::radio_interface_phy* radio_handler,
srslte::thread_pool* _workers_pool,
phy_common* worker_com,
prach_worker* prach,
srslte::log* log_h,
uint32_t prio);
void stop();
private:
void run_thread();
srslte::radio *radio_h;
srslte::radio_interface_phy* radio_h;
srslte::log *log_h;
srslte::thread_pool *workers_pool;
prach_worker* prach;

@ -0,0 +1,49 @@
/*
* 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_radio_multi.h
* Description: Header-only class for eNB to set DL/UL freq during init
*****************************************************************************/
#ifndef SRSENB_RADIO_MULTI_H
#define SRSENB_RADIO_MULTI_H
#include "srslte/common/logger.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/phy/rf/rf.h"
#include "srslte/radio/radio_base.h"
#include "srslte/radio/radio_metrics.h"
#include "srslte/radio/radio_multi.h"
namespace srsenb {
class enb_radio_multi : public srslte::radio_multi
{
public:
enb_radio_multi(srslte::logger* logger_);
~enb_radio_multi() override;
int init(const srslte::rf_args_t& args_, srslte::phy_interface_radio* phy_);
};
} // namespace srsenb
#endif // SRSENB_RADIO_MULTI_H

@ -26,6 +26,41 @@
namespace srsenb {
typedef struct {
bool enable;
std::string filename;
} pcap_args_t;
typedef struct {
bool enable_mbsfn;
std::string m1u_multiaddr;
std::string m1u_if_addr;
} stack_expert_args_t;
typedef struct {
std::string mac_level;
std::string rlc_level;
std::string pdcp_level;
std::string rrc_level;
std::string gtpu_level;
std::string s1ap_level;
int mac_hex_limit;
int rlc_hex_limit;
int pdcp_hex_limit;
int rrc_hex_limit;
int gtpu_hex_limit;
int s1ap_hex_limit;
} stack_log_args_t;
typedef struct {
mac_args_t mac;
s1ap_args_t s1ap;
pcap_args_t pcap;
stack_log_args_t log;
stack_expert_args_t expert;
} stack_args_t;
struct stack_metrics_t;
class enb_stack_base

@ -45,26 +45,12 @@ 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(srslte::logger* logger_);
~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_);
int init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_, phy_interface_stack_lte* phy_);
int init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_);
void stop() final;
std::string get_type() final;
bool get_metrics(stack_metrics_t* metrics) final;
@ -99,9 +85,9 @@ public:
void tti_clock() final { mac.tti_clock(); }
private:
args_t args;
rrc_cfg_t rrc_cfg;
bool started;
stack_args_t args = {};
rrc_cfg_t rrc_cfg = {};
bool started = false;
srsenb::mac mac;
srslte::mac_pcap mac_pcap;
@ -111,7 +97,7 @@ private:
srsenb::gtpu gtpu;
srsenb::s1ap s1ap;
srslte::logger* logger;
srslte::logger* logger = nullptr;
// Radio and PHY log are in enb.cc
srslte::log_filter mac_log;
@ -122,7 +108,7 @@ private:
srslte::log_filter gtpu_log;
// RAT-specific interfaces
phy_interface_stack_lte* phy;
phy_interface_stack_lte* phy = nullptr;
};
} // namespace srsenb

@ -87,16 +87,16 @@ private:
// consts
srslte::log* log_h = nullptr;
sched_ue::sched_dci_cce_t* common_locations = nullptr;
sched_ue::sched_dci_cce_t* rar_locations[10];
uint32_t cce_size_array[nof_cfis];
sched_ue::sched_dci_cce_t* rar_locations[10] = {nullptr};
uint32_t cce_size_array[nof_cfis] = {0};
// tti vars
uint32_t tti_rx;
uint32_t sf_idx;
uint32_t current_cfix;
size_t prev_start, prev_end;
uint32_t tti_rx = 0;
uint32_t sf_idx = 0;
uint32_t current_cfix = 0;
size_t prev_start, prev_end = 0;
std::vector<tree_node_t> dci_alloc_tree;
size_t nof_dci_allocs;
size_t nof_dci_allocs = 0;
};
class tti_grid_t
@ -130,21 +130,21 @@ private:
// consts
srslte::log* log_h = nullptr;
sched_interface::cell_cfg_t* cell_cfg = nullptr;
uint32_t nof_prbs;
uint32_t nof_rbgs;
uint32_t si_n_rbg, rar_n_rbg;
uint32_t nof_prbs = 0;
uint32_t nof_rbgs = 0;
uint32_t si_n_rbg, rar_n_rbg = 0;
// tti const
uint32_t tti_rx = 10241;
// derived
uint32_t tti_tx_dl, tti_tx_ul;
uint32_t sfn;
pdcch_grid_t pdcch_alloc;
uint32_t tti_tx_dl, tti_tx_ul = 0;
uint32_t sfn = 0;
pdcch_grid_t pdcch_alloc = {};
// internal state
uint32_t avail_rbg = 0;
rbgmask_t dl_mask;
prbmask_t ul_mask;
rbgmask_t dl_mask = {};
prbmask_t ul_mask = {};
};
} // namespace srsenb

@ -18,6 +18,7 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(radio)
add_subdirectory(phy)
add_subdirectory(stack)
@ -34,7 +35,8 @@ endif (RPATH)
add_executable(srsenb main.cc enb.cc parser.cc enb_cfg_parser.cc metrics_stdout.cc metrics_csv.cc)
target_link_libraries(srsenb srsenb_phy
target_link_libraries(srsenb srsenb_radio
srsenb_phy
srsenb_stack
srsenb_upper
srsenb_mac

@ -20,6 +20,7 @@
*/
#include "srsenb/hdr/enb.h"
#include "srsenb/hdr/radio/enb_radio_multi.h"
#include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srslte/build_info.h"
#include <boost/algorithm/string.hpp>
@ -52,17 +53,12 @@ void enb::cleanup()
pthread_mutex_unlock(&enb_instance_mutex);
}
enb::enb() : started(false) {
enb::enb() : started(false), pool(srslte::byte_buffer_pool::get_instance(ENB_POOL_SIZE))
{
// print build info
std::cout << std::endl << get_build_string() << std::endl;
srslte_dft_load();
pool = srslte::byte_buffer_pool::get_instance(ENB_POOL_SIZE);
logger = nullptr;
args = nullptr;
bzero(&rf_metrics, sizeof(rf_metrics));
}
enb::~enb()
@ -72,27 +68,37 @@ enb::~enb()
}
}
bool enb::init(all_args_t *args_)
int enb::init(const all_args_t& args_)
{
args = args_;
// Init UE log
log.init("UE ", logger);
log.set_level(srslte::LOG_LEVEL_INFO);
log.info("%s", get_build_string().c_str());
// Validate arguments
if (parse_args(args_)) {
log.console("Error processing arguments.\n");
return SRSLTE_ERROR;
}
if (args->log.filename == "stdout") {
// set logger
if (args.log.filename == "stdout") {
logger = &logger_stdout;
} else {
logger_file.init(args->log.filename, args->log.file_max_size);
logger_file.init(args.log.filename, args.log.file_max_size);
logger_file.log("\n\n");
logger_file.log(get_build_string().c_str());
logger = &logger_file;
}
rf_log.init("RF ", logger);
// Create array of pointers to phy_logs
for (int i=0;i<args->expert.phy.nof_phy_threads;i++) {
for (int i = 0; i < args.expert.phy.nof_phy_threads; i++) {
auto* mylog = new srslte::log_filter;
char tmp[16];
sprintf(tmp, "PHY%d",i);
mylog->init(tmp, logger, true);
mylog->set_level(level(args.log.phy_level));
mylog->set_hex_limit(args.log.phy_hex_limit);
phy_log.push_back(mylog);
}
@ -100,60 +106,119 @@ bool enb::init(all_args_t *args_)
pool_log.set_level(srslte::LOG_LEVEL_ERROR);
pool->set_log(&pool_log);
// Init logs
rf_log.set_level(srslte::LOG_LEVEL_INFO);
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));
// Create layers
std::unique_ptr<enb_stack_lte> lte_stack(new enb_stack_lte(logger));
if (!lte_stack) {
log.console("Error creating eNB stack.\n");
return SRSLTE_ERROR;
}
std::unique_ptr<enb_radio_multi> lte_radio = std::unique_ptr<enb_radio_multi>(new enb_radio_multi(logger));
if (!lte_radio) {
log.console("Error creating radio multi instance.\n");
return SRSLTE_ERROR;
}
std::unique_ptr<srsenb::phy> lte_phy = std::unique_ptr<srsenb::phy>(new srsenb::phy(logger));
if (!lte_phy) {
log.console("Error creating LTE PHY instance.\n");
return SRSLTE_ERROR;
}
// Init layers
if (lte_radio->init(args.rf, lte_phy.get())) {
log.console("Error initializing radio.\n");
return SRSLTE_ERROR;
}
if (lte_phy->init(args.expert.phy, phy_cfg, lte_radio.get(), lte_stack.get())) {
log.console("Error initializing PHY.\n");
return SRSLTE_ERROR;
}
if (lte_stack->init(args.stack, rrc_cfg, lte_phy.get())) {
log.console("Error initializing stack.\n");
return SRSLTE_ERROR;
}
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);
stack = std::move(lte_stack);
phy = std::move(lte_phy);
radio = std::move(lte_radio);
log.console("\n==== eNodeB started ===\n");
log.console("Type <t> to view trace\n");
started = true;
return SRSLTE_SUCCESS;
}
void enb::stop()
{
if (started) {
// tear down in reverse order
if (phy) {
phy->stop();
}
if (stack) {
stack->stop();
}
if (radio) {
radio->stop();
}
started = false;
}
}
int enb::parse_args(const all_args_t& args_)
{
// set member variable
args = args_;
// Parse config files
srslte_cell_t cell_cfg;
phy_cfg_t phy_cfg;
rrc_cfg_t rrc_cfg;
srslte_cell_t cell_cfg = {};
if (parse_cell_cfg(args, &cell_cfg)) {
if (parse_cell_cfg(&args, &cell_cfg)) {
fprintf(stderr, "Error parsing Cell configuration\n");
return false;
return SRSLTE_ERROR;
}
if (parse_sibs(args, &rrc_cfg, &phy_cfg)) {
if (parse_sibs(&args, &rrc_cfg, &phy_cfg)) {
fprintf(stderr, "Error parsing SIB configuration\n");
return false;
return SRSLTE_ERROR;
}
if (parse_rr(args, &rrc_cfg)) {
if (parse_rr(&args, &rrc_cfg)) {
fprintf(stderr, "Error parsing Radio Resources configuration\n");
return false;
return SRSLTE_ERROR;
}
if (parse_drb(args, &rrc_cfg)) {
if (parse_drb(&args, &rrc_cfg)) {
fprintf(stderr, "Error parsing DRB configuration\n");
return false;
return SRSLTE_ERROR;
}
if (args->enb.transmission_mode == 1) {
if (args.enb.transmission_mode == 1) {
phy_cfg.pdsch_cnfg.p_b = 0; // Default TM1
} else {
phy_cfg.pdsch_cnfg.p_b = 1; // Default TM2,3,4
}
rrc_cfg.inactivity_timeout_ms = args->expert.rrc_inactivity_timer;
rrc_cfg.enable_mbsfn = args->expert.enable_mbsfn;
rrc_cfg.inactivity_timeout_ms = args.expert.rrc_inactivity_timer;
rrc_cfg.enable_mbsfn = args.expert.enable_mbsfn;
// Check number of control symbols
if (cell_cfg.nof_prb < 50 && args->expert.mac.sched.nof_ctrl_symbols != 3) {
args->expert.mac.sched.nof_ctrl_symbols = 3;
if (cell_cfg.nof_prb < 50 && args.stack.mac.sched.nof_ctrl_symbols != 3) {
args.stack.mac.sched.nof_ctrl_symbols = 3;
fprintf(stdout,
"Setting number of control symbols to %d for %d PRB cell.\n",
args->expert.mac.sched.nof_ctrl_symbols,
args.stack.mac.sched.nof_ctrl_symbols,
cell_cfg.nof_prb);
}
// Parse EEA preference list
std::vector<std::string> eea_pref_list;
boost::split(eea_pref_list, args->expert.eea_pref_list,
boost::is_any_of(","));
boost::split(eea_pref_list, args.expert.eea_pref_list, boost::is_any_of(","));
int i = 0;
for (auto it = eea_pref_list.begin(); it != eea_pref_list.end() && i < srslte::CIPHERING_ALGORITHM_ID_N_ITEMS; it++) {
boost::trim_left(*it);
@ -167,16 +232,14 @@ bool enb::init(all_args_t *args_)
rrc_cfg.eea_preference_list[i] = srslte::CIPHERING_ALGORITHM_ID_128_EEA2;
i++;
} else {
fprintf(stderr, "Failed to parse EEA prefence list %s \n",
args->expert.eea_pref_list.c_str());
return false;
fprintf(stderr, "Failed to parse EEA prefence list %s \n", args.expert.eea_pref_list.c_str());
return SRSLTE_ERROR;
}
}
// Parse EIA preference list
std::vector<std::string> eia_pref_list;
boost::split(eia_pref_list, args->expert.eia_pref_list,
boost::is_any_of(","));
boost::split(eia_pref_list, args.expert.eia_pref_list, boost::is_any_of(","));
i = 0;
for (auto it = eia_pref_list.begin(); it != eia_pref_list.end() && i < srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS; it++) {
boost::trim_left(*it);
@ -190,87 +253,23 @@ bool enb::init(all_args_t *args_)
rrc_cfg.eia_preference_list[i] = srslte::INTEGRITY_ALGORITHM_ID_128_EIA2;
i++;
} else {
fprintf(stderr, "Failed to parse EIA prefence list %s \n",
args->expert.eia_pref_list.c_str());
return false;
fprintf(stderr, "Failed to parse EIA prefence list %s \n", args.expert.eia_pref_list.c_str());
return SRSLTE_ERROR;
}
}
// Copy cell struct to rrc and phy
memcpy(&rrc_cfg.cell, &cell_cfg, sizeof(srslte_cell_t));
memcpy(&phy_cfg.cell, &cell_cfg, sizeof(srslte_cell_t));
rrc_cfg.cell = cell_cfg;
phy_cfg.cell = cell_cfg;
// Init layers
// Patch certain args that are not exposed yet
args.rf.nof_radios = args.rf.nof_rf_channels = args.rf.nof_rx_ant = 1;
/* Start Radio */
char* dev_name = nullptr;
if (args->rf.device_name != "auto") {
dev_name = (char*) args->rf.device_name.c_str();
}
char* dev_args = nullptr;
if (args->rf.device_args != "auto") {
dev_args = (char*) args->rf.device_args.c_str();
}
if (!radio.init(phy_log[0], dev_args, dev_name, args->enb.nof_ports)) {
phy_log[0]->console(
"Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args.c_str());
return false;
}
// Set RF options
if (args->rf.time_adv_nsamples != "auto") {
radio.set_tx_adv((int)strtol(args->rf.time_adv_nsamples.c_str(), nullptr, 10));
}
if (args->rf.burst_preamble != "auto") {
radio.set_burst_preamble(strtof(args->rf.burst_preamble.c_str(), nullptr));
}
radio.set_rx_gain(args->rf.rx_gain);
radio.set_tx_gain(args->rf.tx_gain);
((srslte::log_filter*) phy_log[0])->console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6);
radio.set_tx_freq(args->enb.nof_ports, args->rf.dl_freq);
radio.set_rx_freq(args->enb.nof_ports, args->rf.ul_freq);
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
std::unique_ptr<enb_stack_lte> lte_stack(new enb_stack_lte());
phy.init(&args->expert.phy, &phy_cfg, &radio, lte_stack.get(), phy_log);
if (lte_stack->init(stack_args, rrc_cfg, logger, &phy) != SRSLTE_SUCCESS) {
return false;
}
stack = std::move(lte_stack);
started = true;
return true;
}
void enb::stop()
{
if(started)
{
phy.stop();
stack->stop();
radio.stop();
started = false;
}
return SRSLTE_SUCCESS;
}
void enb::start_plot() {
phy.start_plot();
phy->start_plot();
}
void enb::print_pool() {
@ -279,46 +278,13 @@ void enb::print_pool() {
bool enb::get_metrics(enb_metrics_t* m)
{
m->rf = rf_metrics;
bzero(&rf_metrics, sizeof(rf_metrics_t));
rf_metrics.rf_error = false; // Reset error flag
phy.get_metrics(m->phy);
radio->get_metrics(&m->rf);
phy->get_metrics(m->phy);
stack->get_metrics(&m->stack);
m->running = started;
return true;
}
void enb::rf_msg(srslte_rf_error_t error)
{
enb *u = enb::get_instance();
u->handle_rf_msg(error);
}
void enb::handle_rf_msg(srslte_rf_error_t error)
{
if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
rf_metrics.rf_o++;
rf_metrics.rf_error = true;
rf_log.warning("Overflow\n");
}else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) {
rf_metrics.rf_u++;
rf_metrics.rf_error = true;
rf_log.warning("Underflow\n");
} else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) {
rf_metrics.rf_l++;
rf_metrics.rf_error = true;
rf_log.warning("Late\n");
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) {
std::string str(error.msg);
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
str.push_back('\n');
rf_log.info("%s\n", str.c_str());
}
}
srslte::LOG_LEVEL_ENUM enb::level(std::string l)
{
boost::to_upper(l);

@ -19,10 +19,10 @@
*
*/
#include "enb_cfg_parser.h"
#include "srsenb/hdr/cfg_parser.h"
#include "srslte/phy/common/phy_common.h"
#include "srslte/srslte.h"
#include "enb_cfg_parser.h"
#include "srslte/asn1/rrc_asn1_utils.h"
using namespace asn1::rrc;
@ -31,10 +31,11 @@ namespace srsenb {
int enb::parse_cell_cfg(all_args_t* args, srslte_cell_t* cell)
{
cell->id = args->enb.pci;
cell->cp = SRSLTE_CP_NORM;
cell->nof_ports = args->enb.nof_ports;
cell->nof_prb = args->enb.n_prb;
cell->frame_type = SRSLTE_FDD;
cell->id = args->enb.pci;
cell->cp = SRSLTE_CP_NORM;
cell->nof_ports = args->enb.nof_ports;
cell->nof_prb = args->enb.n_prb;
phich_cfg_s phichcfg;
@ -49,7 +50,7 @@ int enb::parse_cell_cfg(all_args_t* args, srslte_cell_t* cell)
cell->phich_resources = (srslte_phich_r_t)(int)phichcfg.phich_res;
if (!srslte_cell_isvalid(cell)) {
fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args->enb.n_prb, args->enb.s1ap.cell_id);
fprintf(stderr, "Invalid cell parameters: nof_prb=%d, cell_id=%d\n", args->enb.n_prb, args->stack.s1ap.cell_id);
return -1;
}
@ -622,17 +623,17 @@ int enb::parse_sibs(all_args_t* args, rrc_cfg_t* rrc_cfg, phy_cfg_t* phy_config_
// Fill rest of data from enb config
sib_type1_s::cell_access_related_info_s_* cell_access = &sib1->cell_access_related_info;
cell_access->cell_id.from_number((args->enb.s1ap.enb_id << 8u) + args->enb.s1ap.cell_id);
cell_access->tac.from_number(args->enb.s1ap.tac);
sib1->freq_band_ind = (uint8_t)srslte_band_get_band(args->rf.dl_earfcn);
cell_access->cell_id.from_number((args->stack.s1ap.enb_id << 8u) + args->stack.s1ap.cell_id);
cell_access->tac.from_number(args->stack.s1ap.tac);
sib1->freq_band_ind = (uint8_t)srslte_band_get_band(args->enb.dl_earfcn);
std::string mnc_str;
if (not srslte::mnc_to_string(args->enb.s1ap.mnc, &mnc_str)) {
ERROR("The provided mnc=%d is not valid", args->enb.s1ap.mnc);
if (not srslte::mnc_to_string(args->stack.s1ap.mnc, &mnc_str)) {
ERROR("The provided mnc=%d is not valid", args->stack.s1ap.mnc);
return -1;
}
std::string mcc_str;
if (not srslte::mcc_to_string(args->enb.s1ap.mcc, &mcc_str)) {
ERROR("The provided mnc=%d is not valid", args->enb.s1ap.mcc);
if (not srslte::mcc_to_string(args->stack.s1ap.mcc, &mcc_str)) {
ERROR("The provided mnc=%d is not valid", args->stack.s1ap.mcc);
return -1;
}
cell_access->plmn_id_list.resize(1);
@ -656,7 +657,7 @@ int enb::parse_sibs(all_args_t* args, rrc_cfg_t* rrc_cfg, phy_cfg_t* phy_config_
asn1::number_to_enum(sib2->freq_info.ul_bw, args->enb.n_prb);
}
if (sib2->freq_info.ul_carrier_freq_present) {
sib2->freq_info.ul_carrier_freq = (uint16_t)args->rf.ul_earfcn;
sib2->freq_info.ul_carrier_freq = (uint16_t)args->enb.ul_earfcn;
}
// Update MBSFN list counter. Only 1 supported

@ -67,14 +67,14 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
common.add_options()
("enb.enb_id", bpo::value<string>(&enb_id)->default_value("0x0"), "eNodeB ID")
("enb.name", bpo::value<string>(&args->enb.s1ap.enb_name)->default_value("srsenb01"), "eNodeB Name")
("enb.name", bpo::value<string>(&args->stack.s1ap.enb_name)->default_value("srsenb01"), "eNodeB Name")
("enb.cell_id", bpo::value<string>(&cell_id)->default_value("0x0"), "Cell ID")
("enb.tac", bpo::value<string>(&tac)->default_value("0x0"), "Tracking Area Code")
("enb.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code")
("enb.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
("enb.mme_addr", bpo::value<string>(&args->enb.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connection")
("enb.gtp_bind_addr", bpo::value<string>(&args->enb.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection")
("enb.s1c_bind_addr", bpo::value<string>(&args->enb.s1ap.s1c_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection")
("enb.mme_addr", bpo::value<string>(&args->stack.s1ap.mme_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connection")
("enb.gtp_bind_addr", bpo::value<string>(&args->stack.s1ap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection")
("enb.s1c_bind_addr", bpo::value<string>(&args->stack.s1ap.s1c_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection")
("enb.phy_cell_id", bpo::value<uint32_t>(&args->enb.pci)->default_value(0), "Physical Cell Identity (PCI)")
("enb.n_prb", bpo::value<uint32_t>(&args->enb.n_prb)->default_value(25), "Number of PRB")
("enb.nof_ports", bpo::value<uint32_t>(&args->enb.nof_ports)->default_value(1), "Number of ports")
@ -85,15 +85,15 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("enb_files.rr_config", bpo::value<string>(&args->enb_files.rr_config)->default_value("rr.conf"), "RR configuration files")
("enb_files.drb_config", bpo::value<string>(&args->enb_files.drb_config)->default_value("drb.conf"), "DRB configuration files")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->rf.dl_earfcn)->default_value(3400), "Downlink EARFCN")
("rf.ul_earfcn", bpo::value<uint32_t>(&args->rf.ul_earfcn)->default_value(0), "Uplink EARFCN (Default based on Downlink EARFCN)")
("rf.dl_earfcn", bpo::value<uint32_t>(&args->enb.dl_earfcn)->default_value(3400), "Downlink EARFCN")
("rf.ul_earfcn", bpo::value<uint32_t>(&args->enb.ul_earfcn)->default_value(0), "Uplink EARFCN (Default based on Downlink EARFCN)")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(50), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(70), "Front-end transmitter gain")
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)")
("rf.ul_freq", bpo::value<float>(&args->rf.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)")
("rf.device_name", bpo::value<string>(&args->rf.device_name)->default_value("auto"), "Front-end device name")
("rf.device_args", bpo::value<string>(&args->rf.device_args)->default_value("auto"), "Front-end device arguments")
("rf.device_args", bpo::value<string>(&args->rf.device_args[0])->default_value("auto"), "Front-end device arguments")
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"), "Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
@ -105,18 +105,18 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("log.phy_level", bpo::value<string>(&args->log.phy_level), "PHY log level")
("log.phy_hex_limit", bpo::value<int>(&args->log.phy_hex_limit), "PHY log hex dump limit")
("log.phy_lib_level", bpo::value<string>(&args->log.phy_lib_level)->default_value("none"), "PHY lib log level")
("log.mac_level", bpo::value<string>(&args->log.mac_level), "MAC log level")
("log.mac_hex_limit", bpo::value<int>(&args->log.mac_hex_limit), "MAC log hex dump limit")
("log.rlc_level", bpo::value<string>(&args->log.rlc_level), "RLC log level")
("log.rlc_hex_limit", bpo::value<int>(&args->log.rlc_hex_limit), "RLC log hex dump limit")
("log.pdcp_level", bpo::value<string>(&args->log.pdcp_level), "PDCP log level")
("log.pdcp_hex_limit",bpo::value<int>(&args->log.pdcp_hex_limit), "PDCP log hex dump limit")
("log.rrc_level", bpo::value<string>(&args->log.rrc_level), "RRC log level")
("log.rrc_hex_limit", bpo::value<int>(&args->log.rrc_hex_limit), "RRC log hex dump limit")
("log.gtpu_level", bpo::value<string>(&args->log.gtpu_level), "GTPU log level")
("log.gtpu_hex_limit",bpo::value<int>(&args->log.gtpu_hex_limit), "GTPU log hex dump limit")
("log.s1ap_level", bpo::value<string>(&args->log.s1ap_level), "S1AP log level")
("log.s1ap_hex_limit",bpo::value<int>(&args->log.s1ap_hex_limit), "S1AP log hex dump limit")
("log.mac_level", bpo::value<string>(&args->stack.log.mac_level), "MAC log level")
("log.mac_hex_limit", bpo::value<int>(&args->stack.log.mac_hex_limit), "MAC log hex dump limit")
("log.rlc_level", bpo::value<string>(&args->stack.log.rlc_level), "RLC log level")
("log.rlc_hex_limit", bpo::value<int>(&args->stack.log.rlc_hex_limit), "RLC log hex dump limit")
("log.pdcp_level", bpo::value<string>(&args->stack.log.pdcp_level), "PDCP log level")
("log.pdcp_hex_limit",bpo::value<int>(&args->stack.log.pdcp_hex_limit), "PDCP log hex dump limit")
("log.rrc_level", bpo::value<string>(&args->stack.log.rrc_level), "RRC log level")
("log.rrc_hex_limit", bpo::value<int>(&args->stack.log.rrc_hex_limit), "RRC log hex dump limit")
("log.gtpu_level", bpo::value<string>(&args->stack.log.gtpu_level), "GTPU log level")
("log.gtpu_hex_limit",bpo::value<int>(&args->stack.log.gtpu_hex_limit), "GTPU log hex dump limit")
("log.s1ap_level", bpo::value<string>(&args->stack.log.s1ap_level), "S1AP log level")
("log.s1ap_hex_limit",bpo::value<int>(&args->stack.log.s1ap_hex_limit), "S1AP log hex dump limit")
("log.all_level", bpo::value<string>(&args->log.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit")
@ -125,11 +125,11 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("log.file_max_size", bpo::value<int>(&args->log.file_max_size)->default_value(-1), "Maximum file size (in kilobytes). When passed, multiple files are created. Default -1 (single file)")
/* MCS section */
("scheduler.pdsch_mcs", bpo::value<int>(&args->expert.mac.sched.pdsch_mcs)->default_value(-1), "Optional fixed PDSCH MCS (ignores reported CQIs if specified)")
("scheduler.pdsch_max_mcs", bpo::value<int>(&args->expert.mac.sched.pdsch_max_mcs)->default_value(-1), "Optional PDSCH MCS limit")
("scheduler.pusch_mcs", bpo::value<int>(&args->expert.mac.sched.pusch_mcs)->default_value(-1), "Optional fixed PUSCH MCS (ignores reported CQIs if specified)")
("scheduler.pusch_max_mcs", bpo::value<int>(&args->expert.mac.sched.pusch_max_mcs)->default_value(-1), "Optional PUSCH MCS limit")
("scheduler.nof_ctrl_symbols", bpo::value<int>(&args->expert.mac.sched.nof_ctrl_symbols)->default_value(3), "Number of control symbols")
("scheduler.pdsch_mcs", bpo::value<int>(&args->stack.mac.sched.pdsch_mcs)->default_value(-1), "Optional fixed PDSCH MCS (ignores reported CQIs if specified)")
("scheduler.pdsch_max_mcs", bpo::value<int>(&args->stack.mac.sched.pdsch_max_mcs)->default_value(-1), "Optional PDSCH MCS limit")
("scheduler.pusch_mcs", bpo::value<int>(&args->stack.mac.sched.pusch_mcs)->default_value(-1), "Optional fixed PUSCH MCS (ignores reported CQIs if specified)")
("scheduler.pusch_max_mcs", bpo::value<int>(&args->stack.mac.sched.pusch_max_mcs)->default_value(-1), "Optional PUSCH MCS limit")
("scheduler.nof_ctrl_symbols", bpo::value<int>(&args->stack.mac.sched.nof_ctrl_symbols)->default_value(3), "Number of control symbols")
/* Expert section */
("expert.metrics_period_secs", bpo::value<float>(&args->expert.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds")
@ -140,7 +140,7 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
("expert.pusch_8bit_decoder", bpo::value<bool>(&args->expert.phy.pusch_8bit_decoder)->default_value(false), "Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)")
("expert.tx_amplitude", bpo::value<float>(&args->expert.phy.tx_amplitude)->default_value(0.6), "Transmit amplitude factor")
("expert.nof_phy_threads", bpo::value<int>(&args->expert.phy.nof_phy_threads)->default_value(3), "Number of PHY threads")
("expert.link_failure_nof_err", bpo::value<int>(&args->expert.mac.link_failure_nof_err)->default_value(100), "Number of PUSCH failures after which a radio-link failure is triggered")
("expert.link_failure_nof_err", bpo::value<int>(&args->stack.mac.link_failure_nof_err)->default_value(100), "Number of PUSCH failures after which a radio-link failure is triggered")
("expert.max_prach_offset_us", bpo::value<float>(&args->expert.phy.max_prach_offset_us)->default_value(30), "Maximum allowed RACH offset (in us)")
("expert.equalizer_mode", bpo::value<string>(&args->expert.phy.equalizer_mode)->default_value("mmse"), "Equalizer mode")
("expert.estimator_fil_w", bpo::value<float>(&args->expert.phy.estimator_fil_w)->default_value(0.1), "Chooses the coefficients for the 3-tap channel estimator centered filter.")
@ -220,53 +220,53 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
{
std::stringstream sstr;
sstr << std::hex << vm["enb.enb_id"].as<std::string>();
sstr >> args->enb.s1ap.enb_id;
sstr >> args->stack.s1ap.enb_id;
}
{
std::stringstream sstr;
sstr << std::hex << vm["enb.cell_id"].as<std::string>();
uint16_t tmp; // Need intermediate uint16_t as uint8_t is treated as char
sstr >> tmp;
args->enb.s1ap.cell_id = tmp;
args->stack.s1ap.cell_id = tmp;
}
{
std::stringstream sstr;
sstr << std::hex << vm["enb.tac"].as<std::string>();
sstr >> args->enb.s1ap.tac;
sstr >> args->stack.s1ap.tac;
}
// Convert MCC/MNC strings
if(!srslte::string_to_mcc(mcc, &args->enb.s1ap.mcc)) {
if (!srslte::string_to_mcc(mcc, &args->stack.s1ap.mcc)) {
cout << "Error parsing enb.mcc:" << mcc << " - must be a 3-digit string." << endl;
}
if(!srslte::string_to_mnc(mnc, &args->enb.s1ap.mnc)) {
if (!srslte::string_to_mnc(mnc, &args->stack.s1ap.mnc)) {
cout << "Error parsing enb.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
// Convert UL/DL EARFCN to frequency if needed
if (args->rf.dl_freq < 0) {
args->rf.dl_freq = 1e6 * srslte_band_fd(args->rf.dl_earfcn);
args->rf.dl_freq = 1e6 * srslte_band_fd(args->enb.dl_earfcn);
if (args->rf.dl_freq < 0) {
fprintf(stderr, "Error getting DL frequency for EARFCN=%d\n", args->rf.dl_earfcn);
fprintf(stderr, "Error getting DL frequency for EARFCN=%d\n", args->enb.dl_earfcn);
exit(1);
}
}
if (args->rf.ul_freq < 0) {
if (args->rf.ul_earfcn == 0) {
args->rf.ul_earfcn = srslte_band_ul_earfcn(args->rf.dl_earfcn);
if (args->enb.ul_earfcn == 0) {
args->enb.ul_earfcn = srslte_band_ul_earfcn(args->enb.dl_earfcn);
}
args->rf.ul_freq = 1e6 * srslte_band_fu(args->rf.ul_earfcn);
args->rf.ul_freq = 1e6 * srslte_band_fu(args->enb.ul_earfcn);
if (args->rf.ul_freq < 0) {
fprintf(stderr, "Error getting UL frequency for EARFCN=%d\n", args->rf.dl_earfcn);
fprintf(stderr, "Error getting UL frequency for EARFCN=%d\n", args->enb.dl_earfcn);
exit(1);
}
}
if (args->expert.enable_mbsfn) {
if (args->expert.mac.sched.nof_ctrl_symbols == 3) {
if (args->stack.mac.sched.nof_ctrl_symbols == 3) {
fprintf(stderr,
"nof_ctrl_symbols = %d, While using MBMS, please set number of control symbols to either 1 or 2, "
"depending on the length of the non-mbsfn region\n",
args->expert.mac.sched.nof_ctrl_symbols);
args->stack.mac.sched.nof_ctrl_symbols);
exit(1);
}
}
@ -280,22 +280,22 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
args->log.phy_lib_level = args->log.all_level;
}
if(!vm.count("log.mac_level")) {
args->log.mac_level = args->log.all_level;
args->stack.log.mac_level = args->log.all_level;
}
if(!vm.count("log.rlc_level")) {
args->log.rlc_level = args->log.all_level;
args->stack.log.rlc_level = args->log.all_level;
}
if(!vm.count("log.pdcp_level")) {
args->log.pdcp_level = args->log.all_level;
args->stack.log.pdcp_level = args->log.all_level;
}
if(!vm.count("log.rrc_level")) {
args->log.rrc_level = args->log.all_level;
args->stack.log.rrc_level = args->log.all_level;
}
if(!vm.count("log.gtpu_level")) {
args->log.gtpu_level = args->log.all_level;
args->stack.log.gtpu_level = args->log.all_level;
}
if(!vm.count("log.s1ap_level")) {
args->log.s1ap_level = args->log.all_level;
args->stack.log.s1ap_level = args->log.all_level;
}
}
@ -305,22 +305,22 @@ void parse_args(all_args_t *args, int argc, char* argv[]) {
args->log.phy_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.mac_hex_limit")) {
args->log.mac_hex_limit = args->log.all_hex_limit;
args->stack.log.mac_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.rlc_hex_limit")) {
args->log.rlc_hex_limit = args->log.all_hex_limit;
args->stack.log.rlc_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.pdcp_hex_limit")) {
args->log.pdcp_hex_limit = args->log.all_hex_limit;
args->stack.log.pdcp_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.rrc_hex_limit")) {
args->log.rrc_hex_limit = args->log.all_hex_limit;
args->stack.log.rrc_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.gtpu_hex_limit")) {
args->log.gtpu_hex_limit = args->log.all_hex_limit;
args->stack.log.gtpu_hex_limit = args->log.all_hex_limit;
}
if(!vm.count("log.s1ap_hex_limit")) {
args->log.s1ap_hex_limit = args->log.all_hex_limit;
args->stack.log.s1ap_hex_limit = args->log.all_hex_limit;
}
}
@ -383,7 +383,7 @@ int main(int argc, char *argv[])
{
signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler);
all_args_t args;
all_args_t args = {};
srslte::metrics_hub<enb_metrics_t> metricshub;
metrics_stdout metrics_screen;
@ -394,8 +394,9 @@ int main(int argc, char *argv[])
cout << "--- Software Radio Systems LTE eNodeB ---" << endl << endl;
parse_args(&args, argc, argv);
if(!enb->init(&args)) {
exit(1);
if (enb->init(args)) {
enb->stop();
return SRSLTE_ERROR;
}
metricshub.init(enb, args.expert.metrics_period_secs);
@ -412,12 +413,10 @@ int main(int argc, char *argv[])
pthread_t input;
pthread_create(&input, NULL, &input_loop, &metrics_screen);
bool plot_started = false;
bool signals_pregenerated = false;
if(running) {
if (!plot_started && args.gui.enable) {
if (running) {
if (args.gui.enable) {
enb->start_plot();
plot_started = true;
}
}
int cnt=0;
@ -436,5 +435,6 @@ int main(int argc, char *argv[])
enb->stop();
enb->cleanup();
cout << "--- exiting ---" << endl;
exit(0);
return SRSLTE_SUCCESS;
}

@ -41,121 +41,137 @@ using namespace asn1::rrc;
namespace srsenb {
phy::phy() : workers_pool(MAX_WORKERS),
workers(MAX_WORKERS),
workers_common(MAX_WORKERS),
nof_workers(0)
phy::phy(srslte::logger* logger_) :
logger(logger_),
workers_pool(MAX_WORKERS),
workers(MAX_WORKERS),
workers_common(MAX_WORKERS),
nof_workers(0)
{
radio_handler = NULL;
bzero(&prach_cfg, sizeof(prach_cfg));
}
void phy::parse_config(phy_cfg_t* cfg)
phy::~phy()
{
stop();
}
void phy::parse_config(const phy_cfg_t& cfg)
{
// PRACH configuration
ZERO_OBJECT(prach_cfg);
prach_cfg.config_idx = cfg->prach_cnfg.prach_cfg_info.prach_cfg_idx;
prach_cfg.hs_flag = cfg->prach_cnfg.prach_cfg_info.high_speed_flag;
prach_cfg.root_seq_idx = cfg->prach_cnfg.root_seq_idx;
prach_cfg.zero_corr_zone = cfg->prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg;
prach_cfg.freq_offset = cfg->prach_cnfg.prach_cfg_info.prach_freq_offset;
prach_cfg.config_idx = cfg.prach_cnfg.prach_cfg_info.prach_cfg_idx;
prach_cfg.hs_flag = cfg.prach_cnfg.prach_cfg_info.high_speed_flag;
prach_cfg.root_seq_idx = cfg.prach_cnfg.root_seq_idx;
prach_cfg.zero_corr_zone = cfg.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg;
prach_cfg.freq_offset = cfg.prach_cnfg.prach_cfg_info.prach_freq_offset;
// Uplink Physical common configuration
ZERO_OBJECT(workers_common.ul_cfg_com);
// DMRS
workers_common.ul_cfg_com.dmrs.cyclic_shift = cfg->pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift;
workers_common.ul_cfg_com.dmrs.delta_ss = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch;
workers_common.ul_cfg_com.dmrs.group_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled;
workers_common.ul_cfg_com.dmrs.sequence_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled;
workers_common.ul_cfg_com.dmrs.cyclic_shift = cfg.pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift;
workers_common.ul_cfg_com.dmrs.delta_ss = cfg.pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch;
workers_common.ul_cfg_com.dmrs.group_hopping_en = cfg.pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled;
workers_common.ul_cfg_com.dmrs.sequence_hopping_en = cfg.pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled;
// Hopping
workers_common.ul_cfg_com.hopping.hop_mode =
cfg->pusch_cnfg.pusch_cfg_basic.hop_mode ==
cfg.pusch_cnfg.pusch_cfg_basic.hop_mode ==
asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame
? srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTRA_SF
: srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTER_SF;
;
workers_common.ul_cfg_com.hopping.n_sb = cfg->pusch_cnfg.pusch_cfg_basic.n_sb;
workers_common.ul_cfg_com.hopping.hopping_offset = cfg->pusch_cnfg.pusch_cfg_basic.pusch_hop_offset;
workers_common.ul_cfg_com.hopping.n_sb = cfg.pusch_cnfg.pusch_cfg_basic.n_sb;
workers_common.ul_cfg_com.hopping.hopping_offset = cfg.pusch_cnfg.pusch_cfg_basic.pusch_hop_offset;
workers_common.ul_cfg_com.pusch.max_nof_iterations = workers_common.params.pusch_max_its;
workers_common.ul_cfg_com.pusch.csi_enable = false;
workers_common.ul_cfg_com.pusch.meas_time_en = true;
// PUCCH
workers_common.ul_cfg_com.pucch.delta_pucch_shift = cfg->pucch_cnfg.delta_pucch_shift.to_number();
workers_common.ul_cfg_com.pucch.N_cs = cfg->pucch_cnfg.n_cs_an;
workers_common.ul_cfg_com.pucch.n_rb_2 = cfg->pucch_cnfg.n_rb_cqi;
workers_common.ul_cfg_com.pucch.N_pucch_1 = cfg->pucch_cnfg.n1_pucch_an;
workers_common.ul_cfg_com.pucch.delta_pucch_shift = cfg.pucch_cnfg.delta_pucch_shift.to_number();
workers_common.ul_cfg_com.pucch.N_cs = cfg.pucch_cnfg.n_cs_an;
workers_common.ul_cfg_com.pucch.n_rb_2 = cfg.pucch_cnfg.n_rb_cqi;
workers_common.ul_cfg_com.pucch.N_pucch_1 = cfg.pucch_cnfg.n1_pucch_an;
workers_common.ul_cfg_com.pucch.threshold_format1 = 0.8;
// PDSCH configuration
ZERO_OBJECT(workers_common.dl_cfg_com);
workers_common.dl_cfg_com.tm = SRSLTE_TM1;
workers_common.dl_cfg_com.pdsch.rs_power = cfg->pdsch_cnfg.ref_sig_pwr;
workers_common.dl_cfg_com.pdsch.p_b = cfg->pdsch_cnfg.p_b;
workers_common.dl_cfg_com.pdsch.rs_power = cfg.pdsch_cnfg.ref_sig_pwr;
workers_common.dl_cfg_com.pdsch.p_b = cfg.pdsch_cnfg.p_b;
workers_common.dl_cfg_com.pdsch.meas_time_en = true;
}
bool phy::init(phy_args_t* args,
phy_cfg_t* cfg,
srslte::radio* radio_handler_,
stack_interface_phy_lte* stack_,
srslte::log_filter* log_h)
int phy::init(const phy_args_t& args,
const phy_cfg_t& cfg,
srslte::radio_interface_phy* radio_,
stack_interface_phy_lte* stack_)
{
mlockall(MCL_CURRENT | MCL_FUTURE);
std::vector<srslte::log_filter*> log_vec;
this->log_h = log_h;
for (int i=0;i<args->nof_phy_threads;i++) {
log_vec.push_back(log_h);
// Create array of pointers to phy_logs
for (int i = 0; i < args.nof_phy_threads; i++) {
auto mylog = std::unique_ptr<srslte::log_filter>(new srslte::log_filter);
char tmp[16] = {};
sprintf(tmp, "PHY%d", i);
mylog->init(tmp, logger, true);
mylog->set_level(args.log.phy_level);
mylog->set_hex_limit(args.log.phy_hex_limit);
log_vec.push_back(std::move(mylog));
}
init(args, cfg, radio_handler_, stack_, log_vec);
return true;
}
bool phy::init(phy_args_t* args,
phy_cfg_t* cfg,
srslte::radio* radio_handler_,
stack_interface_phy_lte* stack_,
std::vector<srslte::log_filter*> log_vec)
{
// Add PHY lib log
if (log_vec.at(0)->get_level_from_string(args.log.phy_lib_level) != srslte::LOG_LEVEL_NONE) {
auto lib_log = std::unique_ptr<srslte::log_filter>(new srslte::log_filter);
char tmp[16] = {};
sprintf(tmp, "PHY_LIB");
lib_log->init(tmp, logger, true);
lib_log->set_level(args.log.phy_lib_level);
lib_log->set_hex_limit(args.log.phy_hex_limit);
log_vec.push_back(std::move(lib_log));
} else {
log_vec.push_back(nullptr);
}
mlockall(MCL_CURRENT | MCL_FUTURE);
radio = radio_;
nof_workers = args.nof_phy_threads;
radio_handler = radio_handler_;
nof_workers = args->nof_phy_threads;
this->log_h = (srslte::log*)log_vec[0];
workers_common.params = *args;
workers_common.params = args;
workers_common.init(&cfg->cell, radio_handler, stack_);
workers_common.init(cfg.cell, radio, stack_);
parse_config(cfg);
// Add workers to workers pool and start threads
for (uint32_t i=0;i<nof_workers;i++) {
workers[i].init(&workers_common, (srslte::log*) log_vec[i]);
workers[i].init(&workers_common, log_vec.at(i).get());
workers_pool.init_worker(i, &workers[i], WORKERS_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.init(cfg.cell, prach_cfg, stack_, log_vec.at(0).get(), PRACH_WORKER_THREAD_PRIO);
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
tx_rx.init(radio_handler, &workers_pool, &workers_common, &prach, (srslte::log*) log_vec[0], SF_RECV_THREAD_PRIO);
tx_rx.init(radio, &workers_pool, &workers_common, &prach, log_vec.at(0).get(), SF_RECV_THREAD_PRIO);
initialized = true;
return true;
return SRSLTE_SUCCESS;
}
void phy::stop()
{
tx_rx.stop();
for (uint32_t i=0;i<nof_workers;i++) {
workers[i].stop();
if (initialized) {
tx_rx.stop();
for (uint32_t i = 0; i < nof_workers; i++) {
workers[i].stop();
}
workers_common.stop();
workers_pool.stop();
prach.stop();
initialized = false;
}
workers_common.stop();
workers_pool.stop();
prach.stop();
}
uint32_t phy::tti_to_SFN(uint32_t tti) {

@ -75,11 +75,13 @@ void phy_common::reset()
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_, stack_interface_phy_lte* stack_)
bool phy_common::init(const srslte_cell_t& cell_,
srslte::radio_interface_phy* radio_h_,
stack_interface_phy_lte* stack_)
{
radio = radio_h_;
stack = stack_;
memcpy(&cell, cell_, sizeof(srslte_cell_t));
cell = cell_;
pthread_mutex_init(&user_mutex, NULL);
pthread_mutex_init(&mtch_mutex, NULL);
@ -122,8 +124,8 @@ void phy_common::worker_end(uint32_t tti,
// Wait for the green light to transmit in the current TTI
sem_wait(&tx_sem[tti%nof_workers]);
radio->set_tti(tti);
radio->tx(buffer, nof_samples, tx_time);
// always transmit on single radio
radio->tx(0, buffer, nof_samples, tx_time);
// Allow next TTI to transmit
sem_post(&tx_sem[(tti+1)%nof_workers]);

@ -24,16 +24,16 @@
namespace srsenb {
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)
int prach_worker::init(const srslte_cell_t& cell_,
const srslte_prach_cfg_t& prach_cfg_,
stack_interface_phy_lte* stack_,
srslte::log* log_h_,
int priority)
{
log_h = log_h_;
stack = stack_;
memcpy(&prach_cfg, prach_cfg_, sizeof(srslte_prach_cfg_t));
memcpy(&cell, cell_, sizeof(srslte_cell_t));
prach_cfg = prach_cfg_;
cell = cell_;
max_prach_offset_us = 50;

@ -19,10 +19,9 @@
*
*/
#include <assert.h>
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/srslte.h"
#include "srsenb/hdr/phy/sf_worker.h"

@ -21,8 +21,9 @@
#include <unistd.h>
#include "srslte/common/threads.h"
#include "srslte/common/log.h"
#include "srslte/common/threads.h"
#include "srslte/srslte.h"
#include "srsenb/hdr/phy/sf_worker.h"
#include "srsenb/hdr/phy/txrx.h"
@ -47,12 +48,12 @@ txrx::txrx() : tx_worker_cnt(0), nof_workers(0), tti(0), thread("TXRX")
prach = NULL;
}
bool txrx::init(srslte::radio* radio_h_,
srslte::thread_pool* workers_pool_,
phy_common* worker_com_,
prach_worker* prach_,
srslte::log* log_h_,
uint32_t prio_)
bool txrx::init(srslte::radio_interface_phy* radio_h_,
srslte::thread_pool* workers_pool_,
phy_common* worker_com_,
prach_worker* prach_,
srslte::log* log_h_,
uint32_t prio_)
{
radio_h = radio_h_;
log_h = log_h_;
@ -86,17 +87,14 @@ void txrx::run_thread()
log_h->console("Setting Sampling frequency %.2f MHz\n", (float) samp_rate/1000000);
// Configure radio
radio_h->set_rx_srate(samp_rate);
radio_h->set_tx_srate(samp_rate);
radio_h->set_rx_srate(0, samp_rate);
radio_h->set_tx_srate(0, samp_rate);
log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n", worker_com->cell.nof_prb, sf_len);
// Set TTI so that first TX is at tti=0
tti = 10235;
log_h->console("\n==== eNodeB started ===\n");
log_h->console("Type <t> to view trace\n");
// Main loop
while (running) {
tti = (tti + 1) % 10240;
@ -106,7 +104,7 @@ void txrx::run_thread()
buffer[p] = worker->get_buffer_rx(p);
}
radio_h->rx_now(buffer, sf_len, &rx_time);
radio_h->rx_now(0, buffer, sf_len, &rx_time);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_copy(&tx_time, &rx_time);

@ -18,10 +18,6 @@
# and at http://www.gnu.org/licenses/.
#
set(SOURCES ue_radio.cc)
add_library(srsue_radio STATIC ${SOURCES})
target_link_libraries(srsue_radio srslte_radio)
install(TARGETS srsue_radio DESTINATION ${LIBRARY_DIR})
file(GLOB SOURCES "*.cc")
add_library(srsenb_radio STATIC ${SOURCES})
install(TARGETS srsenb_radio DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,48 @@
/*
* 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/radio/enb_radio_multi.h"
#include <mutex>
namespace srsenb {
enb_radio_multi::enb_radio_multi(srslte::logger* logger_) : radio_multi(logger_) {}
enb_radio_multi::~enb_radio_multi() {}
int enb_radio_multi::init(const srslte::rf_args_t& args_, srslte::phy_interface_radio* phy_)
{
int ret = radio_multi::init(args_, phy_);
if (ret == SRSLTE_SUCCESS) {
ret = SRSLTE_ERROR;
if (radios.size() > 0) {
log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args_.dl_freq / 1e6, args_.ul_freq / 1e6);
radios.at(0)->set_tx_freq(args.nof_tx_ports, args.dl_freq);
radios.at(0)->set_rx_freq(args.nof_tx_ports, args.ul_freq);
ret = SRSLTE_SUCCESS;
}
}
return ret;
}
} // namespace srsenb

@ -28,7 +28,7 @@ using namespace srslte;
namespace srsenb {
enb_stack_lte::enb_stack_lte() : args(), started(false), logger(nullptr), phy(nullptr), pdcp(&pdcp_log) {}
enb_stack_lte::enb_stack_lte(srslte::logger* logger_) : logger(logger_), pdcp(&pdcp_log) {}
enb_stack_lte::~enb_stack_lte()
{
@ -40,23 +40,19 @@ 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_)
int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_, phy_interface_stack_lte* phy_)
{
phy = phy_;
if (init(args_, rrc_cfg_, logger_)) {
if (init(args_, rrc_cfg_)) {
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int enb_stack_lte::init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::logger* logger_)
int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_)
{
args = args_;
rrc_cfg = rrc_cfg_;
logger = logger_;
// setup logging for each layer
mac_log.init("MAC ", logger, true);
@ -101,7 +97,7 @@ int enb_stack_lte::init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::
" Consider changing \"prach_freq_offset\" in sib.conf to a value between %d and %d.\n",
lower_bound,
upper_bound);
return false;
return SRSLTE_ERROR;
}
} else { // 6 PRB case
if (prach_freq_offset + 6 > cell_cfg.nof_prb) {
@ -113,18 +109,18 @@ int enb_stack_lte::init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::
fprintf(
stderr,
" Consider changing the \"prach_freq_offset\" value to 0 in the sib.conf file when using 6 PRBs.\n");
return false;
return SRSLTE_ERROR;
}
}
// Init all layers
mac.init(args.expert.mac, &cell_cfg, phy, &rlc, &rrc, &mac_log);
mac.init(args.mac, &cell_cfg, phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, &mac, &mac, &rlc_log);
pdcp.init(&rlc, &rrc, &gtpu);
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,
s1ap.init(args.s1ap, &rrc, &s1ap_log);
gtpu.init(args.s1ap.gtp_bind_addr,
args.s1ap.mme_addr,
args.expert.m1u_multiaddr,
args.expert.m1u_if_addr,
&pdcp,
@ -132,6 +128,7 @@ int enb_stack_lte::init(const args_t& args_, const rrc_cfg_t& rrc_cfg_, srslte::
args.expert.enable_mbsfn);
started = true;
return SRSLTE_SUCCESS;
}

@ -63,7 +63,7 @@ mac::mac() : timers_db(128), timers_thread(&timers_db), tti(0), last_rnti(0),
mac::~mac()
{
pthread_rwlock_unlock(&rwlock);
stop();
pthread_rwlock_destroy(&rwlock);
}
@ -113,18 +113,20 @@ bool mac::init(const mac_args_t& args_,
void mac::stop()
{
pthread_rwlock_wrlock(&rwlock);
for (uint32_t i=0;i<ue_db.size();i++) {
delete ue_db[i];
}
for (int i=0;i<NOF_BCCH_DLSCH_MSG;i++) {
srslte_softbuffer_tx_free(&bcch_softbuffer_tx[i]);
if (started) {
for (uint32_t i = 0; i < ue_db.size(); i++) {
delete ue_db[i];
}
for (int i = 0; i < NOF_BCCH_DLSCH_MSG; i++) {
srslte_softbuffer_tx_free(&bcch_softbuffer_tx[i]);
}
srslte_softbuffer_tx_free(&pcch_softbuffer_tx);
srslte_softbuffer_tx_free(&rar_softbuffer_tx);
started = false;
timers_thread.stop();
pdu_process_thread.stop();
}
srslte_softbuffer_tx_free(&pcch_softbuffer_tx);
srslte_softbuffer_tx_free(&rar_softbuffer_tx);
started = false;
timers_thread.stop();
pdu_process_thread.stop();
pthread_rwlock_unlock(&rwlock);
}
// Implement Section 5.9

@ -79,7 +79,6 @@ void s1ap::stop()
if(close(socket_fd) == -1) {
s1ap_log->error("Failed to close SCTP socket\n");
}
return;
}
void s1ap::get_metrics(s1ap_metrics_t &m)
@ -145,6 +144,7 @@ void s1ap::run_thread()
s1ap_log->info_hex(pdu->msg, pdu->N_bytes, "Received S1AP PDU");
handle_s1ap_rx_pdu(pdu.get());
}
printf("%s ended\n", __PRETTY_FUNCTION__);
}
// Generate common S1AP protocol IEs from config args

@ -22,13 +22,14 @@
#ifndef SRSUE_PHY_H
#define SRSUE_PHY_H
#include "scell/async_scell_recv.h"
#include "phy_common.h"
#include "phy_metrics.h"
#include "prach.h"
#include "scell/async_scell_recv.h"
#include "sf_worker.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/trace.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h"
#include "srslte/srslte.h"
@ -49,10 +50,10 @@ public:
int init(const phy_args_t& args_, srslte::logger* logger_) final;
// Init for LTE PHYs
int init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
radio_interface_phy* radio_) final;
int init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
srslte::radio_interface_phy* radio_) final;
void stop() final;
@ -142,7 +143,7 @@ private:
const static int SF_RECV_THREAD_PRIO = 1;
const static int WORKERS_THREAD_PRIO = 2;
radio_interface_phy* radio = nullptr;
srslte::radio_interface_phy* radio = nullptr;
std::vector<std::unique_ptr<srslte::log_filter> > log_vec;
srslte::logger* logger = nullptr;

@ -27,6 +27,7 @@
#include "phy_metrics.h"
#include "srslte/common/gen_mch_tables.h"
#include "srslte/common/log.h"
#include "srslte/interfaces/common_interfaces.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h"
#include "srslte/srslte.h"
@ -94,7 +95,7 @@ public:
~phy_common();
void init(phy_args_t* args, srslte::log* _log, radio_interface_phy* _radio, stack_interface_phy_lte* _stack);
void init(phy_args_t* args, srslte::log* _log, srslte::radio_interface_phy* _radio, stack_interface_phy_lte* _stack);
uint32_t ul_pidof(uint32_t tti, srslte_tdd_config_t* tdd_config);
@ -141,7 +142,7 @@ public:
bool sr_enabled;
int sr_last_tx_tti;
radio_interface_phy* get_radio();
srslte::radio_interface_phy* get_radio();
void set_cell(const srslte_cell_t& c);
uint32_t get_nof_prb();
@ -174,7 +175,7 @@ private:
uint32_t max_workers;
bool is_first_of_burst[SRSLTE_MAX_RADIOS];
radio_interface_phy* radio_h;
srslte::radio_interface_phy* radio_h;
float cfo;
srslte::log* log_h;
srslte::channel_ptr ul_channel = nullptr;

@ -38,7 +38,7 @@ public:
async_scell_recv();
~async_scell_recv();
void init(radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h);
void init(srslte::radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h);
void stop();
// from chest_feedback_itf
@ -141,7 +141,7 @@ private:
// Pointers to other classes
srslte::log* log_h;
radio_interface_phy* radio_h;
srslte::radio_interface_phy* radio_h;
phy_common* worker_com;
// pthread objects

@ -48,63 +48,63 @@ typedef _Complex float cf_t;
class sync : public thread, public chest_feedback_itf
{
public:
sync() : thread("SYNC") {};
sync() : thread("SYNC"){};
~sync();
void init(radio_interface_phy* radio_,
stack_interface_phy_lte* _stack,
prach* prach_buffer,
srslte::thread_pool* _workers_pool,
phy_common* _worker_com,
srslte::log* _log_h,
srslte::log* _log_phy_lib_h,
scell::async_recv_vector* scell_sync_,
uint32_t prio,
int sync_cpu_affinity = -1);
void init(srslte::radio_interface_phy* radio_,
stack_interface_phy_lte* _stack,
prach* prach_buffer,
srslte::thread_pool* _workers_pool,
phy_common* _worker_com,
srslte::log* _log_h,
srslte::log* _log_phy_lib_h,
scell::async_recv_vector* scell_sync_,
uint32_t prio,
int sync_cpu_affinity = -1);
void stop();
void radio_overflow();
// RRC interface for controling the SYNC state
phy_interface_rrc_lte::cell_search_ret_t cell_search(phy_interface_rrc_lte::phy_cell_t* cell);
bool cell_select(phy_interface_rrc_lte::phy_cell_t* cell);
bool cell_is_camping();
bool cell_is_camping();
// RRC interface for controlling the neighbour cell measurement
void meas_reset();
int meas_start(uint32_t earfcn, int pci);
int meas_stop(uint32_t earfcn, int pci);
void meas_reset();
int meas_start(uint32_t earfcn, int pci);
int meas_stop(uint32_t earfcn, int pci);
// from chest_feedback_itf
void in_sync() final;
void out_of_sync() final;
void set_cfo(float cfo) final;
void set_time_adv_sec(float time_adv_sec);
void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t* cell, uint32_t* earfcn = nullptr);
uint32_t get_current_tti();
// From UE configuration
void set_agc_enable(bool enable);
void set_earfcn(std::vector<uint32_t> earfcn);
void force_freq(float dl_freq, float ul_freq);
void set_agc_enable(bool enable);
void set_earfcn(std::vector<uint32_t> earfcn);
void force_freq(float dl_freq, float ul_freq);
// Other functions
double set_rx_gain(double gain);
int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
int radio_recv_fnc(cf_t* data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t* rx_time);
private:
// Class to run cell search
class search {
class search
{
public:
typedef enum {CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT} ret_code;
typedef enum { CELL_NOT_FOUND, CELL_FOUND, ERROR, TIMEOUT } ret_code;
~search();
void init(cf_t* buffer[SRSLTE_MAX_PORTS], srslte::log* log_h, uint32_t nof_rx_antennas, sync* parent);
void reset();
float get_last_cfo();
void set_agc_enable(bool enable);
ret_code run(srslte_cell_t *cell);
ret_code run(srslte_cell_t* cell);
private:
sync* p = nullptr;
@ -116,9 +116,10 @@ private:
};
// Class to synchronize system frame number
class sfn_sync {
class sfn_sync
{
public:
typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR} ret_code;
typedef enum { IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR } ret_code;
sfn_sync() = default;
~sfn_sync();
void init(srslte_ue_sync_t* ue_sync,
@ -127,7 +128,7 @@ private:
uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES);
void reset();
bool set_cell(srslte_cell_t cell);
ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false);
ret_code run_subframe(srslte_cell_t* cell, uint32_t* tti_cnt, bool sfidx_only = false);
ret_code
decode_mib(srslte_cell_t* cell, uint32_t* tti_cnt, cf_t* ext_buffer[SRSLTE_MAX_PORTS], bool sfidx_only = false);
@ -148,39 +149,39 @@ private:
std::vector<uint32_t> earfcn;
void reset();
void radio_error();
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
void run_thread() final;
float get_tx_cfo();
void reset();
void radio_error();
void set_ue_sync_opts(srslte_ue_sync_t* q, float cfo);
void run_thread() final;
float get_tx_cfo();
void set_sampling_rate();
bool set_frequency();
bool set_cell();
void set_sampling_rate();
bool set_frequency();
bool set_cell();
bool radio_is_overflow = false;
bool radio_overflow_return = false;
bool running = false;
// Objects for internal use
search search_p;
sfn_sync sfn_p;
scell::intra_measure intra_freq_meas;
search search_p;
sfn_sync sfn_p;
scell::intra_measure intra_freq_meas;
uint32_t current_sflen = 0;
int next_offset = 0; // Sample offset triggered by Time aligment commands
int next_radio_offset[SRSLTE_MAX_RADIOS] = {}; // Sample offset triggered by SFO compensation
// Pointers to other classes
stack_interface_phy_lte* stack = nullptr;
srslte::log* log_h = nullptr;
srslte::log* log_phy_lib_h = nullptr;
srslte::thread_pool* workers_pool = nullptr;
radio_interface_phy* radio_h = nullptr;
phy_common* worker_com = nullptr;
prach* prach_buffer = nullptr;
scell::async_recv_vector* scell_sync = nullptr;
srslte::channel_ptr channel_emulator = nullptr;
stack_interface_phy_lte* stack = nullptr;
srslte::log* log_h = nullptr;
srslte::log* log_phy_lib_h = nullptr;
srslte::thread_pool* workers_pool = nullptr;
srslte::radio_interface_phy* radio_h = nullptr;
phy_common* worker_com = nullptr;
prach* prach_buffer = nullptr;
scell::async_recv_vector* scell_sync = nullptr;
srslte::channel_ptr channel_emulator = nullptr;
// Object for synchronization of the primary cell
srslte_ue_sync_t ue_sync = {};
@ -199,8 +200,9 @@ private:
const static uint32_t NOF_IN_SYNC_SF = 10;
// State machine for SYNC thread
class sync_state {
public:
class sync_state
{
public:
typedef enum {
IDLE = 0,
CELL_SEARCH,
@ -211,7 +213,8 @@ private:
/* Run_state is called by the main thread at the start of each loop. It updates the state
* and returns the current state
*/
state_t run_state() {
state_t run_state()
{
std::lock_guard<std::mutex> lg(inside);
cur_state = next_state;
if (state_setting) {
@ -223,7 +226,8 @@ private:
}
// Called by the main thread at the end of each state to indicate it has finished.
void state_exit(bool exit_ok = true) {
void state_exit(bool exit_ok = true)
{
std::lock_guard<std::mutex> lg(inside);
if (cur_state == SFN_SYNC && exit_ok == true) {
next_state = CAMPING;
@ -233,7 +237,8 @@ private:
state_running = false;
cvar.notify_all();
}
void force_sfn_sync() {
void force_sfn_sync()
{
std::lock_guard<std::mutex> lg(inside);
next_state = SFN_SYNC;
}
@ -243,34 +248,33 @@ private:
*
* These functions are mutexed and only 1 can be called at a time
*/
void go_idle() {
void go_idle()
{
std::lock_guard<std::mutex> lg(outside);
go_state(IDLE);
}
void run_cell_search() {
void run_cell_search()
{
std::lock_guard<std::mutex> lg(outside);
go_state(CELL_SEARCH);
wait_state_run();
wait_state_next();
}
void run_sfn_sync() {
void run_sfn_sync()
{
std::lock_guard<std::mutex> lg(outside);
go_state(SFN_SYNC);
wait_state_run();
wait_state_next();
}
/* Helpers below this */
bool is_idle() {
return cur_state == IDLE;
}
bool is_camping() {
return cur_state == CAMPING;
}
bool is_idle() { return cur_state == IDLE; }
bool is_camping() { return cur_state == CAMPING; }
const char *to_string() {
switch(cur_state) {
const char* to_string()
{
switch (cur_state) {
case IDLE:
return "IDLE";
case CELL_SEARCH:
@ -287,11 +291,12 @@ private:
sync_state() = default;
private:
void go_state(state_t s) {
void go_state(state_t s)
{
std::unique_lock<std::mutex> ul(inside);
next_state = s;
next_state = s;
state_setting = true;
while(state_setting) {
while (state_setting) {
cvar.wait(ul);
}
}
@ -325,20 +330,18 @@ private:
sync_state phy_state;
search::ret_code cell_search_ret = search::CELL_NOT_FOUND;
search::ret_code cell_search_ret = search::CELL_NOT_FOUND;
// Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
enum {
SRATE_NONE=0, SRATE_FIND, SRATE_CAMP
} srate_mode = SRATE_NONE;
float current_srate = 0;
enum { SRATE_NONE = 0, SRATE_FIND, SRATE_CAMP } srate_mode = SRATE_NONE;
float current_srate = 0;
// This is the primary cell
srslte_cell_t cell = {};
bool started = false;
float time_adv_sec = 0;
srslte_cell_t cell = {};
bool started = false;
float time_adv_sec = 0;
float next_time_adv_sec = 0;
uint32_t tti = 0;
uint32_t tti = 0;
uint32_t tx_worker_cnt = 0;
uint32_t nof_workers = 0;

@ -31,7 +31,7 @@
namespace srsue {
class ue_lte_phy_base : public ue_phy_base, public phy_interface_stack_lte, public phy_interface_radio
class ue_lte_phy_base : public ue_phy_base, public phy_interface_stack_lte, public srslte::phy_interface_radio
{
public:
ue_lte_phy_base(){};
@ -40,10 +40,10 @@ public:
virtual std::string get_type() = 0;
virtual int init(const phy_args_t& args_, srslte::logger* logger_) = 0;
virtual int init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
radio_interface_phy* radio_) = 0;
virtual int init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
srslte::radio_interface_phy* radio_) = 0;
virtual void stop() = 0;
virtual void set_earfcn(std::vector<uint32_t> earfcns) = 0;

@ -30,8 +30,6 @@
#include "srslte/common/logger.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/phy/phy_metrics.h"
#include <memory>
#include <vector>
namespace srsue {

@ -28,17 +28,17 @@
#ifndef SRSUE_UE_H
#define SRSUE_UE_H
#include <pthread.h>
#include <stdarg.h>
#include <string>
#include <pthread.h>
#include "phy/ue_phy_base.h"
#include "radio/ue_radio_base.h"
#include "stack/ue_stack_base.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/logger_file.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio_base.h"
#include "stack/ue_stack_base.h"
#include "ue_metrics_interface.h"
@ -72,10 +72,10 @@ typedef struct {
} expert_args_t;
typedef struct {
rf_args_t rf;
trace_args_t trace;
log_args_t log;
gui_args_t gui;
srslte::rf_args_t rf;
trace_args_t trace;
log_args_t log;
gui_args_t gui;
phy_args_t phy;
stack_args_t stack;
@ -109,13 +109,13 @@ public:
private:
// UE consists of a radio, a PHY and a stack element
std::unique_ptr<ue_phy_base> phy;
std::unique_ptr<ue_radio_base> radio;
std::unique_ptr<srslte::radio_base> radio;
std::unique_ptr<ue_stack_base> stack;
std::unique_ptr<gw> gw_inst;
// Generic logger members
srslte::logger* logger = nullptr;
srslte::log_filter log; // Own logger for UE
srslte::logger* logger = nullptr;
srslte::log_filter log; // Own logger for UE
all_args_t args;
srslte::byte_buffer_pool* pool = nullptr;
@ -131,4 +131,3 @@ private:
} // namespace srsue
#endif // SRSUE_UE_H

@ -26,6 +26,7 @@
#include "phy/phy_metrics.h"
#include "srslte/common/metrics_hub.h"
#include "srslte/radio/radio_metrics.h"
#include "srslte/upper/rlc_metrics.h"
#include "stack/mac/mac_metrics.h"
#include "stack/upper/gw_metrics.h"
@ -33,13 +34,6 @@
namespace srsue {
typedef struct {
uint32_t rf_o;
uint32_t rf_u;
uint32_t rf_l;
bool rf_error;
} rf_metrics_t;
typedef struct {
mac_metrics_t mac[SRSLTE_MAX_CARRIERS];
srslte::rlc_metrics_t rlc;
@ -47,7 +41,7 @@ typedef struct {
} stack_metrics_t;
typedef struct {
rf_metrics_t rf;
srslte::rf_metrics_t rf;
phy_metrics_t phy;
gw_metrics_t gw;
stack_metrics_t stack;

@ -18,7 +18,6 @@
# and at http://www.gnu.org/licenses/.
#
add_subdirectory(radio)
add_subdirectory(phy)
add_subdirectory(stack)
@ -32,14 +31,14 @@ if (RPATH)
endif (RPATH)
add_executable(srsue main.cc ue.cc metrics_stdout.cc metrics_csv.cc)
target_link_libraries(srsue srsue_radio
srsue_phy
target_link_libraries(srsue srsue_phy
srsue_stack
srsue_upper
srsue_mac
srsue_rrc
srslte_common
srslte_phy
srslte_radio
srslte_upper
rrc_asn1
${CMAKE_THREAD_LIBS_INIT}

@ -101,10 +101,10 @@ bool phy::check_args(const phy_args_t& args)
return true;
}
int phy::init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
radio_interface_phy* radio_)
int phy::init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
srslte::radio_interface_phy* radio_)
{
stack = stack_;
radio = radio_;

@ -114,10 +114,10 @@ void phy_common::set_nof_workers(uint32_t nof_workers)
this->nof_workers = nof_workers;
}
void phy_common::init(phy_args_t* _args,
srslte::log* _log,
radio_interface_phy* _radio,
stack_interface_phy_lte* _stack)
void phy_common::init(phy_args_t* _args,
srslte::log* _log,
srslte::radio_interface_phy* _radio,
stack_interface_phy_lte* _stack)
{
log_h = _log;
radio_h = _radio;
@ -182,7 +182,7 @@ void phy_common::set_ue_ul_cfg(srslte_ue_ul_cfg_t* ue_ul_cfg)
ue_ul_cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL;
}
radio_interface_phy* phy_common::get_radio()
srslte::radio_interface_phy* phy_common::get_radio()
{
return radio_h;
}

@ -55,8 +55,8 @@ async_scell_recv::async_scell_recv() : thread("ASYNC_SCELL_RECV")
ul_freq = -1;
bzero(&cell, sizeof(srslte_cell_t));
bzero(sf_buffer, sizeof(sf_buffer));
running = false;
radio_idx = 1;
running = false;
radio_idx = 1;
current_sflen = 0;
next_radio_offset = 0;
}
@ -84,7 +84,7 @@ static double callback_set_rx_gain(void* h, double gain)
return ((async_scell_recv*)h)->set_rx_gain(gain);
}
void async_scell_recv::init(radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h)
void async_scell_recv::init(srslte::radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h)
{
// Get handlers
radio_h = _radio_handler;

@ -42,16 +42,16 @@ double callback_set_rx_gain(void *h, double gain) {
return ((sync*)h)->set_rx_gain(gain);
}
void sync::init(radio_interface_phy* _radio,
stack_interface_phy_lte* _stack,
prach* _prach_buffer,
srslte::thread_pool* _workers_pool,
phy_common* _worker_com,
srslte::log* _log_h,
srslte::log* _log_phy_lib_h,
scell::async_recv_vector* scell_sync_,
uint32_t prio,
int sync_cpu_affinity)
void sync::init(srslte::radio_interface_phy* _radio,
stack_interface_phy_lte* _stack,
prach* _prach_buffer,
srslte::thread_pool* _workers_pool,
phy_common* _worker_com,
srslte::log* _log_h,
srslte::log* _log_phy_lib_h,
scell::async_recv_vector* scell_sync_,
uint32_t prio,
int sync_cpu_affinity)
{
radio_h = _radio;
log_h = _log_h;

@ -21,9 +21,9 @@
#include "srsue/hdr/ue.h"
#include "srslte/build_info.h"
#include "srslte/radio/radio_multi.h"
#include "srslte/srslte.h"
#include "srsue/hdr/phy/phy.h"
#include "srsue/hdr/radio/ue_radio.h"
#include "srsue/hdr/stack/ue_stack_lte.h"
#include <algorithm>
#include <iostream>
@ -92,14 +92,14 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_)
return SRSLTE_ERROR;
}
std::unique_ptr<ue_radio> lte_radio = std::unique_ptr<ue_radio>(new ue_radio());
std::unique_ptr<radio_multi> lte_radio = std::unique_ptr<radio_multi>(new radio_multi(logger));
if (!lte_radio) {
log.console("Error creating radio multi instance.\n");
return SRSLTE_ERROR;
}
// init layers
if (lte_radio->init(args.rf, logger, lte_phy.get())) {
if (lte_radio->init(args.rf, lte_phy.get())) {
log.console("Error initializing radio.\n");
return SRSLTE_ERROR;
}

Loading…
Cancel
Save