introduce new UE layer design

- abstract UE object now consists of a radio, a PHY, and a stack layer
- add new stack abstraction layer that combines MAC, RLC, RRC, PDCP, NAS and GW
- PHY layer now has a single stack interface and does not talk to MAC and RRC seperatly
master
Andre Puschmann 6 years ago
parent 3a6dd9b164
commit 65f50cd7ba

@ -30,6 +30,7 @@
#ifndef SRSLTE_LOG_H #ifndef SRSLTE_LOG_H
#define SRSLTE_LOG_H #define SRSLTE_LOG_H
#include <algorithm>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
@ -99,6 +100,27 @@ public:
void set_level(LOG_LEVEL_ENUM l) { void set_level(LOG_LEVEL_ENUM l) {
level = l; level = l;
} }
void set_level(std::string l) { set_level(get_level_from_string(l)); }
srslte::LOG_LEVEL_ENUM get_level_from_string(std::string l)
{
std::transform(l.begin(), l.end(), l.begin(), ::toupper);
if ("NONE" == l) {
return srslte::LOG_LEVEL_NONE;
} else if ("ERROR" == l) {
return srslte::LOG_LEVEL_ERROR;
} else if ("WARNING" == l) {
return srslte::LOG_LEVEL_WARNING;
} else if ("INFO" == l) {
return srslte::LOG_LEVEL_INFO;
} else if ("DEBUG" == l) {
return srslte::LOG_LEVEL_DEBUG;
} else {
return srslte::LOG_LEVEL_NONE;
}
}
LOG_LEVEL_ENUM get_level() { LOG_LEVEL_ENUM get_level() {
return level; return level;
} }

@ -64,6 +64,8 @@ public:
void info_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); void info_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5)));
void debug_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5))); void debug_hex(const uint8_t *hex, int size, const char * message, ...) __attribute__((format (printf, 4, 5)));
srslte::LOG_LEVEL_ENUM get_level(std::string l);
class time_itf { class time_itf {
public: public:
virtual srslte_timestamp_t get_time() = 0; virtual srslte_timestamp_t get_time() = 0;

@ -39,7 +39,7 @@ template<typename metrics_t>
class metrics_interface class metrics_interface
{ {
public: public:
virtual bool get_metrics(metrics_t &m) = 0; virtual bool get_metrics(metrics_t* m) = 0;
}; };
template<typename metrics_t> template<typename metrics_t>
@ -84,7 +84,7 @@ private:
if (m) { if (m) {
metrics_t metric; metrics_t metric;
m->get_metrics(metric); m->get_metrics(&metric);
for (uint32_t i=0;i<listeners.size();i++) { for (uint32_t i=0;i<listeners.size();i++) {
listeners[i]->set_metrics(metric, period_usec.count()); listeners[i]->set_metrics(metric, period_usec.count());
} }

@ -30,6 +30,7 @@
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <sys/time.h>
#include <vector> #include <vector>
namespace srslte { namespace srslte {

@ -24,14 +24,14 @@
#include <stdint.h> #include <stdint.h>
#include "srslte/common/metrics_hub.h" #include "srsenb/hdr/mac/mac_metrics.h"
#include "srsenb/hdr/phy/phy_metrics.h"
#include "srsenb/hdr/upper/common_enb.h" #include "srsenb/hdr/upper/common_enb.h"
#include "srsenb/hdr/upper/s1ap_metrics.h"
#include "srsenb/hdr/upper/rrc_metrics.h" #include "srsenb/hdr/upper/rrc_metrics.h"
#include "srsue/hdr/upper/gw_metrics.h" #include "srsenb/hdr/upper/s1ap_metrics.h"
#include "srslte/common/metrics_hub.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include "srsenb/hdr/mac/mac_metrics.h" #include "srsue/hdr/stack/upper/gw_metrics.h"
#include "srsenb/hdr/phy/phy_metrics.h"
namespace srsenb { namespace srsenb {
@ -55,7 +55,7 @@ typedef struct {
class enb_metrics_interface : public srslte::metrics_interface<enb_metrics_t> class enb_metrics_interface : public srslte::metrics_interface<enb_metrics_t>
{ {
public: public:
virtual bool get_metrics(enb_metrics_t &m) = 0; virtual bool get_metrics(enb_metrics_t* m) = 0;
}; };
} // namespace srsenb } // namespace srsenb

@ -35,6 +35,7 @@
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/phy/rf/rf.h"
#include "srslte/upper/rlc_interface.h" #include "srslte/upper/rlc_interface.h"
namespace srsue { namespace srsue {
@ -170,7 +171,7 @@ public:
}; };
// RRC interface for PHY // RRC interface for PHY
class rrc_interface_phy class rrc_interface_phy_lte
{ {
public: public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
@ -348,7 +349,7 @@ public:
* *
*/ */
/* Interface PHY -> MAC */ /* Interface PHY -> MAC */
class mac_interface_phy class mac_interface_phy_lte
{ {
public: public:
typedef struct { typedef struct {
@ -415,7 +416,7 @@ public:
virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 0; virtual void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) = 0;
/* Indicate successful decoding of BCH TB through PBCH */ /* Indicate successful decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0; virtual void bch_decoded_ok(uint8_t* payload, uint32_t len) = 0;
/* Indicate successful decoding of MCH TB through PMCH */ /* Indicate successful decoding of MCH TB through PMCH */
virtual void mch_decoded(uint32_t len, bool crc) = 0; virtual void mch_decoded(uint32_t len, bool crc) = 0;
@ -660,6 +661,23 @@ public:
virtual void wait_uplink() = 0; 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;
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 /** PHY interface
* *
@ -671,9 +689,25 @@ typedef struct {
} carrier_map_t; } carrier_map_t;
typedef struct { 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;
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
float dl_freq;
float ul_freq;
bool ul_pwr_ctrl_en; bool ul_pwr_ctrl_en;
float prach_gain; float prach_gain;
int pdsch_max_its; int pdsch_max_its;
bool attach_enable_64qam;
int nof_phy_threads; int nof_phy_threads;
int worker_cpu_mask; int worker_cpu_mask;
@ -709,13 +743,13 @@ typedef struct {
uint32_t estimator_fil_order; uint32_t estimator_fil_order;
float snr_to_cqi_offset; float snr_to_cqi_offset;
std::string sss_algorithm; std::string sss_algorithm;
bool rssi_sensor_enabled;
bool sic_pss_enabled; bool sic_pss_enabled;
float rx_gain_offset; float rx_gain_offset;
bool pdsch_csi_enabled; bool pdsch_csi_enabled;
bool pdsch_8bit_decoder; bool pdsch_8bit_decoder;
uint32_t intra_freq_meas_len_ms; uint32_t intra_freq_meas_len_ms;
uint32_t intra_freq_meas_period_ms; uint32_t intra_freq_meas_period_ms;
bool pregenerate_signals;
} phy_args_t; } phy_args_t;
@ -743,7 +777,7 @@ public:
}; };
/* Interface MAC -> PHY */ /* Interface MAC -> PHY */
class phy_interface_mac : public phy_interface_mac_common class phy_interface_mac_lte : public phy_interface_mac_common
{ {
public: public:
typedef struct { typedef struct {
@ -766,7 +800,7 @@ public:
virtual void set_mch_period_stop(uint32_t stop) = 0; virtual void set_mch_period_stop(uint32_t stop) = 0;
}; };
class phy_interface_rrc class phy_interface_rrc_lte
{ {
public: public:
struct phy_cfg_common_t { struct phy_cfg_common_t {
@ -827,8 +861,56 @@ public:
virtual void reset() = 0; virtual void reset() = 0;
virtual void enable_pregen_signals(bool enable) = 0;
};
class radio_interface_phy
{
public:
// trx functions
virtual bool tx(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(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 double& freq) = 0;
virtual void set_rx_freq(const uint32_t& radio_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_master_clock_rate(const double& rate) = 0;
virtual void set_tx_srate(const double& srate) = 0;
virtual void set_rx_srate(const double& srate) = 0;
virtual float set_tx_power(const float& power) = 0;
// getter
virtual float get_rx_gain(const uint32_t& radio_idx = 0) = 0;
virtual double get_freq_offset() = 0;
virtual double get_tx_freq(const uint32_t& radio_idx = 0) = 0;
virtual double get_rx_freq(const uint32_t& radio_idx = 0) = 0;
virtual float get_max_tx_power() = 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) = 0;
};
class phy_interface_radio
{
public:
virtual void radio_overflow() = 0;
virtual void radio_failure() = 0;
}; };
// Combined interface for PHY to access stack (MAC and RRC)
class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_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
{
};
} // namespace srsue } // namespace srsue

@ -98,6 +98,7 @@ class radio {
void set_rx_gain(float gain); void set_rx_gain(float gain);
void set_tx_rx_gain_offset(float offset); void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain); double set_rx_gain_th(float gain);
void set_master_clock_rate(double rate);
void set_freq_offset(double freq); void set_freq_offset(double freq);
void set_tx_freq(uint32_t chan, double freq); void set_tx_freq(uint32_t chan, double freq);
@ -107,7 +108,6 @@ class radio {
double get_tx_freq(); double get_tx_freq();
double get_rx_freq(); double get_rx_freq();
void set_master_clock_rate(double rate);
void set_tx_srate(double srate); void set_tx_srate(double srate);
void set_rx_srate(double srate); void set_rx_srate(double srate);
@ -129,17 +129,17 @@ class radio {
void register_error_handler(srslte_rf_error_handler_t h); void register_error_handler(srslte_rf_error_handler_t h);
protected: protected:
srslte_rf_t rf_device; srslte_rf_t rf_device;
log_filter* log_h; log_filter* log_h;
const static uint32_t burst_preamble_max_samples = 13824; const static uint32_t burst_preamble_max_samples = 13824;
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time) double burst_preamble_sec; // Start of burst preamble time (off->on RF transition time)
srslte_timestamp_t end_of_burst_time; srslte_timestamp_t end_of_burst_time;
bool is_start_of_burst; bool is_start_of_burst;
uint32_t burst_preamble_samples; uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t *zeros; cf_t* zeros;
double master_clock_rate;
double cur_tx_srate; double cur_tx_srate;
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
@ -173,7 +173,6 @@ class radio {
uint32_t saved_nof_channels; uint32_t saved_nof_channels;
char saved_args[128]; char saved_args[128];
char saved_devname[128]; char saved_devname[128];
}; };
} // namespace srslte } // namespace srslte

@ -24,8 +24,6 @@
#include "srslte/common/pcap.h" #include "srslte/common/pcap.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
namespace srslte { namespace srslte {
void mac_pcap::enable(bool en) void mac_pcap::enable(bool en)
@ -40,6 +38,7 @@ void mac_pcap::open(const char* filename, uint32_t ue_id)
} }
void mac_pcap::close() void mac_pcap::close()
{ {
enable_write = false;
fprintf(stdout, "Saving MAC PCAP file\n"); fprintf(stdout, "Saving MAC PCAP file\n");
LTE_PCAP_Close(pcap_file); LTE_PCAP_Close(pcap_file);
} }

@ -485,7 +485,8 @@ void radio::register_error_handler(srslte_rf_error_handler_t h)
srslte_rf_register_error_handler(&rf_device, h); srslte_rf_register_error_handler(&rf_device, h);
} }
srslte_rf_info_t *radio::get_info() { srslte_rf_info_t* radio::get_info()
{
return srslte_rf_get_info(&rf_device); return srslte_rf_get_info(&rf_device);
} }

@ -19,7 +19,7 @@
* *
*/ */
#include "../../../srsue/hdr/rrc/rrc.h" #include "../../../srsue/hdr/stack/rrc/rrc.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 "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"

@ -19,7 +19,7 @@
* *
*/ */
#include "../../../srsue/hdr/rrc/rrc.h" #include "../../../srsue/hdr/stack/rrc/rrc.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 "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"

@ -19,7 +19,7 @@
* *
*/ */
#include "../../../srsue/hdr/rrc/rrc.h" #include "../../../srsue/hdr/stack/rrc/rrc.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 "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"

@ -166,7 +166,7 @@ public:
void handle_rf_msg(srslte_rf_error_t error); void handle_rf_msg(srslte_rf_error_t error);
// eNodeB metrics interface // eNodeB metrics interface
bool get_metrics(enb_metrics_t &m); bool get_metrics(enb_metrics_t* m);
void pregenerate_signals(bool enable); void pregenerate_signals(bool enable);

@ -342,18 +342,18 @@ void enb::print_pool() {
srslte::byte_buffer_pool::get_instance()->print_all_buffers(); srslte::byte_buffer_pool::get_instance()->print_all_buffers();
} }
bool enb::get_metrics(enb_metrics_t &m) bool enb::get_metrics(enb_metrics_t* m)
{ {
m.rf = rf_metrics; m->rf = rf_metrics;
bzero(&rf_metrics, sizeof(rf_metrics_t)); bzero(&rf_metrics, sizeof(rf_metrics_t));
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); mac.get_metrics(m->mac);
rrc.get_metrics(m.rrc); rrc.get_metrics(m->rrc);
s1ap.get_metrics(m.s1ap); s1ap.get_metrics(m->s1ap);
m.running = started; m->running = started;
return true; return true;
} }

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

@ -45,7 +45,7 @@ public:
float get_ref_cfo(); float get_ref_cfo();
void set_tdd_config(srslte_tdd_config_t config); void set_tdd_config(srslte_tdd_config_t config);
void set_pcell_config(phy_interface_rrc::phy_cfg_t* phy_cfg); void set_pcell_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg);
void set_scell_config(asn1::rrc::scell_to_add_mod_r10_s* phy_cfg); void set_scell_config(asn1::rrc::scell_to_add_mod_r10_s* phy_cfg);
void set_crnti(uint16_t rnti); void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled); void enable_pregen_signals(bool enabled);
@ -62,12 +62,12 @@ public:
private: private:
void dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant, void dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant,
srslte_dci_dl_t* dl_dci, srslte_dci_dl_t* dl_dci,
mac_interface_phy::mac_grant_dl_t* mac_grant); mac_interface_phy_lte::mac_grant_dl_t* mac_grant);
void ul_phy_to_mac_grant(srslte_pusch_grant_t* phy_grant, void ul_phy_to_mac_grant(srslte_pusch_grant_t* phy_grant,
srslte_dci_ul_t* ul_dci, srslte_dci_ul_t* ul_dci,
uint32_t pid, uint32_t pid,
bool ul_grant_available, bool ul_grant_available,
mac_interface_phy::mac_grant_ul_t* mac_grant); mac_interface_phy_lte::mac_grant_ul_t* mac_grant);
void fill_dci_cfg(srslte_dci_cfg_t* cfg, bool rel10 = false); void fill_dci_cfg(srslte_dci_cfg_t* cfg, bool rel10 = false);
// Cross-carried grants scheduled from PCell // Cross-carried grants scheduled from PCell
@ -85,12 +85,12 @@ private:
void decode_phich(); void decode_phich();
int decode_pdsch(srslte_pdsch_ack_resource_t ack_resource, int decode_pdsch(srslte_pdsch_ack_resource_t ack_resource,
mac_interface_phy::tb_action_dl_t* action, mac_interface_phy_lte::tb_action_dl_t* action,
bool acks[SRSLTE_MAX_CODEWORDS]); bool acks[SRSLTE_MAX_CODEWORDS]);
int decode_pmch(mac_interface_phy::tb_action_dl_t* action, srslte_mbsfn_cfg_t* mbsfn_cfg); int decode_pmch(mac_interface_phy_lte::tb_action_dl_t* action, srslte_mbsfn_cfg_t* mbsfn_cfg);
/* Methods for UL */ /* Methods for UL */
bool encode_uplink(mac_interface_phy::tb_action_ul_t* action, srslte_uci_data_t* uci_data); bool encode_uplink(mac_interface_phy_lte::tb_action_ul_t* action, srslte_uci_data_t* uci_data);
void set_uci_sr(srslte_uci_data_t* uci_data); void set_uci_sr(srslte_uci_data_t* uci_data);
void set_uci_periodic_cqi(srslte_uci_data_t* uci_data); void set_uci_periodic_cqi(srslte_uci_data_t* uci_data);
void set_uci_aperiodic_cqi(srslte_uci_data_t* uci_data); void set_uci_aperiodic_cqi(srslte_uci_data_t* uci_data);
@ -99,7 +99,7 @@ private:
uint32_t get_wideband_cqi(); uint32_t get_wideband_cqi();
srslte_cqi_report_mode_t aperiodic_mode(asn1::rrc::cqi_report_mode_aperiodic_e mode); srslte_cqi_report_mode_t aperiodic_mode(asn1::rrc::cqi_report_mode_aperiodic_e mode);
void parse_antenna_info(asn1::rrc::phys_cfg_ded_s* dedicated); void parse_antenna_info(asn1::rrc::phys_cfg_ded_s* dedicated);
void parse_pucch_config(phy_interface_rrc::phy_cfg_t* phy_cfg); void parse_pucch_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg);
/* Common objects */ /* Common objects */
phy_common* phy; phy_common* phy;

@ -33,33 +33,34 @@
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srsue/hdr/phy/ue_phy_base.h"
#include "sync.h" #include "sync.h"
namespace srsue { namespace srsue {
typedef _Complex float cf_t; typedef _Complex float cf_t;
class phy class phy : public ue_phy_base, public phy_interface_stack_lte, public phy_interface_radio, public thread
: public phy_interface_mac
, public phy_interface_rrc
, public thread
{ {
public: public:
phy(); phy();
bool init(srslte::radio* radio_handler, ~phy() = default;
mac_interface_phy* mac,
rrc_interface_phy* rrc, // Init defined in base class
std::vector<srslte::log_filter*> log_vec, int init(const phy_args_t& args_, srslte::logger* logger_);
phy_args_t* args = NULL);
// Init for LTE PHYs
int init(const phy_args_t& args_,
srslte::logger* logger_,
stack_interface_phy_lte* stack_,
radio_interface_phy* radio_);
void stop(); void stop();
void wait_initialize(); void wait_initialize();
bool is_initiated(); bool is_initiated();
void set_agc_enable(bool enabled); void get_metrics(phy_metrics_t* m);
void get_metrics(phy_metrics_t &m);
void srslte_phy_logger(phy_logger_level_t log_level, char *str); void srslte_phy_logger(phy_logger_level_t log_level, char *str);
void enable_pregen_signals(bool enable); void enable_pregen_signals(bool enable);
@ -68,6 +69,7 @@ public:
void force_freq(float dl_freq, float ul_freq); void force_freq(float dl_freq, float ul_freq);
void radio_overflow(); void radio_overflow();
void radio_failure();
/********** RRC INTERFACE ********************/ /********** RRC INTERFACE ********************/
void reset(); void reset();
@ -132,6 +134,8 @@ public:
const static int MAX_WORKERS = 4; const static int MAX_WORKERS = 4;
const static int DEFAULT_WORKERS = 4; const static int DEFAULT_WORKERS = 4;
std::string get_type() { return "lte_soft"; }
private: private:
void run_thread(); void run_thread();
@ -141,12 +145,13 @@ private:
const static int SF_RECV_THREAD_PRIO = 1; const static int SF_RECV_THREAD_PRIO = 1;
const static int WORKERS_THREAD_PRIO = 2; const static int WORKERS_THREAD_PRIO = 2;
srslte::radio* radio_handler; radio_interface_phy* radio;
std::vector<srslte::log_filter*> log_vec; std::vector<srslte::log_filter*> log_vec;
srslte::logger* logger;
srslte::log* log_h; srslte::log* log_h;
srslte::log *log_phy_lib_h; srslte::log *log_phy_lib_h;
srsue::mac_interface_phy *mac; srsue::stack_interface_phy_lte* stack;
srsue::rrc_interface_phy *rrc;
srslte::thread_pool workers_pool; srslte::thread_pool workers_pool;
std::vector<sf_worker*> workers; std::vector<sf_worker*> workers;
@ -159,16 +164,14 @@ private:
srslte_prach_cfg_t prach_cfg; srslte_prach_cfg_t prach_cfg;
srslte_tdd_config_t tdd_config; srslte_tdd_config_t tdd_config;
phy_args_t* args; phy_interface_rrc_lte::phy_cfg_t config;
phy_args_t default_args; phy_args_t args;
/* Current time advance */ /* Current time advance */
uint32_t n_ta; uint32_t n_ta;
bool init_(srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log *log_h, bool do_agc, uint32_t nof_workers);
void set_default_args(phy_args_t *args); void set_default_args(phy_args_t *args);
bool check_args(phy_args_t *args); bool check_args(const phy_args_t& args);
}; };
} // namespace srsue } // namespace srsue

@ -53,10 +53,9 @@ class phy_common
public: public:
/* Common variables used by all phy workers */ /* Common variables used by all phy workers */
phy_args_t* args; phy_args_t* args;
rrc_interface_phy* rrc; stack_interface_phy_lte* stack;
mac_interface_phy* mac;
phy_interface_rrc::phy_cfg_mbsfn_t mbsfn_config; phy_interface_rrc_lte::phy_cfg_mbsfn_t mbsfn_config;
/* Power control variables */ /* Power control variables */
float pathloss[SRSLTE_MAX_CARRIERS]; float pathloss[SRSLTE_MAX_CARRIERS];
@ -68,7 +67,6 @@ public:
float avg_rsrp_dbm[SRSLTE_MAX_CARRIERS]; float avg_rsrp_dbm[SRSLTE_MAX_CARRIERS];
float avg_rsrq_db; float avg_rsrq_db;
float avg_rssi_dbm; float avg_rssi_dbm;
float last_radio_rssi;
float rx_gain_offset; float rx_gain_offset;
float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS]; float avg_snr_db_cqi[SRSLTE_MAX_CARRIERS];
float avg_snr_db_sync; float avg_snr_db_sync;
@ -96,8 +94,7 @@ public:
~phy_common(); ~phy_common();
void void init(phy_args_t* args, srslte::log* _log, radio_interface_phy* _radio, stack_interface_phy_lte* _stack);
init(phy_args_t* args, srslte::log* _log, srslte::radio* _radio, rrc_interface_phy* rrc, mac_interface_phy* _mac);
uint32_t ul_pidof(uint32_t tti, srslte_tdd_config_t* tdd_config); uint32_t ul_pidof(uint32_t tti, srslte_tdd_config_t* tdd_config);
@ -144,7 +141,7 @@ public:
bool sr_enabled; bool sr_enabled;
int sr_last_tx_tti; int sr_last_tx_tti;
srslte::radio* get_radio(); radio_interface_phy* get_radio();
void set_cell(const srslte_cell_t& c); void set_cell(const srslte_cell_t& c);
uint32_t get_nof_prb(); uint32_t get_nof_prb();
@ -177,7 +174,7 @@ private:
uint32_t max_workers; uint32_t max_workers;
bool is_first_of_burst[SRSLTE_MAX_RADIOS]; bool is_first_of_burst[SRSLTE_MAX_RADIOS];
srslte::radio* radio_h; radio_interface_phy* radio_h;
float cfo; float cfo;
srslte::log* log_h; srslte::log* log_h;

@ -53,7 +53,7 @@ namespace srsue {
bool is_pending(); bool is_pending();
cf_t* generate(float cfo, uint32_t *nof_sf, float *target_power = NULL); cf_t* generate(float cfo, uint32_t *nof_sf, float *target_power = NULL);
phy_interface_mac::prach_info_t get_info(); phy_interface_mac_lte::prach_info_t get_info();
private: private:
const static int MAX_LEN_SF = 3; const static int MAX_LEN_SF = 3;

@ -56,7 +56,7 @@ public:
void set_cfo(float cfo); void set_cfo(float cfo);
void set_tdd_config(srslte_tdd_config_t config); void set_tdd_config(srslte_tdd_config_t config);
void set_pcell_config(phy_interface_rrc::phy_cfg_t* phy_cfg); void set_pcell_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg);
void set_scell_config(uint32_t cc_idx, asn1::rrc::scell_to_add_mod_r10_s* scell_config); void set_scell_config(uint32_t cc_idx, asn1::rrc::scell_to_add_mod_r10_s* scell_config);
void set_crnti(uint16_t rnti); void set_crnti(uint16_t rnti);
void enable_pregen_signals(bool enabled); void enable_pregen_signals(bool enabled);

@ -46,9 +46,8 @@ public:
sync(); sync();
~sync(); ~sync();
void init(srslte::radio* radio_handler, void init(radio_interface_phy* radio_,
mac_interface_phy* mac, stack_interface_phy_lte* _stack,
rrc_interface_phy* rrc,
prach* prach_buffer, prach* prach_buffer,
srslte::thread_pool* _workers_pool, srslte::thread_pool* _workers_pool,
phy_common* _worker_com, phy_common* _worker_com,
@ -61,8 +60,8 @@ public:
void radio_overflow(); void radio_overflow();
// RRC interface for controling the SYNC state // RRC interface for controling the SYNC state
phy_interface_rrc::cell_search_ret_t cell_search(phy_interface_rrc::phy_cell_t *cell); phy_interface_rrc_lte::cell_search_ret_t cell_search(phy_interface_rrc_lte::phy_cell_t* cell);
bool cell_select(phy_interface_rrc::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 // RRC interface for controlling the neighbour cell measurement
@ -210,7 +209,7 @@ private:
public: public:
intra_measure(); intra_measure();
~intra_measure(); ~intra_measure();
void init(phy_common* common, rrc_interface_phy* rrc, srslte::log* log_h); void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h);
void stop(); void stop();
void add_cell(int pci); void add_cell(int pci);
void rem_cell(int pci); void rem_cell(int pci);
@ -223,7 +222,7 @@ private:
const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5; const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5;
scell_recv scell; scell_recv scell;
rrc_interface_phy* rrc; rrc_interface_phy_lte* rrc;
srslte::log *log_h; srslte::log *log_h;
phy_common* common; phy_common* common;
uint32_t current_earfcn; uint32_t current_earfcn;
@ -273,12 +272,11 @@ private:
int next_offset; int next_offset;
// Pointers to other classes // Pointers to other classes
mac_interface_phy *mac; stack_interface_phy_lte* stack;
rrc_interface_phy *rrc;
srslte::log *log_h; srslte::log *log_h;
srslte::log* log_phy_lib_h; srslte::log* log_phy_lib_h;
srslte::thread_pool* workers_pool; srslte::thread_pool* workers_pool;
srslte::radio* radio_h; radio_interface_phy* radio_h;
phy_common* worker_com; phy_common* worker_com;
prach *prach_buffer; prach *prach_buffer;
async_scell_recv* scell_sync; async_scell_recv* scell_sync;

@ -0,0 +1,60 @@
/*
* 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_phy_base.h
* Description: Base class for all UE PHYs.
*****************************************************************************/
#ifndef SRSUE_UE_PHY_BASE_H
#define SRSUE_UE_PHY_BASE_H
#include "srslte/common/logger.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/phy/phy_metrics.h"
#include <memory>
#include <vector>
namespace srsue {
class ue_phy_base
{
public:
ue_phy_base(){};
virtual ~ue_phy_base(){};
virtual std::string get_type() = 0;
virtual int init(const phy_args_t& args_, srslte::logger* logger_) = 0;
virtual void stop() = 0;
virtual void set_earfcn(std::vector<uint32_t> earfcns) = 0;
virtual void force_freq(float dl_freq, float ul_freq) = 0;
virtual void wait_initialize() = 0;
virtual void start_plot() = 0;
virtual void get_metrics(phy_metrics_t* m) = 0;
};
} // namespace srsue
#endif // SRSUE_UE_PHY_BASE_H

@ -0,0 +1,106 @@
/*
* 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_radio_multi.h
* Description: UE radio module using the srslte_radio_multi() object.
*****************************************************************************/
#ifndef SRSUE_UE_RADIO_MULTI_H
#define SRSUE_UE_RADIO_MULTI_H
#include "srslte/common/log_filter.h"
#include "srslte/radio/radio.h"
#include "srsue/hdr/radio/ue_radio_base.h"
#include "srsue/hdr/ue_metrics_interface.h"
namespace srsue {
/*******************************************************************************
Main UE stack class
*******************************************************************************/
class ue_radio : public ue_radio_base, public radio_interface_phy
{
public:
ue_radio();
~ue_radio();
std::string get_type();
int init(const rf_args_t& args_, srslte::logger* logger_);
int init(const rf_args_t& args_, srslte::logger* logger_, phy_interface_radio* phy_);
void stop();
static void rf_msg(srslte_rf_error_t error);
void handle_rf_msg(srslte_rf_error_t error);
bool get_metrics(rf_metrics_t* metrics);
// radio_interface_phy
bool is_init() { return radios.at(0)->is_init(); }
void reset() { return radios.at(0)->reset(); }
bool is_continuous_tx() { return radios.at(0)->is_continuous_tx(); }
bool tx(cf_t* buffer[SRSLTE_MAX_PORTS], const uint32_t& nof_samples, const srslte_timestamp_t& tx_time)
{
for (auto& radio : radios) {
radio->tx(buffer, nof_samples, tx_time);
}
return true;
}
void tx_end() { return radios.at(0)->tx_end(); }
bool rx_now(cf_t* buffer[SRSLTE_MAX_PORTS], const uint32_t& nof_samples, srslte_timestamp_t* rxd_time)
{
return radios.at(0)->rx_now(buffer, nof_samples, rxd_time);
}
void set_rx_gain(const uint32_t& radio_idx, const float& gain) { radios.at(radio_idx)->set_rx_gain(gain); }
double set_rx_gain_th(const float& gain) { return radios.at(0)->set_rx_gain_th(gain); }
float get_rx_gain(const uint32_t& radio_idx) { return radios.at(radio_idx)->get_rx_gain(); }
void set_tx_freq(const uint32_t& radio_idx, const double& freq) { radios.at(radio_idx)->set_tx_freq(0, freq); }
void set_rx_freq(const uint32_t& radio_idx, const double& freq) { radios.at(radio_idx)->set_rx_freq(0, freq); }
double get_freq_offset() { return radios.at(0)->get_freq_offset(); }
double get_tx_freq(const uint32_t& radio_idx) { return radios.at(radio_idx)->get_tx_freq(); }
double get_rx_freq(const uint32_t& radio_idx) { return radios.at(radio_idx)->get_rx_freq(); }
float get_max_tx_power() { return radios.at(0)->get_max_tx_power(); }
void set_master_clock_rate(const double& rate) { radios.at(0)->set_master_clock_rate(rate); }
void set_tx_srate(const double& srate) { radios.at(0)->set_tx_srate(srate); }
void set_rx_srate(const double& srate) { radios.at(0)->set_rx_srate(srate); }
float set_tx_power(const float& power) { return radios.at(0)->set_tx_power(power); }
srslte_rf_info_t* get_info(const uint32_t& radio_idx) { return radios.at(radio_idx)->get_info(); }
private:
srsue::rf_args_t args;
std::vector<std::unique_ptr<srslte::radio> > radios;
srslte::logger* logger;
srslte::log_filter log;
bool running;
rf_metrics_t rf_metrics;
phy_interface_radio* phy;
};
} // namespace srsue
#endif // SRSUE_UE_RADIO_MULTI_H

@ -0,0 +1,58 @@
/*
* 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_radio_base.h
* Description: Base class for all UE Radios.
*****************************************************************************/
#ifndef SRSUE_UE_RADIO_BASE_H
#define SRSUE_UE_RADIO_BASE_H
#include "srslte/common/logger.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/ue_metrics_interface.h"
#include <memory>
#include <vector>
namespace srsue {
class ue_radio_base
{
public:
ue_radio_base(){};
virtual ~ue_radio_base(){};
static std::shared_ptr<ue_radio_base> get_instance(const std::string& type);
virtual std::string get_type() = 0;
virtual int init(const srsue::rf_args_t& args_, srslte::logger* logger_) = 0;
virtual void stop() = 0;
virtual bool get_metrics(rf_metrics_t* metrics) = 0;
private:
};
} // namespace srsue
#endif // SRSUE_UE_RADIO_BASE_H

@ -48,8 +48,8 @@ public:
void start_pcap(srslte::mac_pcap* pcap_); void start_pcap(srslte::mac_pcap* pcap_);
/***************** PHY->MAC interface for DL processes **************************/ /***************** PHY->MAC interface for DL processes **************************/
void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]); void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]);
void set_si_window_start(int si_window_start); void set_si_window_start(int si_window_start);
@ -63,8 +63,8 @@ private:
bool init(int pid, dl_harq_entity* parent); bool init(int pid, dl_harq_entity* parent);
void reset(void); void reset(void);
void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]); void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]);
bool is_sps(); bool is_sps();
@ -79,12 +79,12 @@ private:
bool init(int pid, dl_harq_entity* parent, uint32_t tb_idx); bool init(int pid, dl_harq_entity* parent, uint32_t tb_idx);
void reset(bool lock = true); void reset(bool lock = true);
void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool* ack_ptr); void tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool* ack_ptr);
private: private:
// Determine if it's a new transmission 5.3.2.2 // Determine if it's a new transmission 5.3.2.2
bool calc_is_new_transmission(mac_interface_phy::mac_grant_dl_t grant); bool calc_is_new_transmission(mac_interface_phy_lte::mac_grant_dl_t grant);
pthread_mutex_t mutex; pthread_mutex_t mutex;
@ -103,7 +103,7 @@ private:
uint32_t n_retx; uint32_t n_retx;
mac_interface_phy::mac_grant_dl_t cur_grant; mac_interface_phy_lte::mac_grant_dl_t cur_grant;
srslte_softbuffer_rx_t softbuffer; srslte_softbuffer_rx_t softbuffer;
}; };

@ -36,7 +36,7 @@ public:
void clear() {} void clear() {}
void reset() {} void reset() {}
bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_dl_t* grant) { return false; } bool get_pending_grant(uint32_t tti, mac_interface_phy_lte::mac_grant_dl_t* grant) { return false; }
private: private:

@ -40,7 +40,7 @@
namespace srsue { namespace srsue {
class mac : public mac_interface_phy, class mac : public mac_interface_phy_lte,
public mac_interface_rrc, public mac_interface_rrc,
public srslte::timer_callback, public srslte::timer_callback,
public srslte::mac_interface_timers, public srslte::mac_interface_timers,
@ -49,7 +49,7 @@ class mac : public mac_interface_phy,
{ {
public: public:
mac(); mac();
bool init(phy_interface_mac* phy, bool init(phy_interface_mac_lte* phy,
rlc_interface_mac* rlc, rlc_interface_mac* rlc,
rrc_interface_mac* rrc, rrc_interface_mac* rrc,
srslte::log* log_h, srslte::log* log_h,
@ -121,11 +121,11 @@ private:
static const int MAC_PDU_THREAD_PRIO = 5; static const int MAC_PDU_THREAD_PRIO = 5;
// Interaction with PHY // Interaction with PHY
phy_interface_mac *phy_h; phy_interface_mac_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;
mac_interface_phy::mac_phy_cfg_mbsfn_t phy_mbsfn_cfg; mac_interface_phy_lte::mac_phy_cfg_mbsfn_t phy_mbsfn_cfg;
// RNTI search window scheduling // RNTI search window scheduling
int si_window_length, si_window_start; int si_window_length, si_window_start;

@ -37,7 +37,7 @@ class phr_proc : public srslte::timer_callback
{ {
public: public:
phr_proc(); phr_proc();
void init(phy_interface_mac* phy_h, srslte::log* log_h_, srslte::timers* timers_db_); void init(phy_interface_mac_lte* phy_h, srslte::log* log_h_, srslte::timers* timers_db_);
void set_config(mac_interface_rrc::phr_cfg_t& cfg); void set_config(mac_interface_rrc::phr_cfg_t& cfg);
void step(uint32_t tti); void step(uint32_t tti);
void reset(); void reset();
@ -53,7 +53,7 @@ private:
bool pathloss_changed(); bool pathloss_changed();
srslte::log* log_h; srslte::log* log_h;
phy_interface_mac* phy_h; phy_interface_mac_lte* phy_h;
srslte::timers* timers_db; srslte::timers* timers_db;
mac_interface_rrc::phr_cfg_t phr_cfg; mac_interface_rrc::phr_cfg_t phr_cfg;
bool initiated; bool initiated;

@ -72,7 +72,7 @@ public:
~ra_proc(); ~ra_proc();
void init(phy_interface_mac* phy_h, void init(phy_interface_mac_lte* phy_h,
rrc_interface_mac* rrc_, rrc_interface_mac* rrc_,
srslte::log* log_h, srslte::log* log_h,
mac_interface_rrc::ue_rnti_t* rntis, mac_interface_rrc::ue_rnti_t* rntis,
@ -94,7 +94,7 @@ public:
void harq_max_retx(); void harq_max_retx();
void pdcch_to_crnti(bool contains_uplink_grant); void pdcch_to_crnti(bool contains_uplink_grant);
void timer_expired(uint32_t timer_id); void timer_expired(uint32_t timer_id);
void new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action); void new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action);
void tb_decoded_ok(); void tb_decoded_ok();
void start_noncont(uint32_t preamble_index, uint32_t prach_mask); void start_noncont(uint32_t preamble_index, uint32_t prach_mask);
@ -168,7 +168,7 @@ private:
void read_params(); void read_params();
phy_interface_mac* phy_h; phy_interface_mac_lte* phy_h;
srslte::log* log_h; srslte::log* log_h;
mux *mux_unit; mux *mux_unit;
srslte::mac_pcap *pcap; srslte::mac_pcap *pcap;

@ -35,7 +35,7 @@ class sr_proc
{ {
public: public:
sr_proc(); sr_proc();
void init(phy_interface_mac* phy_h, rrc_interface_mac* rrc, srslte::log* log_h); void init(phy_interface_mac_lte* phy_h, rrc_interface_mac* rrc, srslte::log* log_h);
void step(uint32_t tti); void step(uint32_t tti);
void set_config(mac_interface_rrc::sr_cfg_t& cfg); void set_config(mac_interface_rrc::sr_cfg_t& cfg);
void reset(); void reset();
@ -51,7 +51,7 @@ private:
mac_interface_rrc::sr_cfg_t sr_cfg; mac_interface_rrc::sr_cfg_t sr_cfg;
rrc_interface_mac *rrc; rrc_interface_mac *rrc;
phy_interface_mac *phy_h; phy_interface_mac_lte* phy_h;
srslte::log *log_h; srslte::log *log_h;
bool initiated; bool initiated;

@ -51,7 +51,7 @@ public:
void start_pcap(srslte::mac_pcap* pcap_); void start_pcap(srslte::mac_pcap* pcap_);
/***************** PHY->MAC interface for UL processes **************************/ /***************** PHY->MAC interface for UL processes **************************/
void new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); void new_grant_ul(mac_interface_phy_lte::mac_grant_ul_t grant, mac_interface_phy_lte::tb_action_ul_t* action);
int get_current_tbs(uint32_t pid); int get_current_tbs(uint32_t pid);
float get_average_retx(); float get_average_retx();
@ -76,10 +76,10 @@ private:
int get_current_tbs(); int get_current_tbs();
// Implements Section 5.4.2.1 // Implements Section 5.4.2.1
void new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); void new_grant_ul(mac_interface_phy_lte::mac_grant_ul_t grant, mac_interface_phy_lte::tb_action_ul_t* action);
private: private:
mac_interface_phy::mac_grant_ul_t cur_grant; mac_interface_phy_lte::mac_grant_ul_t cur_grant;
uint32_t pid; uint32_t pid;
uint32_t current_tx_nb; uint32_t current_tx_nb;
@ -96,9 +96,9 @@ private:
uint8_t* payload_buffer; uint8_t* payload_buffer;
uint8_t* pdu_ptr; uint8_t* pdu_ptr;
void generate_tx(mac_interface_phy::tb_action_ul_t* action); void generate_tx(mac_interface_phy_lte::tb_action_ul_t* action);
void generate_retx(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); void generate_retx(mac_interface_phy_lte::mac_grant_ul_t grant, mac_interface_phy_lte::tb_action_ul_t* action);
void generate_new_tx(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action); void generate_new_tx(mac_interface_phy_lte::mac_grant_ul_t grant, mac_interface_phy_lte::tb_action_ul_t* action);
}; };
ul_sps ul_sps_assig; ul_sps ul_sps_assig;

@ -38,7 +38,7 @@ public:
void clear() {} void clear() {}
void reset(uint32_t tti) {} void reset(uint32_t tti) {}
bool get_pending_grant(uint32_t tti, mac_interface_phy::mac_grant_ul_t* grant) { return false; } bool get_pending_grant(uint32_t tti, mac_interface_phy_lte::mac_grant_ul_t* grant) { return false; }
private: private:

@ -47,6 +47,8 @@ typedef struct {
uint8_t supported_bands[SRSLTE_RRC_N_BANDS]; uint8_t supported_bands[SRSLTE_RRC_N_BANDS];
uint32_t nof_supported_bands; uint32_t nof_supported_bands;
bool support_ca; bool support_ca;
int mbms_service_id;
uint32_t mbms_service_port;
} rrc_args_t; } rrc_args_t;
#define SRSLTE_UE_CATEGORY_DEFAULT "4" #define SRSLTE_UE_CATEGORY_DEFAULT "4"
@ -118,12 +120,13 @@ class cell_t
} }
cell_t() { cell_t() {
phy_interface_rrc::phy_cell_t tmp; phy_interface_rrc_lte::phy_cell_t tmp;
ZERO_OBJECT(tmp); ZERO_OBJECT(tmp);
ZERO_OBJECT(phy_cell); ZERO_OBJECT(phy_cell);
cell_t(tmp, 0); cell_t(tmp, 0);
} }
cell_t(phy_interface_rrc::phy_cell_t phy_cell, float rsrp) { cell_t(phy_interface_rrc_lte::phy_cell_t phy_cell, float rsrp)
{
gettimeofday(&last_update, NULL); gettimeofday(&last_update, NULL);
this->has_valid_sib1 = false; this->has_valid_sib1 = false;
this->has_valid_sib2 = false; this->has_valid_sib2 = false;
@ -253,7 +256,7 @@ class cell_t
return 0; return 0;
} }
phy_interface_rrc::phy_cell_t phy_cell; phy_interface_rrc_lte::phy_cell_t phy_cell;
bool in_sync; bool in_sync;
bool has_mcch; bool has_mcch;
asn1::rrc::sib_type1_s sib1; asn1::rrc::sib_type1_s sib1;
@ -274,7 +277,7 @@ private:
}; };
class rrc : public rrc_interface_nas, class rrc : public rrc_interface_nas,
public rrc_interface_phy, public rrc_interface_phy_lte,
public rrc_interface_mac, public rrc_interface_mac,
public rrc_interface_pdcp, public rrc_interface_pdcp,
public rrc_interface_rlc, public rrc_interface_rlc,
@ -285,7 +288,7 @@ public:
rrc(); rrc();
~rrc(); ~rrc();
void init(phy_interface_rrc* phy_, void init(phy_interface_rrc_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_,
@ -294,12 +297,11 @@ public:
gw_interface_rrc* gw_, gw_interface_rrc* gw_,
srslte::mac_interface_timers* mac_timers_, srslte::mac_interface_timers* mac_timers_,
srslte::log* rrc_log_, srslte::log* rrc_log_,
rrc_args_t* args_); const rrc_args_t& args_);
void stop(); void stop();
rrc_state_t get_state(); rrc_state_t get_state();
void set_args(rrc_args_t args);
// Timeout callback interface // Timeout callback interface
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);
@ -309,7 +311,7 @@ public:
template <class T> template <class T>
void log_rrc_message(const std::string source, const direction_t dir, const srslte::byte_buffer_t* pdu, const T& msg); void log_rrc_message(const std::string source, const direction_t dir, const srslte::byte_buffer_t* pdu, const T& msg);
void print_mbms(); std::string print_mbms();
bool mbms_service_start(uint32_t serv, uint32_t port); bool mbms_service_start(uint32_t serv, uint32_t port);
// NAS interface // NAS interface
@ -364,7 +366,7 @@ private:
srslte::byte_buffer_pool *pool; srslte::byte_buffer_pool *pool;
srslte::log *rrc_log; srslte::log *rrc_log;
phy_interface_rrc *phy; phy_interface_rrc_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;
@ -394,7 +396,7 @@ private:
uint16_t ho_src_rnti; uint16_t ho_src_rnti;
cell_t ho_src_cell; cell_t ho_src_cell;
phy_interface_rrc::phy_cfg_t current_phy_cfg, previous_phy_cfg; phy_interface_rrc_lte::phy_cfg_t current_phy_cfg, previous_phy_cfg;
mac_interface_rrc::mac_cfg_t current_mac_cfg, previous_mac_cfg; mac_interface_rrc::mac_cfg_t current_mac_cfg, previous_mac_cfg;
bool pending_mob_reconf; bool pending_mob_reconf;
asn1::rrc::rrc_conn_recfg_s mob_reconf; asn1::rrc::rrc_conn_recfg_s mob_reconf;
@ -449,11 +451,11 @@ private:
std::vector<cell_t*> neighbour_cells; std::vector<cell_t*> neighbour_cells;
cell_t *serving_cell; cell_t *serving_cell;
void set_serving_cell(uint32_t cell_idx); void set_serving_cell(uint32_t cell_idx);
void set_serving_cell(phy_interface_rrc::phy_cell_t phy_cell); void set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell);
int find_neighbour_cell(uint32_t earfcn, uint32_t pci); int find_neighbour_cell(uint32_t earfcn, uint32_t pci);
bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp); bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp);
bool add_neighbour_cell(phy_interface_rrc::phy_cell_t phy_cell, float rsrp); bool add_neighbour_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, float rsrp);
bool add_neighbour_cell(cell_t *cell); bool add_neighbour_cell(cell_t *cell);
void sort_neighbour_cells(); void sort_neighbour_cells();
void clean_neighbours(); void clean_neighbours();
@ -537,7 +539,7 @@ private:
rrc *parent; rrc *parent;
srslte::log *log_h; srslte::log *log_h;
phy_interface_rrc *phy; phy_interface_rrc_lte* phy;
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
uint32_t filter_k_rsrp, filter_k_rsrq; uint32_t filter_k_rsrp, filter_k_rsrq;
@ -611,7 +613,7 @@ private:
bool cell_selection_criteria(float rsrp, float rsrq = 0); bool cell_selection_criteria(float rsrp, float rsrq = 0);
void cell_reselection(float rsrp, float rsrq); void cell_reselection(float rsrp, float rsrq);
phy_interface_rrc::cell_search_ret_t cell_search(); phy_interface_rrc_lte::cell_search_ret_t cell_search();
asn1::rrc::plmn_id_s selected_plmn_id; asn1::rrc::plmn_id_s selected_plmn_id;
bool plmn_is_selected; bool plmn_is_selected;

@ -0,0 +1,53 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSUE_UE_STACK_BASE_H
#define SRSUE_UE_STACK_BASE_H
#include "srslte/common/logger.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/ue_metrics_interface.h"
#include "srsue/hdr/ue_stack_interface.h"
#include <memory>
namespace srsue {
class ue_stack_base : public ue_interface
{
public:
ue_stack_base(){};
virtual ~ue_stack_base(){};
virtual std::string get_type() = 0;
virtual int init(const stack_args_t& args_, srslte::logger* logger_) = 0;
virtual void stop() = 0;
virtual bool switch_on() = 0;
virtual bool switch_off() = 0;
virtual bool is_rrc_connected() = 0;
// UE metrics interface
virtual bool get_metrics(stack_metrics_t* metrics) = 0;
};
} // namespace srsue
#endif // SRSUE_UE_BASE_H

@ -0,0 +1,137 @@
/*
* 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.h
* Description: L2/L3 LTE stack class.
*****************************************************************************/
#ifndef SRSUE_UE_STACK_LTE_H
#define SRSUE_UE_STACK_LTE_H
#include <pthread.h>
#include <stdarg.h>
#include <string>
#include "mac/mac.h"
#include "rrc/rrc.h"
#include "srslte/radio/radio.h"
#include "srslte/upper/pdcp.h"
#include "srslte/upper/rlc.h"
#include "upper/gw.h"
#include "upper/nas.h"
#include "upper/usim.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/log_filter.h"
#include "srsue/hdr/ue_metrics_interface.h"
#include "ue_stack_base.h"
namespace srsue {
class ue_stack_lte : public ue_stack_base, public stack_interface_phy_lte
{
public:
ue_stack_lte();
~ue_stack_lte();
std::string get_type();
int init(const stack_args_t& args_, srslte::logger* logger_);
int init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_);
bool switch_on();
bool switch_off();
void stop();
bool get_metrics(stack_metrics_t* metrics);
bool is_rrc_connected();
// RRC interface for PHY
void in_sync() { rrc.in_sync(); };
void out_of_sync() { rrc.out_of_sync(); };
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1)
{
rrc.new_phy_meas(rsrp, rsrq, tti, earfcn, pci);
};
// MAC Interface for PHY
uint16_t get_dl_sched_rnti(uint32_t tti) { return mac.get_dl_sched_rnti(tti); }
uint16_t get_ul_sched_rnti(uint32_t tti) { return mac.get_ul_sched_rnti(tti); }
void new_grant_ul(uint32_t cc_idx, mac_grant_ul_t grant, tb_action_ul_t* action)
{
mac.new_grant_ul(cc_idx, grant, action);
}
void new_grant_dl(uint32_t cc_idx, mac_grant_dl_t grant, tb_action_dl_t* action)
{
mac.new_grant_dl(cc_idx, grant, action);
}
void tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS])
{
mac.tb_decoded(cc_idx, grant, ack);
}
void bch_decoded_ok(uint8_t* payload, uint32_t len) { mac.bch_decoded_ok(payload, len); }
void mch_decoded(uint32_t len, bool crc) { mac.mch_decoded(len, crc); }
void new_mch_dl(srslte_pdsch_grant_t phy_grant, tb_action_dl_t* action) { mac.new_mch_dl(phy_grant, action); }
void set_mbsfn_config(uint32_t nof_mbsfn_services) { mac.set_mbsfn_config(nof_mbsfn_services); }
void run_tti(const uint32_t tti) { mac.run_tti(tti); }
private:
bool running;
srsue::stack_args_t args;
srsue::mac mac;
srslte::mac_pcap mac_pcap;
srslte::nas_pcap nas_pcap;
srslte::rlc rlc;
srslte::pdcp pdcp;
srsue::rrc rrc;
srsue::nas nas;
srsue::gw gw;
srsue::usim_base* usim;
srslte::logger* logger;
// Radio and PHY log are in ue.cc
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter nas_log;
srslte::log_filter gw_log;
srslte::log_filter usim_log;
srslte::log_filter pool_log;
// RAT-specific interfaces
phy_interface_stack_lte* phy;
};
} // namespace srsue
#endif // SRSUE_UE_STACK_LTE_H

@ -33,6 +33,13 @@
namespace srsue { namespace srsue {
class gw_args_t
{
public:
std::string tun_dev_name;
std::string tun_dev_netmask;
};
class gw class gw
:public gw_interface_pdcp :public gw_interface_pdcp
,public gw_interface_nas ,public gw_interface_nas
@ -41,12 +48,10 @@ class gw
{ {
public: public:
gw(); gw();
void init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, srslte::srslte_gw_config_t); void init(pdcp_interface_gw* pdcp_, nas_interface_gw* nas_, srslte::log* gw_log_, gw_args_t);
void stop(); void stop();
void get_metrics(gw_metrics_t &m); void get_metrics(gw_metrics_t &m);
void set_netmask(std::string netmask);
void set_tundevname(const std::string & devname);
// PDCP interface // PDCP interface
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu); void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu);
@ -59,11 +64,6 @@ public:
void add_mch_port(uint32_t lcid, uint32_t port); void add_mch_port(uint32_t lcid, uint32_t port);
private: private:
bool default_netmask;
std::string netmask;
std::string tundevname;
static const int GW_THREAD_PRIO = 7; static const int GW_THREAD_PRIO = 7;
pdcp_interface_gw *pdcp; pdcp_interface_gw *pdcp;
@ -72,7 +72,7 @@ private:
srslte::byte_buffer_pool *pool; srslte::byte_buffer_pool *pool;
srslte::log *gw_log; srslte::log *gw_log;
srslte::srslte_gw_config_t cfg; gw_args_t args;
bool running; bool running;
bool run_enable; bool run_enable;

@ -22,12 +22,12 @@
#ifndef SRSUE_PCSC_USIM_H #ifndef SRSUE_PCSC_USIM_H
#define SRSUE_PCSC_USIM_H #define SRSUE_PCSC_USIM_H
#include <string>
#include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/log.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srsue/hdr/upper/usim.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/stack/upper/usim.h"
#include <string>
#include <winscard.h> #include <winscard.h>
namespace srsue { namespace srsue {

@ -58,7 +58,7 @@ class usim_base
public: public:
usim_base(); usim_base();
virtual ~usim_base(); virtual ~usim_base();
static usim_base* get_instance(usim_args_t *args, srslte::log *usim_log_); static usim_base* get_instance(usim_args_t* args);
virtual int init(usim_args_t *args, srslte::log *usim_log_) = 0; virtual int init(usim_args_t *args, srslte::log *usim_log_) = 0;
virtual void stop() = 0; virtual void stop() = 0;

@ -32,17 +32,10 @@
#include <string> #include <string>
#include <pthread.h> #include <pthread.h>
#include "mac/mac.h" #include "phy/ue_phy_base.h"
#include "phy/phy.h" #include "radio/ue_radio_base.h"
#include "rrc/rrc.h" #include "stack/ue_stack_base.h"
#include "srslte/radio/radio_multi.h" #include "ue_stack_interface.h"
#include "srslte/upper/pdcp.h"
#include "srslte/upper/rlc.h"
#include "ue_base.h"
#include "upper/gw.h"
#include "upper/nas.h"
#include "upper/usim.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"
@ -52,70 +45,88 @@
namespace srsue { namespace srsue {
/*******************************************************************************
UE Parameters
*******************************************************************************/
typedef struct {
bool enable;
std::string phy_filename;
std::string radio_filename;
} trace_args_t;
typedef struct {
std::string all_level;
int all_hex_limit;
int file_max_size;
std::string filename;
} log_args_t;
typedef struct {
bool enable;
} gui_args_t;
typedef struct {
float metrics_period_secs;
bool metrics_csv_enable;
std::string metrics_csv_filename;
} expert_args_t;
typedef struct {
rf_args_t rf;
trace_args_t trace;
log_args_t log;
gui_args_t gui;
phy_args_t phy;
stack_args_t stack;
expert_args_t expert;
} all_args_t;
/******************************************************************************* /*******************************************************************************
Main UE class Main UE class
*******************************************************************************/ *******************************************************************************/
class ue class ue : public ue_interface, public ue_metrics_interface
:public ue_base
{ {
public: public:
ue(); ue();
~ue();
bool init(all_args_t *args_); int init(const all_args_t& args_);
void stop(); void stop();
bool switch_on(); bool switch_on();
bool switch_off(); bool switch_off();
bool is_attached(); bool is_rrc_connected();
void start_plot(); void start_plot();
void print_mbms();
bool mbms_service_start(uint32_t serv, uint32_t port);
void print_pool();
static void rf_msg(srslte_rf_error_t error);
// UE metrics interface // UE metrics interface
bool get_metrics(ue_metrics_t &m); bool get_metrics(ue_metrics_t* m);
void pregenerate_signals(bool enable);
void radio_overflow(); void radio_overflow();
private: private:
virtual ~ue(); // UE consists of a radio, a PHY and a stack element
std::unique_ptr<ue_radio_base> radio;
srslte::radio radios[SRSLTE_MAX_RADIOS]; std::unique_ptr<ue_phy_base> phy;
srsue::phy phy; std::unique_ptr<ue_stack_base> stack;
srsue::mac mac;
srslte::mac_pcap mac_pcap;
srslte::nas_pcap nas_pcap;
srslte::rlc rlc;
srslte::pdcp pdcp;
srsue::rrc rrc;
srsue::nas nas;
srsue::gw gw;
srsue::usim_base* usim;
// Generic logger members
srslte::logger_stdout logger_stdout; srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file; srslte::logger_file logger_file;
srslte::logger *logger; srslte::logger *logger;
srslte::log_filter log; // Own logger for UE
all_args_t args;
srslte::byte_buffer_pool* pool;
// Helper functions
int parse_args(const all_args_t& args); // parse and validate arguments
// rf_log is on ue_base std::string get_build_mode();
std::vector<srslte::log_filter*> phy_log; std::string get_build_info();
srslte::log_filter mac_log; std::string get_build_string();
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter nas_log;
srslte::log_filter gw_log;
srslte::log_filter usim_log;
srslte::log_filter pool_log;
all_args_t *args;
bool started;
bool check_srslte_version();
}; };
} // namespace srsue } // namespace srsue

@ -1,185 +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_base.h
* Description: Base class for UEs.
*****************************************************************************/
#ifndef SRSUE_UE_BASE_H
#define SRSUE_UE_BASE_H
#include "phy/phy.h"
#include "rrc/rrc.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/radio/radio_multi.h"
#include "upper/nas.h"
#include "upper/usim.h"
#include <pthread.h>
#include <stdarg.h>
#include <string>
#include "srslte/common/logger.h"
#include "srslte/common/log_filter.h"
#include "ue_metrics_interface.h"
namespace srsue {
/*******************************************************************************
UE Parameters
*******************************************************************************/
typedef struct {
std::string dl_earfcn;
float dl_freq;
float ul_freq;
float freq_offset;
float rx_gain;
float tx_gain;
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;
typedef struct {
bool enable;
std::string filename;
bool nas_enable;
std::string nas_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 gw_level;
std::string nas_level;
std::string usim_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 gw_hex_limit;
int nas_hex_limit;
int usim_hex_limit;
int all_hex_limit;
int file_max_size;
std::string filename;
} log_args_t;
typedef struct {
bool enable;
}gui_args_t;
typedef struct {
std::string ip_netmask;
std::string ip_devname;
phy_args_t phy;
float metrics_period_secs;
bool pregenerate_signals;
bool print_buffer_state;
bool metrics_csv_enable;
std::string metrics_csv_filename;
int mbms_service;
} expert_args_t;
typedef struct {
rf_args_t rf;
pcap_args_t pcap;
log_args_t log;
gui_args_t gui;
usim_args_t usim;
rrc_args_t rrc;
nas_args_t nas;
expert_args_t expert;
} all_args_t;
typedef enum {
LTE = 0,
SRSUE_INSTANCE_TYPE_NITEMS
} srsue_instance_type_t;
static const char srsue_instance_type_text[SRSUE_INSTANCE_TYPE_NITEMS][10] = { "LTE" };
/*******************************************************************************
Main UE class
*******************************************************************************/
class ue_base
:public ue_interface
,public ue_metrics_interface
{
public:
ue_base();
virtual ~ue_base();
static ue_base* get_instance(srsue_instance_type_t type);
void cleanup(void);
virtual bool init(all_args_t *args_) = 0;
virtual void stop() = 0;
virtual bool switch_on() = 0;
virtual bool switch_off() = 0;
virtual bool is_attached() = 0;
virtual void start_plot() = 0;
virtual void print_pool() = 0;
virtual void radio_overflow() = 0;
virtual void print_mbms() = 0;
virtual bool mbms_service_start(uint32_t serv, uint32_t port) = 0;
void handle_rf_msg(srslte_rf_error_t error);
// UE metrics interface
virtual bool get_metrics(ue_metrics_t &m) = 0;
virtual void pregenerate_signals(bool enable) = 0;
srslte::log_filter rf_log;
rf_metrics_t rf_metrics;
srslte::LOG_LEVEL_ENUM level(std::string l);
std::string get_build_mode();
std::string get_build_info();
std::string get_build_string();
private:
srslte::byte_buffer_pool *pool;
};
} // namespace srsue
#endif // SRSUE_UE_BASE_H

@ -24,11 +24,11 @@
#include <stdint.h> #include <stdint.h>
#include "phy/phy_metrics.h"
#include "srslte/common/metrics_hub.h" #include "srslte/common/metrics_hub.h"
#include "upper/gw_metrics.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include "mac/mac_metrics.h" #include "stack/mac/mac_metrics.h"
#include "phy/phy_metrics.h" #include "stack/upper/gw_metrics.h"
namespace srsue { namespace srsue {
@ -37,22 +37,26 @@ typedef struct {
uint32_t rf_u; uint32_t rf_u;
uint32_t rf_l; uint32_t rf_l;
bool rf_error; bool rf_error;
}rf_metrics_t; } rf_metrics_t;
typedef struct { typedef struct {
rf_metrics_t rf;
phy_metrics_t phy;
mac_metrics_t mac[SRSLTE_MAX_CARRIERS]; mac_metrics_t mac[SRSLTE_MAX_CARRIERS];
srslte::rlc_metrics_t rlc; srslte::rlc_metrics_t rlc;
gw_metrics_t gw; gw_metrics_t gw;
}ue_metrics_t; } stack_metrics_t;
typedef struct {
rf_metrics_t rf;
phy_metrics_t phy;
stack_metrics_t stack;
} ue_metrics_t;
// UE interface // UE interface
class ue_metrics_interface : public srslte::metrics_interface<ue_metrics_t> class ue_metrics_interface : public srslte::metrics_interface<ue_metrics_t>
{ {
public: public:
virtual bool get_metrics(ue_metrics_t &m) = 0; virtual bool get_metrics(ue_metrics_t* m) = 0;
virtual bool is_attached() = 0; virtual bool is_rrc_connected() = 0;
}; };
} // namespace srsue } // namespace srsue

@ -0,0 +1,90 @@
/*
* 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

@ -18,10 +18,9 @@
# and at http://www.gnu.org/licenses/. # and at http://www.gnu.org/licenses/.
# #
add_subdirectory(radio)
add_subdirectory(phy) add_subdirectory(phy)
add_subdirectory(mac) add_subdirectory(stack)
add_subdirectory(rrc)
add_subdirectory(upper)
# Link libstdc++ and libgcc # Link libstdc++ and libgcc
if(BUILD_STATIC) if(BUILD_STATIC)
@ -32,15 +31,16 @@ if (RPATH)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif (RPATH) endif (RPATH)
add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc metrics_csv.cc) add_executable(srsue main.cc ue.cc metrics_stdout.cc metrics_csv.cc)
target_link_libraries(srsue srsue_mac target_link_libraries(srsue srsue_radio
srsue_phy srsue_phy
srsue_rrc srsue_stack
srsue_upper srsue_upper
srsue_mac
srsue_rrc
srslte_common srslte_common
srslte_phy srslte_phy
srslte_upper srslte_upper
srslte_radio
rrc_asn1 rrc_asn1
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}) ${Boost_LIBRARIES})

@ -54,7 +54,6 @@ string config_file;
void parse_args(all_args_t* args, int argc, char* argv[]) void parse_args(all_args_t* args, int argc, char* argv[])
{ {
// Command line only options // Command line only options
bpo::options_description general("General options"); bpo::options_description general("General options");
@ -66,10 +65,14 @@ void parse_args(all_args_t* args, int argc, char* argv[])
bpo::options_description common("Configuration options"); bpo::options_description common("Configuration options");
// clang-format off // clang-format off
common.add_options() common.add_options()
("rf.dl_earfcn", bpo::value<string>(&args->rf.dl_earfcn)->default_value("3400"), "Downlink EARFCN list") ("ue.radio", bpo::value<string>(&args->rf.type)->default_value("multi"), "Type of the radio [multi]")
("ue.phy", bpo::value<string>(&args->phy.type)->default_value("lte"), "Type of the PHY [lte]")
("ue.stack", bpo::value<string>(&args->stack.type)->default_value("lte"), "Type of the upper stack [lte]")
("rf.dl_earfcn", bpo::value<string>(&args->phy.dl_earfcn)->default_value("3400"), "Downlink EARFCN list")
("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset") ("rf.freq_offset", bpo::value<float>(&args->rf.freq_offset)->default_value(0), "(optional) Frequency offset")
("rf.dl_freq", bpo::value<float>(&args->rf.dl_freq)->default_value(-1), "Downlink Frequency (if positive overrides EARFCN)") ("rf.dl_freq", bpo::value<float>(&args->phy.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.ul_freq", bpo::value<float>(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)")
("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain") ("rf.rx_gain", bpo::value<float>(&args->rf.rx_gain)->default_value(-1), "Front-end receiver gain")
("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain") ("rf.tx_gain", bpo::value<float>(&args->rf.tx_gain)->default_value(-1), "Front-end transmitter gain")
("rf.nof_radios", bpo::value<uint32_t>(&args->rf.nof_radios)->default_value(1), "Number of available RF devices") ("rf.nof_radios", bpo::value<uint32_t>(&args->rf.nof_radios)->default_value(1), "Number of available RF devices")
@ -84,7 +87,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") ("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
("rf.continuous_tx", bpo::value<string>(&args->rf.continuous_tx)->default_value("auto"), "Transmit samples continuously to the radio or on bursts (auto/yes/no). Default is auto (yes for UHD, no for rest)") ("rf.continuous_tx", bpo::value<string>(&args->rf.continuous_tx)->default_value("auto"), "Transmit samples continuously to the radio or on bursts (auto/yes/no). Default is auto (yes for UHD, no for rest)")
("rrc.feature_group", bpo::value<uint32_t>(&args->rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the" ("rrc.feature_group", bpo::value<uint32_t>(&args->stack.rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the"
"UECapabilityInformation message. Default 0xe6041000") "UECapabilityInformation message. Default 0xe6041000")
("rrc.ue_category", bpo::value<string>(&args->stack.rrc.ue_category_str)->default_value(SRSLTE_UE_CATEGORY_DEFAULT), "UE Category (1 to 10)") ("rrc.ue_category", bpo::value<string>(&args->stack.rrc.ue_category_str)->default_value(SRSLTE_UE_CATEGORY_DEFAULT), "UE Category (1 to 10)")
("rrc.release", bpo::value<uint32_t>(&args->stack.rrc.release)->default_value(SRSLTE_RELEASE_DEFAULT), "UE Release (8 to 10)") ("rrc.release", bpo::value<uint32_t>(&args->stack.rrc.release)->default_value(SRSLTE_RELEASE_DEFAULT), "UE Release (8 to 10)")
@ -106,23 +109,24 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("gui.enable", bpo::value<bool>(&args->gui.enable)->default_value(false), "Enable GUI plots") ("gui.enable", bpo::value<bool>(&args->gui.enable)->default_value(false), "Enable GUI plots")
("log.phy_level", bpo::value<string>(&args->log.phy_level), "PHY log level") ("log.rf_level", bpo::value<string>(&args->rf.log_level)->default_value("error"), "RF log level")
("log.phy_lib_level", bpo::value<string>(&args->log.phy_lib_level), "PHY lib log level") ("log.phy_level", bpo::value<string>(&args->phy.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->phy.log.phy_lib_level), "PHY lib log level")
("log.mac_level", bpo::value<string>(&args->log.mac_level), "MAC log level") ("log.phy_hex_limit", bpo::value<int>(&args->phy.log.phy_hex_limit), "PHY log hex dump limit")
("log.mac_hex_limit", bpo::value<int>(&args->log.mac_hex_limit), "MAC log hex dump limit") ("log.mac_level", bpo::value<string>(&args->stack.log.mac_level), "MAC log level")
("log.rlc_level", bpo::value<string>(&args->log.rlc_level), "RLC log level") ("log.mac_hex_limit", bpo::value<int>(&args->stack.log.mac_hex_limit), "MAC log hex dump limit")
("log.rlc_hex_limit", bpo::value<int>(&args->log.rlc_hex_limit), "RLC log hex dump limit") ("log.rlc_level", bpo::value<string>(&args->stack.log.rlc_level), "RLC log level")
("log.pdcp_level", bpo::value<string>(&args->log.pdcp_level), "PDCP log level") ("log.rlc_hex_limit", bpo::value<int>(&args->stack.log.rlc_hex_limit), "RLC log hex dump limit")
("log.pdcp_hex_limit", bpo::value<int>(&args->log.pdcp_hex_limit), "PDCP log hex dump limit") ("log.pdcp_level", bpo::value<string>(&args->stack.log.pdcp_level), "PDCP log level")
("log.rrc_level", bpo::value<string>(&args->log.rrc_level), "RRC log level") ("log.pdcp_hex_limit", bpo::value<int>(&args->stack.log.pdcp_hex_limit), "PDCP log hex dump limit")
("log.rrc_hex_limit", bpo::value<int>(&args->log.rrc_hex_limit), "RRC log hex dump limit") ("log.rrc_level", bpo::value<string>(&args->stack.log.rrc_level), "RRC log level")
("log.gw_level", bpo::value<string>(&args->log.gw_level), "GW log level") ("log.rrc_hex_limit", bpo::value<int>(&args->stack.log.rrc_hex_limit), "RRC log hex dump limit")
("log.gw_hex_limit", bpo::value<int>(&args->log.gw_hex_limit), "GW log hex dump limit") ("log.gw_level", bpo::value<string>(&args->stack.log.gw_level), "GW log level")
("log.nas_level", bpo::value<string>(&args->log.nas_level), "NAS log level") ("log.gw_hex_limit", bpo::value<int>(&args->stack.log.gw_hex_limit), "GW log hex dump limit")
("log.nas_hex_limit", bpo::value<int>(&args->log.nas_hex_limit), "NAS log hex dump limit") ("log.nas_level", bpo::value<string>(&args->stack.log.nas_level), "NAS log level")
("log.usim_level", bpo::value<string>(&args->log.usim_level), "USIM log level") ("log.nas_hex_limit", bpo::value<int>(&args->stack.log.nas_hex_limit), "NAS log hex dump limit")
("log.usim_hex_limit", bpo::value<int>(&args->log.usim_hex_limit), "USIM log hex dump limit") ("log.usim_level", bpo::value<string>(&args->stack.log.usim_level), "USIM log level")
("log.usim_hex_limit", bpo::value<int>(&args->stack.log.usim_hex_limit), "USIM log hex dump limit")
("log.all_level", bpo::value<string>(&args->log.all_level)->default_value("info"), "ALL log level") ("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") ("log.all_hex_limit", bpo::value<int>(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit")
@ -130,35 +134,26 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename") ("log.filename", bpo::value<string>(&args->log.filename)->default_value("/tmp/ue.log"), "Log filename")
("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)") ("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)")
("usim.mode", bpo::value<string>(&args->usim.mode)->default_value("soft"), "USIM mode (soft or pcsc)") ("usim.mode", bpo::value<string>(&args->stack.usim.mode)->default_value("soft"), "USIM mode (soft or pcsc)")
("usim.algo", bpo::value<string>(&args->usim.algo), "USIM authentication algorithm") ("usim.algo", bpo::value<string>(&args->stack.usim.algo), "USIM authentication algorithm")
("usim.op", bpo::value<string>(&args->usim.op), "USIM operator code") ("usim.op", bpo::value<string>(&args->stack.usim.op), "USIM operator code")
("usim.opc", bpo::value<string>(&args->usim.opc), "USIM operator code (ciphered variant)") ("usim.opc", bpo::value<string>(&args->stack.usim.opc), "USIM operator code (ciphered variant)")
("usim.imsi", bpo::value<string>(&args->usim.imsi), "USIM IMSI") ("usim.imsi", bpo::value<string>(&args->stack.usim.imsi), "USIM IMSI")
("usim.imei", bpo::value<string>(&args->usim.imei), "USIM IMEI") ("usim.imei", bpo::value<string>(&args->stack.usim.imei), "USIM IMEI")
("usim.k", bpo::value<string>(&args->usim.k), "USIM K") ("usim.k", bpo::value<string>(&args->stack.usim.k), "USIM K")
("usim.pin", bpo::value<string>(&args->usim.pin), "PIN in case real SIM card is used") ("usim.pin", bpo::value<string>(&args->stack.usim.pin), "PIN in case real SIM card is used")
("usim.reader", bpo::value<string>(&args->usim.reader)->default_value(""), "Force specific PCSC reader. Default: Try all available readers.") ("usim.reader", bpo::value<string>(&args->stack.usim.reader)->default_value(""), "Force specific PCSC reader. Default: Try all available readers.")
/* Expert section */
("expert.ip_netmask",
bpo::value<string>(&args->expert.ip_netmask)->default_value("255.255.255.0"),
"Netmask of the tun_srsue device")
("expert.ip_devname",
bpo::value<string>(&args->expert.ip_devname)->default_value("tun_srsue"),
"Name of the tun_srsue device")
("expert.mbms_service", ("gw.ip_devname", bpo::value<string>(&args->stack.gw.tun_dev_name)->default_value("tun_srsue"), "Name of the tun_srsue device")
bpo::value<int>(&args->expert.mbms_service)->default_value(-1), ("gw.ip_netmask", bpo::value<string>(&args->stack.gw.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the tun_srsue device")
"automatically starts an mbms service of the number given")
/* Expert section */
("expert.phy.worker_cpu_mask", ("expert.phy.worker_cpu_mask",
bpo::value<int>(&args->expert.phy.worker_cpu_mask)->default_value(-1), bpo::value<int>(&args->phy.worker_cpu_mask)->default_value(-1),
"cpu bit mask (eg 255 = 1111 1111)") "cpu bit mask (eg 255 = 1111 1111)")
("expert.phy.sync_cpu_affinity", ("expert.phy.sync_cpu_affinity",
bpo::value<int>(&args->expert.phy.sync_cpu_affinity)->default_value(-1), bpo::value<int>(&args->phy.sync_cpu_affinity)->default_value(-1),
"index of the core used by the sync thread") "index of the core used by the sync thread")
("expert.metrics_period_secs", ("expert.metrics_period_secs",
@ -174,113 +169,105 @@ void parse_args(all_args_t* args, int argc, char* argv[])
"Metrics CSV filename") "Metrics CSV filename")
("expert.pregenerate_signals", ("expert.pregenerate_signals",
bpo::value<bool>(&args->expert.pregenerate_signals)->default_value(false), bpo::value<bool>(&args->phy.pregenerate_signals)->default_value(false),
"Pregenerate uplink signals after attach. Improves CPU performance.") "Pregenerate uplink signals after attach. Improves CPU performance.")
("expert.print_buffer_state",
bpo::value<bool>(&args->expert.print_buffer_state)->default_value(false),
"Prints on the console the buffer state every 10 seconds")
("expert.rssi_sensor_enabled",
bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(false),
"Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault")
("expert.rx_gain_offset", ("expert.rx_gain_offset",
bpo::value<float>(&args->expert.phy.rx_gain_offset)->default_value(62), bpo::value<float>(&args->phy.rx_gain_offset)->default_value(62),
"RX Gain offset to add to rx_gain to correct RSRP value") "RX Gain offset to add to rx_gain to correct RSRP value")
("expert.prach_gain", ("expert.prach_gain",
bpo::value<float>(&args->expert.phy.prach_gain)->default_value(-1.0), bpo::value<float>(&args->phy.prach_gain)->default_value(-1.0),
"Disable PRACH power control") "Disable PRACH power control")
("expert.cqi_max", ("expert.cqi_max",
bpo::value<int>(&args->expert.phy.cqi_max)->default_value(15), bpo::value<int>(&args->phy.cqi_max)->default_value(15),
"Upper bound on the maximum CQI to be reported. Default 15.") "Upper bound on the maximum CQI to be reported. Default 15.")
("expert.cqi_fixed", ("expert.cqi_fixed",
bpo::value<int>(&args->expert.phy.cqi_fixed)->default_value(-1), bpo::value<int>(&args->phy.cqi_fixed)->default_value(-1),
"Fixes the reported CQI to a constant value. Default disabled.") "Fixes the reported CQI to a constant value. Default disabled.")
("expert.sfo_correct_period", ("expert.sfo_correct_period",
bpo::value<uint32_t>(&args->expert.phy.sfo_correct_period)->default_value(DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD), bpo::value<uint32_t>(&args->phy.sfo_correct_period)->default_value(DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD),
"Period in ms to correct sample time") "Period in ms to correct sample time")
("expert.sfo_emma", ("expert.sfo_emma",
bpo::value<float>(&args->expert.phy.sfo_ema)->default_value(DEFAULT_SFO_EMA_COEFF), bpo::value<float>(&args->phy.sfo_ema)->default_value(DEFAULT_SFO_EMA_COEFF),
"EMA coefficient to average sample offsets used to compute SFO") "EMA coefficient to average sample offsets used to compute SFO")
("expert.snr_ema_coeff", ("expert.snr_ema_coeff",
bpo::value<float>(&args->expert.phy.snr_ema_coeff)->default_value(0.1), bpo::value<float>(&args->phy.snr_ema_coeff)->default_value(0.1),
"Sets the SNR exponential moving average coefficient (Default 0.1)") "Sets the SNR exponential moving average coefficient (Default 0.1)")
("expert.snr_estim_alg", ("expert.snr_estim_alg",
bpo::value<string>(&args->expert.phy.snr_estim_alg)->default_value("refs"), bpo::value<string>(&args->phy.snr_estim_alg)->default_value("refs"),
"Sets the noise estimation algorithm. (Default refs)") "Sets the noise estimation algorithm. (Default refs)")
("expert.pdsch_max_its", ("expert.pdsch_max_its",
bpo::value<int>(&args->expert.phy.pdsch_max_its)->default_value(8), bpo::value<int>(&args->phy.pdsch_max_its)->default_value(8),
"Maximum number of turbo decoder iterations") "Maximum number of turbo decoder iterations")
("expert.nof_phy_threads", ("expert.nof_phy_threads",
bpo::value<int>(&args->expert.phy.nof_phy_threads)->default_value(3), bpo::value<int>(&args->phy.nof_phy_threads)->default_value(3),
"Number of PHY threads") "Number of PHY threads")
("expert.equalizer_mode", ("expert.equalizer_mode",
bpo::value<string>(&args->expert.phy.equalizer_mode)->default_value("mmse"), bpo::value<string>(&args->phy.equalizer_mode)->default_value("mmse"),
"Equalizer mode") "Equalizer mode")
("expert.intra_freq_meas_len_ms", ("expert.intra_freq_meas_len_ms",
bpo::value<uint32_t>(&args->expert.phy.intra_freq_meas_len_ms)->default_value(20), bpo::value<uint32_t>(&args->phy.intra_freq_meas_len_ms)->default_value(20),
"Duration of the intra-frequency neighbour cell measurement in ms.") "Duration of the intra-frequency neighbour cell measurement in ms.")
("expert.intra_freq_meas_period_ms", ("expert.intra_freq_meas_period_ms",
bpo::value<uint32_t>(&args->expert.phy.intra_freq_meas_period_ms)->default_value(200), bpo::value<uint32_t>(&args->phy.intra_freq_meas_period_ms)->default_value(200),
"Period of intra-frequency neighbour cell measurement in ms. Maximum as per 3GPP is 200 ms.") "Period of intra-frequency neighbour cell measurement in ms. Maximum as per 3GPP is 200 ms.")
("expert.cfo_is_doppler", ("expert.cfo_is_doppler",
bpo::value<bool>(&args->expert.phy.cfo_is_doppler)->default_value(false), bpo::value<bool>(&args->phy.cfo_is_doppler)->default_value(false),
"Assume detected CFO is doppler and correct the UL in the same direction. If disabled, the CFO is assumed" "Assume detected CFO is doppler and correct the UL in the same direction. If disabled, the CFO is assumed"
"to be caused by the local oscillator and the UL correction is in the opposite direction. Default assumes oscillator.") "to be caused by the local oscillator and the UL correction is in the opposite direction. Default assumes oscillator.")
("expert.cfo_integer_enabled", ("expert.cfo_integer_enabled",
bpo::value<bool>(&args->expert.phy.cfo_integer_enabled)->default_value(false), bpo::value<bool>(&args->phy.cfo_integer_enabled)->default_value(false),
"Enables integer CFO estimation and correction.") "Enables integer CFO estimation and correction.")
("expert.cfo_correct_tol_hz", ("expert.cfo_correct_tol_hz",
bpo::value<float>(&args->expert.phy.cfo_correct_tol_hz)->default_value(1.0), bpo::value<float>(&args->phy.cfo_correct_tol_hz)->default_value(1.0),
"Tolerance (in Hz) for digital CFO compensation (needs to be low if interpolate_subframe_enabled=true.") "Tolerance (in Hz) for digital CFO compensation (needs to be low if interpolate_subframe_enabled=true.")
("expert.cfo_pss_ema", ("expert.cfo_pss_ema",
bpo::value<float>(&args->expert.phy.cfo_pss_ema)->default_value(DEFAULT_CFO_EMA_TRACK), bpo::value<float>(&args->phy.cfo_pss_ema)->default_value(DEFAULT_CFO_EMA_TRACK),
"CFO Exponential Moving Average coefficient for PSS estimation during TRACK.") "CFO Exponential Moving Average coefficient for PSS estimation during TRACK.")
("expert.cfo_ref_mask", ("expert.cfo_ref_mask",
bpo::value<uint32_t>(&args->expert.phy.cfo_ref_mask)->default_value(1023), bpo::value<uint32_t>(&args->phy.cfo_ref_mask)->default_value(1023),
"Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)") "Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)")
("expert.cfo_loop_bw_pss", ("expert.cfo_loop_bw_pss",
bpo::value<float>(&args->expert.phy.cfo_loop_bw_pss)->default_value(DEFAULT_CFO_BW_PSS), bpo::value<float>(&args->phy.cfo_loop_bw_pss)->default_value(DEFAULT_CFO_BW_PSS),
"CFO feedback loop bandwidth for samples from PSS") "CFO feedback loop bandwidth for samples from PSS")
("expert.cfo_loop_bw_ref", ("expert.cfo_loop_bw_ref",
bpo::value<float>(&args->expert.phy.cfo_loop_bw_ref)->default_value(DEFAULT_CFO_BW_REF), bpo::value<float>(&args->phy.cfo_loop_bw_ref)->default_value(DEFAULT_CFO_BW_REF),
"CFO feedback loop bandwidth for samples from RS") "CFO feedback loop bandwidth for samples from RS")
("expert.cfo_loop_pss_tol", ("expert.cfo_loop_pss_tol",
bpo::value<float>(&args->expert.phy.cfo_loop_pss_tol)->default_value(DEFAULT_CFO_PSS_MIN), bpo::value<float>(&args->phy.cfo_loop_pss_tol)->default_value(DEFAULT_CFO_PSS_MIN),
"Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop" "Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop"
"and RS estimations are used instead (when available)") "and RS estimations are used instead (when available)")
("expert.cfo_loop_ref_min", ("expert.cfo_loop_ref_min",
bpo::value<float>(&args->expert.phy.cfo_loop_ref_min)->default_value(DEFAULT_CFO_REF_MIN), bpo::value<float>(&args->phy.cfo_loop_ref_min)->default_value(DEFAULT_CFO_REF_MIN),
"Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop") "Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop")
("expert.cfo_loop_pss_conv", ("expert.cfo_loop_pss_conv",
bpo::value<uint32_t>(&args->expert.phy.cfo_loop_pss_conv)->default_value(DEFAULT_PSS_STABLE_TIMEOUT), bpo::value<uint32_t>(&args->phy.cfo_loop_pss_conv)->default_value(DEFAULT_PSS_STABLE_TIMEOUT),
"After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.") "After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.")
("expert.sic_pss_enabled", ("expert.sic_pss_enabled",
bpo::value<bool>(&args->expert.phy.sic_pss_enabled)->default_value(false), bpo::value<bool>(&args->phy.sic_pss_enabled)->default_value(false),
"Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.") "Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells. Must be disabled if cells have identical channel and timing.")
("phy.interpolate_subframe_enabled", ("phy.interpolate_subframe_enabled",
@ -288,31 +275,31 @@ void parse_args(all_args_t* args, int argc, char* argv[])
"Interpolates in the time domain the channel estimates within 1 subframe.") "Interpolates in the time domain the channel estimates within 1 subframe.")
("expert.estimator_fil_auto", ("expert.estimator_fil_auto",
bpo::value<bool>(&args->expert.phy.estimator_fil_auto)->default_value(false), bpo::value<bool>(&args->phy.estimator_fil_auto)->default_value(false),
"The channel estimator smooths the channel estimate with an adaptative filter.") "The channel estimator smooths the channel estimate with an adaptative filter.")
("expert.estimator_fil_stddev", ("expert.estimator_fil_stddev",
bpo::value<float>(&args->expert.phy.estimator_fil_stddev)->default_value(1.0f), bpo::value<float>(&args->phy.estimator_fil_stddev)->default_value(1.0f),
"Sets the channel estimator smooth gaussian filter standard deviation.") "Sets the channel estimator smooth gaussian filter standard deviation.")
("expert.estimator_fil_order", ("expert.estimator_fil_order",
bpo::value<uint32_t>(&args->expert.phy.estimator_fil_order)->default_value(4), bpo::value<uint32_t>(&args->phy.estimator_fil_order)->default_value(4),
"Sets the channel estimator smooth gaussian filter order (even values perform better).") "Sets the channel estimator smooth gaussian filter order (even values perform better).")
("expert.snr_to_cqi_offset", ("expert.snr_to_cqi_offset",
bpo::value<float>(&args->expert.phy.snr_to_cqi_offset)->default_value(0), bpo::value<float>(&args->phy.snr_to_cqi_offset)->default_value(0),
"Sets an offset in the SNR to CQI table. This is used to adjust the reported CQI.") "Sets an offset in the SNR to CQI table. This is used to adjust the reported CQI.")
("expert.sss_algorithm", ("expert.sss_algorithm",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"), bpo::value<string>(&args->phy.sss_algorithm)->default_value("full"),
"Selects the SSS estimation algorithm.") "Selects the SSS estimation algorithm.")
("expert.pdsch_csi_enabled", ("expert.pdsch_csi_enabled",
bpo::value<bool>(&args->expert.phy.pdsch_csi_enabled)->default_value(true), bpo::value<bool>(&args->phy.pdsch_csi_enabled)->default_value(true),
"Stores the Channel State Information and uses it for weightening the softbits. It is only used in TM1.") "Stores the Channel State Information and uses it for weightening the softbits. It is only used in TM1.")
("expert.pdsch_8bit_decoder", ("expert.pdsch_8bit_decoder",
bpo::value<bool>(&args->expert.phy.pdsch_8bit_decoder)->default_value(false), bpo::value<bool>(&args->phy.pdsch_8bit_decoder)->default_value(false),
"Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)"); "Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)");
// Positional options - config file location // Positional options - config file location
@ -383,88 +370,68 @@ void parse_args(all_args_t* args, int argc, char* argv[])
cout << "Conflicting options OP and OPc. Please configure either one or the other." << endl; cout << "Conflicting options OP and OPc. Please configure either one or the other." << endl;
exit(1); exit(1);
} else { } else {
args->usim.using_op = vm.count("usim.op"); args->stack.usim.using_op = vm.count("usim.op");
} }
// Apply all_level to any unset layers // Apply all_level to any unset layers
if (vm.count("log.all_level")) { if (vm.count("log.all_level")) {
if (!vm.count("log.phy_level")) { if (!vm.count("log.phy_level")) {
args->log.phy_level = args->log.all_level; args->rf.log_level = args->log.all_level;
}
if (!vm.count("log.phy_level")) {
args->phy.log.phy_level = args->log.all_level;
} }
if (!vm.count("log.phy_lib_level")) { if (!vm.count("log.phy_lib_level")) {
args->log.phy_lib_level = args->log.all_level; args->phy.log.phy_lib_level = args->log.all_level;
} }
if (!vm.count("log.mac_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")) { 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")) { 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")) { 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.nas_level")) { if (!vm.count("log.nas_level")) {
args->log.nas_level = args->log.all_level; args->stack.log.nas_level = args->log.all_level;
} }
if (!vm.count("log.gw_level")) { if (!vm.count("log.gw_level")) {
args->log.gw_level = args->log.all_level; args->stack.log.gw_level = args->log.all_level;
} }
if (!vm.count("log.usim_level")) { if (!vm.count("log.usim_level")) {
args->log.usim_level = args->log.all_level; args->stack.log.usim_level = args->log.all_level;
} }
} }
// Apply all_hex_limit to any unset layers // Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) { if (vm.count("log.all_hex_limit")) {
if (!vm.count("log.phy_hex_limit")) { if (!vm.count("log.phy_hex_limit")) {
args->log.phy_hex_limit = args->log.all_hex_limit; args->phy.log.phy_hex_limit = args->log.all_hex_limit;
} }
if (!vm.count("log.mac_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")) { 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")) { 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")) { 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.nas_hex_limit")) { if (!vm.count("log.nas_hex_limit")) {
args->log.nas_hex_limit = args->log.all_hex_limit; args->stack.log.nas_hex_limit = args->log.all_hex_limit;
} }
if (!vm.count("log.gw_hex_limit")) { if (!vm.count("log.gw_hex_limit")) {
args->log.gw_hex_limit = args->log.all_hex_limit; args->stack.log.gw_hex_limit = args->log.all_hex_limit;
} }
if (!vm.count("log.usim_hex_limit")) { if (!vm.count("log.usim_hex_limit")) {
args->log.usim_hex_limit = args->log.all_hex_limit; args->stack.log.usim_hex_limit = args->log.all_hex_limit;
}
}
if (args->expert.mbms_service > -1) {
if (!args->expert.phy.interpolate_subframe_enabled) {
fprintf(stderr,
"interpolate_subframe_enabled = %d, While using MBMS, "
"please set interpolate_subframe_enabled to true\n",
args->expert.phy.interpolate_subframe_enabled);
exit(1);
}
if (args->expert.phy.nof_phy_threads > 2) {
fprintf(stderr,
"nof_phy_threads = %d, While using MBMS, please set "
"number of phy threads to 1 or 2\n",
args->expert.phy.nof_phy_threads);
exit(1);
}
if ((0 == args->expert.phy.snr_estim_alg.find("refs"))) {
fprintf(stderr,
"snr_estim_alg = refs, While using MBMS, please set "
"algorithm to pss or empty \n");
exit(1);
} }
} }
} }
@ -473,9 +440,6 @@ static int sigcnt = 0;
static bool running = true; static bool running = true;
static bool do_metrics = false; static bool do_metrics = false;
metrics_stdout metrics_screen; metrics_stdout metrics_screen;
static bool show_mbms = false;
static bool mbms_service_start = false;
uint32_t serv, port;
void sig_int_handler(int signo) void sig_int_handler(int signo)
{ {
@ -512,26 +476,6 @@ void* input_loop(void* m)
cout << "Receiving zeros for " << zero_tti << " ms" << endl; cout << "Receiving zeros for " << zero_tti << " ms" << endl;
} else if (0 == key.compare("q")) { } else if (0 == key.compare("q")) {
running = false; running = false;
} else if (0 == key.compare("mbms")) {
show_mbms = true;
} else if (key.find("mbms_service_start") != string::npos) {
char* dup = strdup(key.c_str());
strtok(dup, " ");
char* s = strtok(NULL, " ");
char* p = strtok(NULL, " ");
if (NULL == s) {
cout << "Usage: mbms_service_start <service_id> <port_number>" << endl;
goto free_mem;
}
serv = atoi(s);
if (NULL == p) {
cout << "Usage: mbms_service_start <service_id> <port_number>" << endl;
goto free_mem;
}
port = atoi(p);
mbms_service_start = true;
free_mem:
free(dup);
} }
} }
} }
@ -540,86 +484,55 @@ void* input_loop(void* m)
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
srslte::metrics_hub<ue_metrics_t> metricshub;
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler); signal(SIGTERM, sig_int_handler);
all_args_t args;
srslte_debug_handle_crash(argc, argv); srslte_debug_handle_crash(argc, argv);
all_args_t args = {};
parse_args(&args, argc, argv); parse_args(&args, argc, argv);
srsue_instance_type_t type = LTE; // Create UE instance
ue_base* ue = ue_base::get_instance(type); srsue::ue ue;
if (!ue) { if (ue.init(args)) {
cout << "Error creating UE instance." << endl << endl; ue.stop();
exit(1); return SRSLTE_ERROR;
}
cout << "--- Software Radio Systems " << srsue_instance_type_text[type] << " UE ---" << endl << endl;
if (!ue->init(&args)) {
exit(1);
} }
metricshub.init(ue, args.expert.metrics_period_secs); srslte::metrics_hub<ue_metrics_t> metricshub;
metricshub.init(&ue, args.expert.metrics_period_secs);
metricshub.add_listener(&metrics_screen); metricshub.add_listener(&metrics_screen);
metrics_screen.set_ue_handle(ue); metrics_screen.set_ue_handle(&ue);
metrics_csv metrics_file(args.expert.metrics_csv_filename); metrics_csv metrics_file(args.expert.metrics_csv_filename);
if (args.expert.metrics_csv_enable) { if (args.expert.metrics_csv_enable) {
metricshub.add_listener(&metrics_file); metricshub.add_listener(&metrics_file);
metrics_file.set_ue_handle(ue); metrics_file.set_ue_handle(&ue);
} }
pthread_t input; pthread_t input;
pthread_create(&input, NULL, &input_loop, &args); pthread_create(&input, NULL, &input_loop, &args);
cout << "Attaching UE..." << endl; cout << "Attaching UE..." << endl;
while (!ue->switch_on() && running) { while (!ue.switch_on() && running) {
sleep(1); sleep(1);
} }
if (running) { if (running) {
if (args.expert.pregenerate_signals) {
cout << "Pre-generating signals..." << endl;
ue->pregenerate_signals(true);
cout << "Done pregenerating signals." << endl;
}
if (args.gui.enable) { if (args.gui.enable) {
ue->start_plot(); ue.start_plot();
}
// Auto-start MBMS service by default
if (args.expert.mbms_service > -1) {
serv = args.expert.mbms_service;
port = 4321;
mbms_service_start = true;
} }
} }
int cnt = 0;
while (running) { while (running) {
if (mbms_service_start) {
if (ue->mbms_service_start(serv, port)) {
mbms_service_start = false;
}
}
if (show_mbms) {
show_mbms = false;
ue->print_mbms();
}
if (args.expert.print_buffer_state) {
cnt++;
if (cnt == 10) {
cnt = 0;
ue->print_pool();
}
}
sleep(1); sleep(1);
} }
ue->switch_off();
ue.switch_off();
pthread_cancel(input); pthread_cancel(input);
pthread_join(input, NULL); pthread_join(input, NULL);
metricshub.stop(); metricshub.stop();
ue->stop(); ue.stop();
ue->cleanup();
cout << "--- exiting ---" << endl; cout << "--- exiting ---" << endl;
exit(0);
return SRSLTE_SUCCESS;
} }

@ -87,7 +87,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
// Sum DL rate for all CCs // Sum DL rate for all CCs
float rx_brate = 0; float rx_brate = 0;
for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) {
rx_brate += metrics.mac[r].rx_brate; rx_brate += metrics.stack.mac[r].rx_brate;
} }
file << float_to_string(rx_brate / period_usec * 1e6, 2); file << float_to_string(rx_brate / period_usec * 1e6, 2);
@ -95,8 +95,8 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
int rx_pkts = 0; int rx_pkts = 0;
int rx_errors = 0; int rx_errors = 0;
for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) {
rx_pkts += metrics.mac[r].rx_pkts; rx_pkts += metrics.stack.mac[r].rx_pkts;
rx_errors += metrics.mac[r].rx_errors; rx_errors += metrics.stack.mac[r].rx_errors;
} }
if (rx_pkts > 0) { if (rx_pkts > 0) {
file << float_to_string((float)100 * rx_errors / rx_pkts, 1); file << float_to_string((float)100 * rx_errors / rx_pkts, 1);
@ -106,12 +106,12 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
file << float_to_string(metrics.phy.sync.ta_us, 2); file << float_to_string(metrics.phy.sync.ta_us, 2);
file << float_to_string(metrics.phy.ul[0].mcs, 2); file << float_to_string(metrics.phy.ul[0].mcs, 2);
file << float_to_string((float)metrics.mac[0].ul_buffer, 2); file << float_to_string((float)metrics.stack.mac[0].ul_buffer, 2);
// Sum UL rate for all CCs // Sum UL rate for all CCs
float tx_brate = 0; float tx_brate = 0;
for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) {
tx_brate += metrics.mac[r].tx_brate; tx_brate += metrics.stack.mac[r].tx_brate;
} }
file << float_to_string(tx_brate / period_usec * 1e6, 2); file << float_to_string(tx_brate / period_usec * 1e6, 2);
@ -119,8 +119,8 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
int tx_pkts = 0; int tx_pkts = 0;
int tx_errors = 0; int tx_errors = 0;
for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) { for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) {
tx_pkts += metrics.mac[r].tx_pkts; tx_pkts += metrics.stack.mac[r].tx_pkts;
tx_errors += metrics.mac[r].tx_errors; tx_errors += metrics.stack.mac[r].tx_errors;
} }
if (tx_pkts > 0) { if (tx_pkts > 0) {
file << float_to_string((float)100 * tx_errors / tx_pkts, 1); file << float_to_string((float)100 * tx_errors / tx_pkts, 1);
@ -131,7 +131,7 @@ void metrics_csv::set_metrics(ue_metrics_t &metrics, const uint32_t period_usec)
file << float_to_string(metrics.rf.rf_o, 2); file << float_to_string(metrics.rf.rf_o, 2);
file << float_to_string(metrics.rf.rf_u, 2); file << float_to_string(metrics.rf.rf_u, 2);
file << float_to_string(metrics.rf.rf_l, 2); file << float_to_string(metrics.rf.rf_l, 2);
file << (ue->is_attached() ? "1.0" : "0.0"); file << (ue->is_rrc_connected() ? "1.0" : "0.0");
file << "\n"; file << "\n";
n_reports++; n_reports++;

@ -63,7 +63,7 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us
if(!do_print || ue == NULL) if(!do_print || ue == NULL)
return; return;
if (!ue->is_attached()) { if (!ue->is_rrc_connected()) {
cout << "--- disconnected ---" << endl; cout << "--- disconnected ---" << endl;
return; return;
} }
@ -84,9 +84,9 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us
cout << float_to_string(metrics.phy.dl[r].sinr, 2); cout << float_to_string(metrics.phy.dl[r].sinr, 2);
cout << float_to_string(metrics.phy.dl[r].turbo_iters, 2); cout << float_to_string(metrics.phy.dl[r].turbo_iters, 2);
cout << float_to_eng_string((float)metrics.mac[r].rx_brate / period_usec * 1e6, 2); cout << float_to_eng_string((float)metrics.stack.mac[r].rx_brate / period_usec * 1e6, 2);
if (metrics.mac[r].rx_pkts > 0) { if (metrics.stack.mac[r].rx_pkts > 0) {
cout << float_to_string((float)100 * metrics.mac[r].rx_errors / metrics.mac[r].rx_pkts, 1) << "%"; cout << float_to_string((float)100 * metrics.stack.mac[r].rx_errors / metrics.stack.mac[r].rx_pkts, 1) << "%";
} else { } else {
cout << float_to_string(0, 1) << "%"; cout << float_to_string(0, 1) << "%";
} }
@ -94,10 +94,10 @@ void metrics_stdout::set_metrics(ue_metrics_t &metrics, const uint32_t period_us
cout << float_to_string(metrics.phy.sync.ta_us, 2); cout << float_to_string(metrics.phy.sync.ta_us, 2);
cout << float_to_string(metrics.phy.ul[r].mcs, 2); cout << float_to_string(metrics.phy.ul[r].mcs, 2);
cout << float_to_eng_string((float)metrics.mac[r].ul_buffer, 2); cout << float_to_eng_string((float)metrics.stack.mac[r].ul_buffer, 2);
cout << float_to_eng_string((float)metrics.mac[r].tx_brate / period_usec * 1e6, 2); cout << float_to_eng_string((float)metrics.stack.mac[r].tx_brate / period_usec * 1e6, 2);
if (metrics.mac[r].tx_pkts > 0) { if (metrics.stack.mac[r].tx_pkts > 0) {
cout << float_to_string((float)100 * metrics.mac[r].tx_errors / metrics.mac[r].tx_pkts, 1) << "%"; cout << float_to_string((float)100 * metrics.stack.mac[r].tx_errors / metrics.stack.mac[r].tx_pkts, 1) << "%";
} else { } else {
cout << float_to_string(0, 1) << "%"; cout << float_to_string(0, 1) << "%";
} }

@ -80,7 +80,7 @@ static double callback_set_rx_gain(void* h, double gain)
return ((async_scell_recv*)h)->set_rx_gain(gain); return ((async_scell_recv*)h)->set_rx_gain(gain);
} }
void async_scell_recv::init(srslte::radio* _radio_handler, phy_common* _worker_com, srslte::log* _log_h) void async_scell_recv::init(radio_interface_phy* _radio_handler, phy_common* _worker_com, srslte::log* _log_h)
{ {
// Get handlers // Get handlers
radio_h = _radio_handler; radio_h = _radio_handler;
@ -283,7 +283,6 @@ bool async_scell_recv::set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell
// Detect change in cell configuration // Detect change in cell configuration
if (memcmp(&cell, _cell, sizeof(srslte_cell_t)) != 0) { if (memcmp(&cell, _cell, sizeof(srslte_cell_t)) != 0) {
// Set sampling rate, if number of PRB changed // Set sampling rate, if number of PRB changed
if (cell.nof_prb != _cell->nof_prb && ret) { if (cell.nof_prb != _cell->nof_prb && ret) {
double srate = srslte_sampling_freq_hz(_cell->nof_prb); double srate = srslte_sampling_freq_hz(_cell->nof_prb);
@ -298,7 +297,7 @@ bool async_scell_recv::set_scell_cell(uint32_t carrier_idx, srslte_cell_t* _cell
} }
// Copy cell // Copy cell
memcpy(&cell, _cell, sizeof(srslte_cell_t)); cell = *_cell;
reset_ue_sync = true; reset_ue_sync = true;
// Set cell in ue sync // Set cell in ue sync

@ -136,7 +136,7 @@ void cc_worker::reset()
bzero(&dl_metrics, sizeof(dl_metrics_t)); bzero(&dl_metrics, sizeof(dl_metrics_t));
bzero(&ul_metrics, sizeof(ul_metrics_t)); bzero(&ul_metrics, sizeof(ul_metrics_t));
phy_interface_rrc::phy_cfg_t empty_cfg = {}; phy_interface_rrc_lte::phy_cfg_t empty_cfg = {};
// defaults // defaults
empty_cfg.common.pucch_cnfg.delta_pucch_shift.value = pucch_cfg_common_s::delta_pucch_shift_opts::ds1; empty_cfg.common.pucch_cnfg.delta_pucch_shift.value = pucch_cfg_common_s::delta_pucch_shift_opts::ds1;
empty_cfg.common.ul_pwr_ctrl.alpha.value = alpha_r12_opts::al0; empty_cfg.common.ul_pwr_ctrl.alpha.value = alpha_r12_opts::al0;
@ -267,7 +267,7 @@ bool cc_worker::work_dl_regular()
{ {
bool dl_ack[SRSLTE_MAX_CODEWORDS]; bool dl_ack[SRSLTE_MAX_CODEWORDS];
mac_interface_phy::tb_action_dl_t dl_action; mac_interface_phy_lte::tb_action_dl_t dl_action;
bool found_dl_grant = false; bool found_dl_grant = false;
@ -333,16 +333,16 @@ bool cc_worker::work_dl_regular()
ue_dl_cfg.cfg.pdsch.rnti = dci_dl.rnti; ue_dl_cfg.cfg.pdsch.rnti = dci_dl.rnti;
// Generate MAC grant // Generate MAC grant
mac_interface_phy::mac_grant_dl_t mac_grant; mac_interface_phy_lte::mac_grant_dl_t mac_grant;
dl_phy_to_mac_grant(&ue_dl_cfg.cfg.pdsch.grant, &dci_dl, &mac_grant); dl_phy_to_mac_grant(&ue_dl_cfg.cfg.pdsch.grant, &dci_dl, &mac_grant);
// Save ACK resource configuration // Save ACK resource configuration
srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce}; srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce};
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
phy->mac->new_grant_dl(cc_idx, mac_grant, &dl_action); phy->stack->new_grant_dl(cc_idx, mac_grant, &dl_action);
decode_pdsch(ack_resource, &dl_action, dl_ack); decode_pdsch(ack_resource, &dl_action, dl_ack);
phy->mac->tb_decoded(cc_idx, mac_grant, dl_ack); phy->stack->tb_decoded(cc_idx, mac_grant, dl_ack);
} }
/* Decode PHICH */ /* Decode PHICH */
@ -353,7 +353,7 @@ bool cc_worker::work_dl_regular()
bool cc_worker::work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg) bool cc_worker::work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg)
{ {
mac_interface_phy::tb_action_dl_t dl_action; mac_interface_phy_lte::tb_action_dl_t dl_action;
// Configure MBSFN settings // Configure MBSFN settings
srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_cfg.mbsfn_area_id); srslte_ue_dl_set_mbsfn_area_id(&ue_dl, mbsfn_cfg.mbsfn_area_id);
@ -378,12 +378,12 @@ bool cc_worker::work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg)
srslte_ra_dl_compute_nof_re(&cell, &sf_cfg_dl, &pmch_cfg.pdsch_cfg.grant); srslte_ra_dl_compute_nof_re(&cell, &sf_cfg_dl, &pmch_cfg.pdsch_cfg.grant);
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC // Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
phy->mac->new_mch_dl(pmch_cfg.pdsch_cfg.grant, &dl_action); phy->stack->new_mch_dl(pmch_cfg.pdsch_cfg.grant, &dl_action);
bool mch_decoded = true; bool mch_decoded = true;
if (!decode_pmch(&dl_action, &mbsfn_cfg)) { if (!decode_pmch(&dl_action, &mbsfn_cfg)) {
mch_decoded = false; mch_decoded = false;
} }
phy->mac->mch_decoded((uint32_t)pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8, mch_decoded); phy->stack->mch_decoded((uint32_t)pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8, mch_decoded);
} else if (mbsfn_cfg.is_mcch) { } else if (mbsfn_cfg.is_mcch) {
// release lock in phy_common // release lock in phy_common
phy->set_mch_period_stop(0); phy->set_mch_period_stop(0);
@ -397,7 +397,7 @@ bool cc_worker::work_dl_mbsfn(srslte_mbsfn_cfg_t mbsfn_cfg)
void cc_worker::dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant, void cc_worker::dl_phy_to_mac_grant(srslte_pdsch_grant_t* phy_grant,
srslte_dci_dl_t* dl_dci, srslte_dci_dl_t* dl_dci,
srsue::mac_interface_phy::mac_grant_dl_t* mac_grant) srsue::mac_interface_phy_lte::mac_grant_dl_t* mac_grant)
{ {
/* Fill MAC dci structure */ /* Fill MAC dci structure */
mac_grant->pid = dl_dci->pid; mac_grant->pid = dl_dci->pid;
@ -423,7 +423,7 @@ int cc_worker::decode_pdcch_dl()
srslte_dci_dl_t dci[SRSLTE_MAX_CARRIERS]; srslte_dci_dl_t dci[SRSLTE_MAX_CARRIERS];
ZERO_OBJECT(dci); ZERO_OBJECT(dci);
uint16_t dl_rnti = phy->mac->get_dl_sched_rnti(CURRENT_TTI); uint16_t dl_rnti = phy->stack->get_dl_sched_rnti(CURRENT_TTI);
if (dl_rnti) { if (dl_rnti) {
/* Blind search first without cross scheduling then with it if enabled */ /* Blind search first without cross scheduling then with it if enabled */
@ -456,7 +456,7 @@ int cc_worker::decode_pdcch_dl()
} }
int cc_worker::decode_pdsch(srslte_pdsch_ack_resource_t ack_resource, int cc_worker::decode_pdsch(srslte_pdsch_ack_resource_t ack_resource,
mac_interface_phy::tb_action_dl_t* action, mac_interface_phy_lte::tb_action_dl_t* action,
bool mac_acks[SRSLTE_MAX_CODEWORDS]) bool mac_acks[SRSLTE_MAX_CODEWORDS])
{ {
@ -516,7 +516,7 @@ int cc_worker::decode_pdsch(srslte_pdsch_ack_resource_t ack_resource,
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int cc_worker::decode_pmch(mac_interface_phy::tb_action_dl_t* action, srslte_mbsfn_cfg_t* mbsfn_cfg) int cc_worker::decode_pmch(mac_interface_phy_lte::tb_action_dl_t* action, srslte_mbsfn_cfg_t* mbsfn_cfg)
{ {
srslte_pdsch_res_t pmch_dec; srslte_pdsch_res_t pmch_dec;
@ -670,8 +670,8 @@ bool cc_worker::work_ul(srslte_uci_data_t* uci_data)
bool signal_ready; bool signal_ready;
srslte_dci_ul_t dci_ul = {}; srslte_dci_ul_t dci_ul = {};
mac_interface_phy::mac_grant_ul_t ul_mac_grant = {}; mac_interface_phy_lte::mac_grant_ul_t ul_mac_grant = {};
mac_interface_phy::tb_action_ul_t ul_action = {}; mac_interface_phy_lte::tb_action_ul_t ul_action = {};
uint32_t pid = 0; uint32_t pid = 0;
bool ul_grant_available = phy->get_ul_pending_grant(&sf_cfg_ul, cc_idx, &pid, &dci_ul); bool ul_grant_available = phy->get_ul_pending_grant(&sf_cfg_ul, cc_idx, &pid, &dci_ul);
@ -711,7 +711,7 @@ bool cc_worker::work_ul(srslte_uci_data_t* uci_data)
// Fill MAC dci // Fill MAC dci
ul_phy_to_mac_grant(&ue_ul_cfg.ul_cfg.pusch.grant, &dci_ul, pid, ul_grant_available, &ul_mac_grant); ul_phy_to_mac_grant(&ue_ul_cfg.ul_cfg.pusch.grant, &dci_ul, pid, ul_grant_available, &ul_mac_grant);
phy->mac->new_grant_ul(cc_idx, ul_mac_grant, &ul_action); phy->stack->new_grant_ul(cc_idx, ul_mac_grant, &ul_action);
// Calculate PUSCH Hopping procedure // Calculate PUSCH Hopping procedure
ue_ul_cfg.ul_cfg.hopping.current_tx_nb = ul_action.current_tx_nb; ue_ul_cfg.ul_cfg.hopping.current_tx_nb = ul_action.current_tx_nb;
@ -722,7 +722,7 @@ bool cc_worker::work_ul(srslte_uci_data_t* uci_data)
if (ul_grant_available || ul_mac_grant.phich_available) { if (ul_grant_available || ul_mac_grant.phich_available) {
ue_ul_cfg.ul_cfg.pusch.rnti = dci_ul.rnti; ue_ul_cfg.ul_cfg.pusch.rnti = dci_ul.rnti;
} else { } else {
ue_ul_cfg.ul_cfg.pucch.rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI_TX); ue_ul_cfg.ul_cfg.pucch.rnti = phy->stack->get_ul_sched_rnti(CURRENT_TTI_TX);
} }
// PCell sends SR and ACK // PCell sends SR and ACK
@ -757,10 +757,10 @@ void cc_worker::ul_phy_to_mac_grant(srslte_pusch_grant_t* ph
srslte_dci_ul_t* dci_ul, srslte_dci_ul_t* dci_ul,
uint32_t pid, uint32_t pid,
bool ul_grant_available, bool ul_grant_available,
srsue::mac_interface_phy::mac_grant_ul_t* mac_grant) srsue::mac_interface_phy_lte::mac_grant_ul_t* mac_grant)
{ {
if (mac_grant->phich_available && !dci_ul->rnti) { if (mac_grant->phich_available && !dci_ul->rnti) {
mac_grant->rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI); mac_grant->rnti = phy->stack->get_ul_sched_rnti(CURRENT_TTI);
} else { } else {
mac_grant->rnti = dci_ul->rnti; mac_grant->rnti = dci_ul->rnti;
} }
@ -778,7 +778,7 @@ int cc_worker::decode_pdcch_ul()
srslte_dci_ul_t dci[SRSLTE_MAX_CARRIERS]; srslte_dci_ul_t dci[SRSLTE_MAX_CARRIERS];
ZERO_OBJECT(dci); ZERO_OBJECT(dci);
uint16_t ul_rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI); uint16_t ul_rnti = phy->stack->get_ul_sched_rnti(CURRENT_TTI);
if (ul_rnti) { if (ul_rnti) {
/* Blind search first without cross scheduling then with it if enabled */ /* Blind search first without cross scheduling then with it if enabled */
@ -810,7 +810,7 @@ int cc_worker::decode_pdcch_ul()
return nof_grants; return nof_grants;
} }
bool cc_worker::encode_uplink(mac_interface_phy::tb_action_ul_t* action, srslte_uci_data_t* uci_data) bool cc_worker::encode_uplink(mac_interface_phy_lte::tb_action_ul_t* action, srslte_uci_data_t* uci_data)
{ {
srslte_pusch_data_t data = {}; srslte_pusch_data_t data = {};
ue_ul_cfg.cc_idx = cc_idx; ue_ul_cfg.cc_idx = cc_idx;
@ -838,7 +838,7 @@ bool cc_worker::encode_uplink(mac_interface_phy::tb_action_ul_t* action, srslte_
ue_ul_cfg.grant_available = action->tb.enabled; ue_ul_cfg.grant_available = action->tb.enabled;
// Set UL RNTI // Set UL RNTI
ue_ul_cfg.ul_cfg.pucch.rnti = phy->mac->get_ul_sched_rnti(CURRENT_TTI_TX); ue_ul_cfg.ul_cfg.pucch.rnti = phy->stack->get_ul_sched_rnti(CURRENT_TTI_TX);
// Encode signal // Encode signal
int ret = srslte_ue_ul_encode(&ue_ul, &sf_cfg_ul, &ue_ul_cfg, &data); int ret = srslte_ue_ul_encode(&ue_ul, &sf_cfg_ul, &ue_ul_cfg, &data);
@ -1020,9 +1020,9 @@ void cc_worker::parse_antenna_info(phys_cfg_ded_s* dedicated)
} }
} }
void cc_worker::parse_pucch_config(phy_interface_rrc::phy_cfg_t* phy_cfg) void cc_worker::parse_pucch_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg)
{ {
phy_interface_rrc::phy_cfg_common_t* common = &phy_cfg->common; phy_interface_rrc_lte::phy_cfg_common_t* common = &phy_cfg->common;
phys_cfg_ded_s* dedicated = &phy_cfg->dedicated; phys_cfg_ded_s* dedicated = &phy_cfg->dedicated;
/* PUCCH configuration */ /* PUCCH configuration */
@ -1123,9 +1123,9 @@ void cc_worker::parse_pucch_config(phy_interface_rrc::phy_cfg_t* phy_cfg)
/* Translates RRC structs into PHY structs /* Translates RRC structs into PHY structs
*/ */
void cc_worker::set_pcell_config(phy_interface_rrc::phy_cfg_t* phy_cfg) void cc_worker::set_pcell_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg)
{ {
phy_interface_rrc::phy_cfg_common_t* common = &phy_cfg->common; phy_interface_rrc_lte::phy_cfg_common_t* common = &phy_cfg->common;
phys_cfg_ded_s* dedicated = &phy_cfg->dedicated; phys_cfg_ded_s* dedicated = &phy_cfg->dedicated;
// Configure PDSCH // Configure PDSCH

@ -46,9 +46,11 @@ phy::phy() : workers_pool(MAX_WORKERS), workers(0), common(MAX_WORKERS)
{ {
tdd_config = {}; tdd_config = {};
prach_cfg = {}; prach_cfg = {};
default_args = {}; args = {};
ZERO_OBJECT(scell_earfcn); ZERO_OBJECT(scell_earfcn);
ZERO_OBJECT(scell_sync);
n_ta = 0; n_ta = 0;
initiated = false;
} }
static void srslte_phy_handler(phy_logger_level_t log_level, void *ctx, char *str) { static void srslte_phy_handler(phy_logger_level_t log_level, void *ctx, char *str) {
@ -96,47 +98,74 @@ void phy::set_default_args(phy_args_t *args)
args->estimator_fil_order = 4; args->estimator_fil_order = 4;
} }
bool phy::check_args(phy_args_t* args) bool phy::check_args(const phy_args_t& args)
{ {
if (args->nof_phy_threads > MAX_WORKERS) { if (args.nof_phy_threads > MAX_WORKERS) {
log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n"); log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n");
return false; return false;
} }
if (args->snr_ema_coeff > 1.0) { if (args.snr_ema_coeff > 1.0) {
log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n"); log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n");
return false; return false;
} }
return true; return true;
} }
bool phy::init(srslte::radio* radio_handler, int phy::init(const phy_args_t& args_,
mac_interface_phy* mac, srslte::logger* logger_,
rrc_interface_phy* rrc, stack_interface_phy_lte* stack_,
std::vector<srslte::log_filter*> log_vec, radio_interface_phy* radio_)
phy_args_t* phy_args)
{ {
stack = stack_;
radio = radio_;
init(args_, logger_);
return SRSLTE_SUCCESS;
}
int phy::init(const phy_args_t& args_, srslte::logger* logger_)
{
mlockall(MCL_CURRENT | MCL_FUTURE); mlockall(MCL_CURRENT | MCL_FUTURE);
n_ta = 0; args = args_;
this->log_vec = log_vec;
this->log_h = (srslte::log*) log_vec[0]; logger = logger_;
this->radio_handler = radio_handler;
this->mac = mac; set_earfcn(args.earfcn_list);
this->rrc = rrc;
// Create array of pointers to phy_logs
if (!phy_args) { for (int i = 0; i < args.nof_phy_threads; i++) {
args = &default_args; srslte::log_filter* mylog = new srslte::log_filter;
set_default_args(args); 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(mylog);
}
// Add PHY lib log
if (log_vec.at(0)->get_level_from_string(args.log.phy_lib_level) != srslte::LOG_LEVEL_NONE) {
srslte::log_filter* lib_log = 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(lib_log);
} else { } else {
args = phy_args; log_vec.push_back(NULL);
} }
// set default logger
log_h = log_vec.at(0);
if (!check_args(args)) { if (!check_args(args)) {
return false; return false;
} }
nof_workers = args->nof_phy_threads; nof_workers = args.nof_phy_threads;
if (log_vec[nof_workers]) { if (log_vec[nof_workers]) {
this->log_phy_lib_h = (srslte::log*)log_vec[0]; this->log_phy_lib_h = (srslte::log*)log_vec[0];
srslte_phy_log_register_handler(this, srslte_phy_handler); srslte_phy_log_register_handler(this, srslte_phy_handler);
@ -150,28 +179,27 @@ bool phy::init(srslte::radio* radio_handler,
} }
// Initializes PHY in a thread // Initializes PHY in a thread
void phy::run_thread() { void phy::run_thread()
{
prach_buffer.init(SRSLTE_MAX_PRB, log_h); prach_buffer.init(SRSLTE_MAX_PRB, log_h);
common.init(args, (srslte::log*)log_vec[0], radio_handler, rrc, mac); common.init(&args, (srslte::log*)log_vec[0], radio, stack);
// Add workers to workers pool and start threads // Add workers to workers pool and start threads
for (uint32_t i=0;i<nof_workers;i++) { for (uint32_t i=0;i<nof_workers;i++) {
sf_worker* w = sf_worker* w =
new sf_worker(SRSLTE_MAX_PRB, &common, (srslte::log*)log_vec[i], (srslte::log*)log_vec[nof_workers], &sfsync); new sf_worker(SRSLTE_MAX_PRB, &common, (srslte::log*)log_vec[i], (srslte::log*)log_vec[nof_workers], &sfsync);
workers.push_back(w); workers.push_back(w);
workers_pool.init_worker(i, w, WORKERS_THREAD_PRIO, args->worker_cpu_mask); workers_pool.init_worker(i, w, WORKERS_THREAD_PRIO, args.worker_cpu_mask);
} }
// Load Asynchronous SCell objects // Load Asynchronous SCell objects
for (int i = 0; i < (int)args->nof_radios - 1; i++) { for (int i = 0; i < (int)args.nof_radios - 1; i++) {
scell_sync[i].init(&radio_handler[i + 1], &common, log_h); scell_sync[i].init(&radio[i + 1], &common, log_h);
} }
// 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
sfsync.init(radio_handler, sfsync.init(radio,
mac, stack,
rrc,
&prach_buffer, &prach_buffer,
&workers_pool, &workers_pool,
&common, &common,
@ -179,7 +207,7 @@ void phy::run_thread() {
log_phy_lib_h, log_phy_lib_h,
scell_sync, scell_sync,
SF_RECV_THREAD_PRIO, SF_RECV_THREAD_PRIO,
args->sync_cpu_affinity); args.sync_cpu_affinity);
// Disable UL signal pregeneration until the attachment // Disable UL signal pregeneration until the attachment
enable_pregen_signals(false); enable_pregen_signals(false);
@ -196,18 +224,11 @@ bool phy::is_initiated()
return initiated; return initiated;
} }
void phy::set_agc_enable(bool enabled)
{
sfsync.set_agc_enable(enabled);
for (int i = 0; i < (int)args->nof_radios - 1; i++) {
scell_sync[i].set_agc_enable(enabled);
}
}
void phy::stop() void phy::stop()
{ {
if (initiated) {
sfsync.stop(); sfsync.stop();
for (uint32_t i = 0; i < args->nof_radios - 1; i++) { for (uint32_t i = 0; i < args.nof_radios - 1; i++) {
scell_sync[i].stop(); scell_sync[i].stop();
} }
@ -216,13 +237,17 @@ void phy::stop()
for (uint32_t i = 0; i < nof_workers; i++) { for (uint32_t i = 0; i < nof_workers; i++) {
delete ((sf_worker*)workers[i]); delete ((sf_worker*)workers[i]);
} }
initiated = false;
}
} }
void phy::get_metrics(phy_metrics_t &m) { void phy::get_metrics(phy_metrics_t* m)
common.get_dl_metrics(m.dl); {
common.get_ul_metrics(m.ul); common.get_dl_metrics(m->dl);
common.get_sync_metrics(m.sync); common.get_ul_metrics(m->ul);
m.nof_active_cc = args->nof_carriers; common.get_sync_metrics(m->sync);
m->nof_active_cc = args.nof_carriers;
} }
void phy::set_timeadv_rar(uint32_t ta_cmd) { void phy::set_timeadv_rar(uint32_t ta_cmd) {
@ -286,7 +311,8 @@ bool phy::cell_select(phy_cell_t *cell) {
return sfsync.cell_select(cell); return sfsync.cell_select(cell);
} }
phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell) { phy_interface_rrc_lte::cell_search_ret_t phy::cell_search(phy_cell_t* cell)
{
return sfsync.cell_search(cell); return sfsync.cell_search(cell);
} }
@ -296,7 +322,7 @@ bool phy::cell_is_camping() {
float phy::get_phr() float phy::get_phr()
{ {
float phr = radio_handler->get_max_tx_power() - common.cur_pusch_power; float phr = radio->get_max_tx_power() - common.cur_pusch_power;
return phr; return phr;
} }
@ -330,17 +356,23 @@ void phy::prach_send(uint32_t preamble_idx, int allowed_subframe, float target_p
} }
} }
phy_interface_mac::prach_info_t phy::prach_get_info() phy_interface_mac_lte::prach_info_t phy::prach_get_info()
{ {
return prach_buffer.get_info(); return prach_buffer.get_info();
} }
// Handle the case of a radio overflow. Resynchronise inmediatly // Handle the case of a radio overflow. Resynchronise immediatly
void phy::radio_overflow() void phy::radio_overflow()
{ {
sfsync.radio_overflow(); sfsync.radio_overflow();
} }
void phy::radio_failure()
{
// TODO: handle failure
Error("Radio failure.\n");
}
void phy::reset() void phy::reset()
{ {
Info("Resetting PHY\n"); Info("Resetting PHY\n");
@ -402,7 +434,7 @@ void phy::enable_pregen_signals(bool enable)
} }
} }
void phy::set_config(phy_interface_rrc::phy_cfg_t* phy_cfg) void phy::set_config(phy_interface_rrc_lte::phy_cfg_t* phy_cfg)
{ {
if (is_initiated()) { if (is_initiated()) {
for (uint32_t i = 0; i < nof_workers; i++) { for (uint32_t i = 0; i < nof_workers; i++) {
@ -425,8 +457,8 @@ void phy::set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config)
uint32_t cc_idx = scell_config->s_cell_idx_r10; uint32_t cc_idx = scell_config->s_cell_idx_r10;
// Component carrier index zero should be reserved for PCell // Component carrier index zero should be reserved for PCell
if (cc_idx != 0 && cc_idx < args->nof_carriers) { if (cc_idx != 0 && cc_idx < args.nof_carriers) {
carrier_map_t* m = &args->carrier_map[cc_idx]; carrier_map_t* m = &args.carrier_map[cc_idx];
srslte_cell_t cell = {}; srslte_cell_t cell = {};
uint32_t earfcn = 0; uint32_t earfcn = 0;
@ -463,8 +495,8 @@ void phy::set_config_scell(asn1::rrc::scell_to_add_mod_r10_s* scell_config)
if (scell_earfcn[cc_idx - 1] != earfcn) { if (scell_earfcn[cc_idx - 1] != earfcn) {
float dl_freq = srslte_band_fd(earfcn) * 1e6f; float dl_freq = srslte_band_fd(earfcn) * 1e6f;
float ul_freq = srslte_band_fu(srslte_band_ul_earfcn(earfcn)) * 1e6f; float ul_freq = srslte_band_fu(srslte_band_ul_earfcn(earfcn)) * 1e6f;
radio_handler->set_rx_freq(m->channel_idx, dl_freq); radio->set_rx_freq(m->channel_idx, dl_freq);
radio_handler->set_tx_freq(m->channel_idx, ul_freq); radio->set_tx_freq(m->channel_idx, ul_freq);
} }
} }
@ -520,7 +552,7 @@ void phy::set_config_mbsfn_sib13(sib_type13_r9_s* sib13)
void phy::set_config_mbsfn_mcch(mcch_msg_s* mcch) void phy::set_config_mbsfn_mcch(mcch_msg_s* mcch)
{ {
common.mbsfn_config.mcch = *mcch; common.mbsfn_config.mcch = *mcch;
mac->set_mbsfn_config( stack->set_mbsfn_config(
common.mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].mbms_session_info_list_r9.size()); common.mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].mbms_session_info_list_r9.size());
common.set_mch_period_stop( common.set_mch_period_stop(
common.mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9); common.mbsfn_config.mcch.msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[0].pmch_cfg_r9.sf_alloc_end_r9);

@ -50,7 +50,7 @@ phy_common::phy_common(uint32_t max_workers) : tx_sem(max_workers)
args = NULL; args = NULL;
log_h = NULL; log_h = NULL;
radio_h = NULL; radio_h = NULL;
mac = NULL; stack = NULL;
this->max_workers = max_workers; this->max_workers = max_workers;
rx_gain_offset = 0; rx_gain_offset = 0;
// have_mtch_stop = false; // have_mtch_stop = false;
@ -114,13 +114,14 @@ void phy_common::set_nof_workers(uint32_t nof_workers)
this->nof_workers = nof_workers; this->nof_workers = nof_workers;
} }
void phy_common::init( void phy_common::init(phy_args_t* _args,
phy_args_t* _args, srslte::log* _log, srslte::radio* _radio, rrc_interface_phy* _rrc, mac_interface_phy* _mac) srslte::log* _log,
radio_interface_phy* _radio,
stack_interface_phy_lte* _stack)
{ {
log_h = _log; log_h = _log;
radio_h = _radio; radio_h = _radio;
rrc = _rrc; stack = _stack;
mac = _mac;
args = _args; args = _args;
is_first_tx = true; is_first_tx = true;
sr_last_tx_tti = -1; sr_last_tx_tti = -1;
@ -128,7 +129,6 @@ void phy_common::init(
void phy_common::set_ue_dl_cfg(srslte_ue_dl_cfg_t* ue_dl_cfg) void phy_common::set_ue_dl_cfg(srslte_ue_dl_cfg_t* ue_dl_cfg)
{ {
ue_dl_cfg->snr_to_cqi_offset = args->snr_to_cqi_offset; ue_dl_cfg->snr_to_cqi_offset = args->snr_to_cqi_offset;
srslte_chest_dl_cfg_t* chest_cfg = &ue_dl_cfg->chest_cfg; srslte_chest_dl_cfg_t* chest_cfg = &ue_dl_cfg->chest_cfg;
@ -176,7 +176,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; ue_ul_cfg->ul_cfg.pucch.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL;
} }
srslte::radio* phy_common::get_radio() radio_interface_phy* phy_common::get_radio()
{ {
return radio_h; return radio_h;
} }
@ -564,7 +564,6 @@ void phy_common::worker_end(uint32_t tti,
// For each radio, transmit // For each radio, transmit
for (uint32_t i = 0; i < args->nof_radios; i++) { for (uint32_t i = 0; i < args->nof_radios; i++) {
radio_h[i].set_tti(tti);
if (tx_enable && !srslte_timestamp_iszero(&tx_time[i])) { if (tx_enable && !srslte_timestamp_iszero(&tx_time[i])) {
radio_h[i].tx(buffer[i], nof_samples[i], tx_time[i]); radio_h[i].tx(buffer[i], nof_samples[i], tx_time[i]);
is_first_of_burst[i] = false; is_first_of_burst[i] = false;

@ -191,9 +191,9 @@ bool prach::is_ready_to_send(uint32_t current_tti_) {
return false; return false;
} }
phy_interface_mac::prach_info_t prach::get_info() phy_interface_mac_lte::prach_info_t prach::get_info()
{ {
phy_interface_mac::prach_info_t info = {}; phy_interface_mac_lte::prach_info_t info = {};
info.preamble_format = prach_obj.config_idx / 16; info.preamble_format = prach_obj.config_idx / 16;
if (transmitted_tti >= 0) { if (transmitted_tti >= 0) {

@ -54,14 +54,17 @@ static int plot_worker_id = -1;
namespace srsue { namespace srsue {
sf_worker::sf_worker( sf_worker::sf_worker(uint32_t max_prb,
uint32_t max_prb, phy_common* phy, srslte::log* log_h, srslte::log* log_phy_lib_h, chest_feedback_itf* chest_loop) phy_common* phy_,
srslte::log* log_h_,
srslte::log* log_phy_lib_h_,
chest_feedback_itf* chest_loop_)
{ {
cell_initiated = false; cell_initiated = false;
this->phy = phy; phy = phy_;
this->log_h = log_h; log_h = log_h_;
this->log_phy_lib_h = log_phy_lib_h; log_phy_lib_h = log_phy_lib_h_;
this->chest_loop = chest_loop; chest_loop = chest_loop_;
bzero(&tdd_config, sizeof(srslte_tdd_config_t)); bzero(&tdd_config, sizeof(srslte_tdd_config_t));
@ -184,7 +187,7 @@ void sf_worker::enable_pregen_signals(bool enabled)
} }
} }
void sf_worker::set_pcell_config(srsue::phy_interface_rrc::phy_cfg_t* phy_cfg) void sf_worker::set_pcell_config(srsue::phy_interface_rrc_lte::phy_cfg_t* phy_cfg)
{ {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
Info("Setting PCell configuration for cc_worker=%d, cc=%d\n", get_id(), 0); Info("Setting PCell configuration for cc_worker=%d, cc=%d\n", get_id(), 0);
@ -328,13 +331,8 @@ void sf_worker::update_measurements()
} }
if (!rssi_read_cnt) { if (!rssi_read_cnt) {
if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) {
phy->last_radio_rssi = phy->get_radio()->get_rssi();
phy->rx_gain_offset = phy->avg_rssi_dbm - phy->last_radio_rssi + 30;
} else {
phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset; phy->rx_gain_offset = phy->get_radio()->get_rx_gain() + phy->args->rx_gain_offset;
} }
}
rssi_read_cnt++; rssi_read_cnt++;
if (rssi_read_cnt == 1000) { if (rssi_read_cnt == 1000) {
rssi_read_cnt = 0; rssi_read_cnt = 0;
@ -348,7 +346,7 @@ void sf_worker::update_measurements()
// Send PCell measurement // Send PCell measurement
if ((tti % phy->pcell_report_period) == phy->pcell_report_period - 1) { if ((tti % phy->pcell_report_period) == phy->pcell_report_period - 1) {
phy->rrc->new_phy_meas(phy->avg_rsrp_dbm[0], phy->avg_rsrq_db, tti); phy->stack->new_phy_meas(phy->avg_rsrp_dbm[0], phy->avg_rsrq_db, tti);
} }
// Check in-sync / out-sync conditions // Check in-sync / out-sync conditions

@ -59,9 +59,8 @@ sync::sync()
worker_com = NULL; worker_com = NULL;
} }
void sync::init(srslte::radio* _radio_handler, void sync::init(radio_interface_phy* _radio,
mac_interface_phy* _mac, stack_interface_phy_lte* _stack,
rrc_interface_phy* _rrc,
prach* _prach_buffer, prach* _prach_buffer,
srslte::thread_pool* _workers_pool, srslte::thread_pool* _workers_pool,
phy_common* _worker_com, phy_common* _worker_com,
@ -71,11 +70,10 @@ void sync::init(srslte::radio* _radio_handler,
uint32_t prio, uint32_t prio,
int sync_cpu_affinity) int sync_cpu_affinity)
{ {
radio_h = _radio_handler; radio_h = _radio;
log_h = _log_h; log_h = _log_h;
log_phy_lib_h = _log_phy_lib_h; log_phy_lib_h = _log_phy_lib_h;
mac = _mac; stack = _stack;
rrc = _rrc;
scell_sync = scell_sync_; scell_sync = scell_sync_;
workers_pool = _workers_pool; workers_pool = _workers_pool;
worker_com = _worker_com; worker_com = _worker_com;
@ -103,7 +101,7 @@ void sync::init(srslte::radio* _radio_handler,
sfn_p.init(&ue_sync, sf_buffer[0], log_h); sfn_p.init(&ue_sync, sf_buffer[0], log_h);
// Start intra-frequency measurement // Start intra-frequency measurement
intra_freq_meas.init(worker_com, rrc, log_h); intra_freq_meas.init(worker_com, stack, log_h);
pthread_mutex_init(&rrc_mutex, NULL); pthread_mutex_init(&rrc_mutex, NULL);
@ -119,6 +117,7 @@ void sync::init(srslte::radio* _radio_handler,
sync::~sync() sync::~sync()
{ {
if (running) {
uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant; uint32_t nof_rf_channels = worker_com->args->nof_rf_channels * worker_com->args->nof_rx_ant;
for (uint32_t r = 0; r < worker_com->args->nof_radios; r++) { for (uint32_t r = 0; r < worker_com->args->nof_radios; r++) {
for (uint32_t p = 0; p < nof_rf_channels; p++) { for (uint32_t p = 0; p < nof_rf_channels; p++) {
@ -129,6 +128,7 @@ sync::~sync()
} }
pthread_mutex_destroy(&rrc_mutex); pthread_mutex_destroy(&rrc_mutex);
srslte_ue_sync_free(&ue_sync); srslte_ue_sync_free(&ue_sync);
}
} }
void sync::stop() void sync::stop()
@ -193,12 +193,12 @@ void sync::reset()
* If no cells are found in any frequency it returns 0. If error returns -1. * If no cells are found in any frequency it returns 0. If error returns -1.
*/ */
phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_cell_t* found_cell) phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte::phy_cell_t* found_cell)
{ {
phy_interface_rrc::cell_search_ret_t ret; phy_interface_rrc_lte::cell_search_ret_t ret;
ret.found = phy_interface_rrc::cell_search_ret_t::ERROR; ret.found = phy_interface_rrc_lte::cell_search_ret_t::ERROR;
ret.last_freq = phy_interface_rrc::cell_search_ret_t::NO_MORE_FREQS; ret.last_freq = phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS;
pthread_mutex_lock(&rrc_mutex); pthread_mutex_lock(&rrc_mutex);
@ -206,11 +206,16 @@ phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_ce
Info("Cell Search: Start EARFCN index=%u/%zd\n", cellsearch_earfcn_index, earfcn.size()); Info("Cell Search: Start EARFCN index=%u/%zd\n", cellsearch_earfcn_index, earfcn.size());
phy_state.go_idle(); phy_state.go_idle();
if (current_earfcn != (int) earfcn[cellsearch_earfcn_index]) { try {
current_earfcn = (int) earfcn[cellsearch_earfcn_index]; if (current_earfcn != (int)earfcn.at(cellsearch_earfcn_index)) {
current_earfcn = (int)earfcn[cellsearch_earfcn_index];
Info("Cell Search: changing frequency to EARFCN=%d\n", current_earfcn); Info("Cell Search: changing frequency to EARFCN=%d\n", current_earfcn);
set_frequency(); set_frequency();
} }
} catch (const std::out_of_range& oor) {
Error("Index %d is not a valid EARFCN element.\n", cellsearch_earfcn_index);
return ret;
}
// Move to CELL SEARCH and wait to finish // Move to CELL SEARCH and wait to finish
Info("Cell Search: Setting Cell search state\n"); Info("Cell Search: Setting Cell search state\n");
@ -232,10 +237,10 @@ phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_ce
found_cell->earfcn = current_earfcn; found_cell->earfcn = current_earfcn;
found_cell->cell = cell; found_cell->cell = cell;
} }
ret.found = phy_interface_rrc::cell_search_ret_t::CELL_FOUND; ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND;
} else { } else {
log_h->info("Cell Search: Could not synchronize with cell\n"); log_h->info("Cell Search: Could not synchronize with cell\n");
ret.found = phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND; ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
} }
} else { } else {
Error("Cell Search: Setting cell PCI=%d, nof_prb=%d\n", cell.id, cell.nof_prb); Error("Cell Search: Setting cell PCI=%d, nof_prb=%d\n", cell.id, cell.nof_prb);
@ -243,7 +248,7 @@ phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_ce
break; break;
case search::CELL_NOT_FOUND: case search::CELL_NOT_FOUND:
Info("Cell Search: No cell found in this frequency\n"); Info("Cell Search: No cell found in this frequency\n");
ret.found = phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND; ret.found = phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND;
break; break;
default: default:
Error("Cell Search: while receiving samples\n"); Error("Cell Search: while receiving samples\n");
@ -255,9 +260,9 @@ phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_ce
if (cellsearch_earfcn_index >= earfcn.size()) { if (cellsearch_earfcn_index >= earfcn.size()) {
Info("Cell Search: No more frequencies in the current EARFCN set\n"); Info("Cell Search: No more frequencies in the current EARFCN set\n");
cellsearch_earfcn_index = 0; cellsearch_earfcn_index = 0;
ret.last_freq = phy_interface_rrc::cell_search_ret_t::NO_MORE_FREQS; ret.last_freq = phy_interface_rrc_lte::cell_search_ret_t::NO_MORE_FREQS;
} else { } else {
ret.last_freq = phy_interface_rrc::cell_search_ret_t::MORE_FREQS; ret.last_freq = phy_interface_rrc_lte::cell_search_ret_t::MORE_FREQS;
} }
pthread_mutex_unlock(&rrc_mutex); pthread_mutex_unlock(&rrc_mutex);
@ -267,7 +272,7 @@ phy_interface_rrc::cell_search_ret_t sync::cell_search(phy_interface_rrc::phy_ce
/* Cell select synchronizes to a new cell (e.g. during HO or during cell reselection on IDLE) or /* Cell select synchronizes to a new cell (e.g. during HO or during cell reselection on IDLE) or
* re-synchronizes with the current cell if cell argument is NULL * re-synchronizes with the current cell if cell argument is NULL
*/ */
bool sync::cell_select(phy_interface_rrc::phy_cell_t* new_cell) bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell)
{ {
pthread_mutex_lock(&rrc_mutex); pthread_mutex_lock(&rrc_mutex);
@ -598,7 +603,7 @@ void sync::run_thread()
radio_is_overflow = false; radio_is_overflow = false;
} else if (phy_state.is_idle()) { } else if (phy_state.is_idle()) {
log_h->warning("Could not synchronize SFN after radio overflow. Trying again\n"); log_h->warning("Could not synchronize SFN after radio overflow. Trying again\n");
rrc->out_of_sync(); stack->out_of_sync();
phy_state.force_sfn_sync(); phy_state.force_sfn_sync();
} }
} else { } else {
@ -621,7 +626,7 @@ void sync::run_thread()
// Increase TTI counter // Increase TTI counter
tti = (tti+1) % 10240; tti = (tti+1) % 10240;
mac->run_tti(tti); stack->run_tti(tti);
} }
for (uint32_t p = 0; p < nof_rf_channels; p++) { for (uint32_t p = 0; p < nof_rf_channels; p++) {
@ -664,7 +669,7 @@ void sync::in_sync()
in_sync_cnt++; in_sync_cnt++;
// Send RRC in-sync signal after 100 ms consecutive subframes // Send RRC in-sync signal after 100 ms consecutive subframes
if (in_sync_cnt == NOF_IN_SYNC_SF) { if (in_sync_cnt == NOF_IN_SYNC_SF) {
rrc->in_sync(); stack->in_sync();
in_sync_cnt = 0; in_sync_cnt = 0;
out_of_sync_cnt = 0; out_of_sync_cnt = 0;
} }
@ -678,7 +683,7 @@ void sync::out_of_sync()
out_of_sync_cnt++; out_of_sync_cnt++;
if (out_of_sync_cnt == NOF_OUT_OF_SYNC_SF) { if (out_of_sync_cnt == NOF_OUT_OF_SYNC_SF) {
Info("Sending to RRC\n"); Info("Sending to RRC\n");
rrc->out_of_sync(); stack->out_of_sync();
out_of_sync_cnt = 0; out_of_sync_cnt = 0;
in_sync_cnt = 0; in_sync_cnt = 0;
} }
@ -1668,7 +1673,7 @@ sync::intra_measure::~intra_measure()
free(search_buffer); free(search_buffer);
} }
void sync::intra_measure::init(phy_common* common, rrc_interface_phy* rrc, srslte::log* log_h) void sync::intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h)
{ {
this->rrc = rrc; this->rrc = rrc;
this->log_h = log_h; this->log_h = log_h;

@ -0,0 +1,27 @@
#
# 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 ue_radio.cc)
add_library(srsue_radio STATIC ${SOURCES})
target_link_libraries(srsue_radio srslte_radio)
install(TARGETS srsue_radio DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,192 @@
/*
* 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 "srsue/hdr/radio/ue_radio.h"
#include <mutex>
using namespace srslte;
namespace srsue {
std::mutex instance_mutex;
static ue_radio* instance;
ue_radio::ue_radio() : args(), logger(nullptr), running(false), phy(nullptr), rf_metrics(), radios()
{
std::lock_guard<std::mutex> lock(instance_mutex);
instance = this;
}
ue_radio::~ue_radio()
{
stop();
}
std::string ue_radio::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;
}
int ue_radio::init(const rf_args_t& args_, srslte::logger* logger_)
{
args = args_;
logger = logger_;
// Init log
log.init("RF ", logger);
log.set_level(args.log_level);
if (args.nof_radios > SRSLTE_MAX_RADIOS) {
log.error("Maximum supported number of radios exceeded (%d > %d)\n", args.nof_radios, SRSLTE_MAX_RADIOS);
return SRSLTE_ERROR;
}
// Init and start Radio
char* dev_name = NULL;
if (args.device_name.compare("auto")) {
dev_name = (char*)args.device_name.c_str();
}
char* dev_args[SRSLTE_MAX_RADIOS] = {NULL};
for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) {
if (args.device_args[0].compare("auto")) {
dev_args[i] = (char*)args.device_args[i].c_str();
}
}
log.console(
"Opening %d RF devices with %d RF channels...\n", args.nof_radios, args.nof_rf_channels * args.nof_rx_ant);
for (uint32_t r = 0; r < args.nof_radios; r++) {
std::unique_ptr<srslte::radio> radio = std::unique_ptr<srslte::radio>(new srslte::radio());
if (!radio->init(&log, dev_args[r], dev_name, args.nof_rf_channels * args.nof_rx_ant)) {
log.console("Failed to find device %s with args %s\n", args.device_name.c_str(), args.device_args[0].c_str());
return SRSLTE_ERROR;
}
// Set RF options
if (args.time_adv_nsamples.compare("auto")) {
int t = atoi(args.time_adv_nsamples.c_str());
radio->set_tx_adv(abs(t));
radio->set_tx_adv_neg(t < 0);
}
if (args.burst_preamble.compare("auto")) {
radio->set_burst_preamble(atof(args.burst_preamble.c_str()));
}
if (args.continuous_tx.compare("auto")) {
log.console("set continuous %s\n", args.continuous_tx.c_str());
radio->set_continuous_tx(args.continuous_tx.compare("yes") ? false : true);
}
// Set PHY options
if (args.rx_gain < 0) {
radio->start_agc(false);
} else {
radio->set_rx_gain(args.rx_gain);
}
if (args.tx_gain > 0) {
radio->set_tx_gain(args.tx_gain);
} else {
radio->set_tx_gain(args.rx_gain);
log.console("\nWarning: TX gain was not set. Using open-loop power control (not working properly)\n\n");
}
radio->register_error_handler(rf_msg);
radio->set_freq_offset(args.freq_offset);
// append to radios
radios.push_back(std::move(radio));
}
running = true;
return SRSLTE_SUCCESS;
}
void ue_radio::stop()
{
if (running) {
std::lock_guard<std::mutex> lock(instance_mutex);
instance = nullptr;
for (auto& radio : radios) {
radio->stop();
}
running = false;
}
}
bool ue_radio::get_metrics(rf_metrics_t* metrics)
{
*metrics = rf_metrics;
rf_metrics = {};
return true;
}
void ue_radio::rf_msg(srslte_rf_error_t error)
{
std::lock_guard<std::mutex> lock(instance_mutex);
if (instance) {
instance->handle_rf_msg(error);
}
}
void ue_radio::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;
log.info("Overflow\n");
// inform PHY about overflow
phy->radio_overflow();
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_UNDERFLOW) {
rf_metrics.rf_u++;
rf_metrics.rf_error = true;
log.info("Underflow\n");
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) {
rf_metrics.rf_l++;
rf_metrics.rf_error = true;
log.info("Late (detected in %s)\n", error.opt ? "rx call" : "asynchronous thread");
} else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_RX) {
log.error("Fatal radio error occured.\n");
phy->radio_failure();
} 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');
log.info("%s\n", str.c_str());
}
}
} // namespace srsue

@ -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 ue_stack_lte.cc)
add_library(srsue_stack STATIC ${SOURCES})
target_link_libraries(srsue_stack)
install(TARGETS srsue_stack DESTINATION ${LIBRARY_DIR})

@ -20,4 +20,5 @@
file(GLOB SOURCES "*.cc") file(GLOB SOURCES "*.cc")
add_library(srsue_mac STATIC ${SOURCES}) add_library(srsue_mac STATIC ${SOURCES})
install(TARGETS srsue_mac DESTINATION ${LIBRARY_DIR}) install(TARGETS srsue_mac DESTINATION ${LIBRARY_DIR})

@ -24,9 +24,9 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/mac.h" #include "srsue/hdr/stack/mac/demux.h"
#include "srsue/hdr/mac/demux.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/stack/mac/mac.h"
namespace srsue { namespace srsue {

@ -24,7 +24,7 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/dl_harq.h" #include "srsue/hdr/stack/mac/dl_harq.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
@ -64,9 +64,10 @@ bool dl_harq_entity::init(srslte::log* log_h,
} }
/***************** PHY->MAC interface for DL processes **************************/ /***************** PHY->MAC interface for DL processes **************************/
void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action) void dl_harq_entity::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
mac_interface_phy_lte::tb_action_dl_t* action)
{ {
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
if (grant.rnti != rntis->sps_rnti) { if (grant.rnti != rntis->sps_rnti) {
// Set BCCH PID for SI RNTI // Set BCCH PID for SI RNTI
@ -95,7 +96,7 @@ void dl_harq_entity::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_i
} }
} }
void dl_harq_entity::tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS]) void dl_harq_entity::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant, bool ack[SRSLTE_MAX_CODEWORDS])
{ {
if (grant.rnti == SRSLTE_SIRNTI) { if (grant.rnti == SRSLTE_SIRNTI) {
bcch_proc.tb_decoded(grant, ack); bcch_proc.tb_decoded(grant, ack);
@ -151,10 +152,10 @@ void dl_harq_entity::dl_harq_process::reset(void)
} }
} }
void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
mac_interface_phy::tb_action_dl_t* action) mac_interface_phy_lte::tb_action_dl_t* action)
{ {
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
/* For each subprocess... */ /* For each subprocess... */
for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) { for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) {
if (grant.tb[i].tbs) { if (grant.tb[i].tbs) {
@ -163,7 +164,7 @@ void dl_harq_entity::dl_harq_process::new_grant_dl(mac_interface_phy::mac_grant_
} }
} }
void dl_harq_entity::dl_harq_process::tb_decoded(mac_interface_phy::mac_grant_dl_t grant, void dl_harq_entity::dl_harq_process::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant,
bool ack[SRSLTE_MAX_CODEWORDS]) bool ack[SRSLTE_MAX_CODEWORDS])
{ {
/* For each subprocess... */ /* For each subprocess... */
@ -182,7 +183,7 @@ dl_harq_entity::dl_harq_process::dl_tb_process::dl_tb_process()
is_initiated = false; is_initiated = false;
ack = false; ack = false;
n_retx = 0; n_retx = 0;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_dl_t)); bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_dl_t));
payload_buffer_ptr = NULL; payload_buffer_ptr = NULL;
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
} }
@ -223,7 +224,7 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock)
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
} }
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_dl_t)); bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_dl_t));
is_first_tb = true; is_first_tb = true;
ack = false; ack = false;
n_retx = 0; n_retx = 0;
@ -244,8 +245,8 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::reset(bool lock)
} }
} }
void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant,
mac_interface_phy::tb_action_dl_t* action) mac_interface_phy_lte::tb_action_dl_t* action)
{ {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
@ -327,7 +328,8 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::new_grant_dl(mac_interface_
} }
} }
void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_phy::mac_grant_dl_t grant, bool* ack_ptr) void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_phy_lte::mac_grant_dl_t grant,
bool* ack_ptr)
{ {
if (payload_buffer_ptr) { if (payload_buffer_ptr) {
this->ack = *ack_ptr; this->ack = *ack_ptr;
@ -382,7 +384,8 @@ void dl_harq_entity::dl_harq_process::dl_tb_process::tb_decoded(mac_interface_ph
} }
// Determine if it's a new transmission 5.3.2.2 // Determine if it's a new transmission 5.3.2.2
bool dl_harq_entity::dl_harq_process::dl_tb_process::calc_is_new_transmission(mac_interface_phy::mac_grant_dl_t grant) bool dl_harq_entity::dl_harq_process::dl_tb_process::calc_is_new_transmission(
mac_interface_phy_lte::mac_grant_dl_t grant)
{ {
if (((grant.tb[tid].ndi_present && if (((grant.tb[tid].ndi_present &&

@ -30,8 +30,8 @@
#include <unistd.h> #include <unistd.h>
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srsue/hdr/mac/mac.h"
#include "srslte/common/pcap.h" #include "srslte/common/pcap.h"
#include "srsue/hdr/stack/mac/mac.h"
using namespace asn1::rrc; using namespace asn1::rrc;
@ -50,8 +50,11 @@ mac::mac() :
clear_rntis(); clear_rntis();
} }
bool mac::init( bool mac::init(phy_interface_mac_lte* phy,
phy_interface_mac* phy, rlc_interface_mac* rlc, rrc_interface_mac* rrc, srslte::log* log_h_, uint32_t nof_carriers) rlc_interface_mac* rlc,
rrc_interface_mac* rrc,
srslte::log* log_h_,
uint32_t nof_carriers)
{ {
phy_h = phy; phy_h = phy;
rlc_h = rlc; rlc_h = rlc;
@ -397,14 +400,14 @@ void mac::tb_decoded(uint32_t cc_idx, mac_grant_dl_t grant, bool ack[SRSLTE_MAX_
} }
void mac::new_grant_dl(uint32_t cc_idx, void mac::new_grant_dl(uint32_t cc_idx,
mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy_lte::mac_grant_dl_t grant,
mac_interface_phy::tb_action_dl_t* action) mac_interface_phy_lte::tb_action_dl_t* action)
{ {
if (SRSLTE_RNTI_ISRAR(grant.rnti)) { if (SRSLTE_RNTI_ISRAR(grant.rnti)) {
ra_procedure.new_grant_dl(grant, action); ra_procedure.new_grant_dl(grant, action);
} else if (grant.rnti == SRSLTE_PRNTI) { } else if (grant.rnti == SRSLTE_PRNTI) {
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
if (grant.tb[0].tbs > pch_payload_buffer_sz) { if (grant.tb[0].tbs > pch_payload_buffer_sz) {
Error("Received dci for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.tb[0].tbs, pch_payload_buffer_sz); Error("Received dci for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.tb[0].tbs, pch_payload_buffer_sz);
action->tb[0].enabled = false; action->tb[0].enabled = false;
@ -446,8 +449,8 @@ bool mac::contention_resolution_id_rcv(uint64_t id)
} }
void mac::new_grant_ul(uint32_t cc_idx, void mac::new_grant_ul(uint32_t cc_idx,
mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy_lte::mac_grant_ul_t grant,
mac_interface_phy::tb_action_ul_t* action) mac_interface_phy_lte::tb_action_ul_t* action)
{ {
/* Start PHR Periodic timer on first UL dci */ /* Start PHR Periodic timer on first UL dci */
if (is_first_ul_grant) { if (is_first_ul_grant) {

@ -24,8 +24,8 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/mux.h" #include "srsue/hdr/stack/mac/mux.h"
#include "srsue/hdr/mac/mac.h" #include "srsue/hdr/stack/mac/mac.h"
#include <set> #include <set>
#include <algorithm> #include <algorithm>

@ -24,9 +24,9 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/proc_bsr.h" #include "srsue/hdr/stack/mac/proc_bsr.h"
#include "srsue/hdr/mac/mac.h" #include "srsue/hdr/stack/mac/mac.h"
#include "srsue/hdr/mac/mux.h" #include "srsue/hdr/stack/mac/mux.h"
namespace srsue { namespace srsue {

@ -24,10 +24,10 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/proc_phr.h" #include "srsue/hdr/stack/mac/proc_phr.h"
#include "srsue/hdr/mac/mac.h"
#include "srsue/hdr/mac/mux.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/stack/mac/mac.h"
#include "srsue/hdr/stack/mac/mux.h"
namespace srsue { namespace srsue {
@ -38,7 +38,7 @@ phr_proc::phr_proc()
phr_cfg = {}; phr_cfg = {};
} }
void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, srslte::timers* timers_db_) void phr_proc::init(phy_interface_mac_lte* phy_h_, srslte::log* log_h_, srslte::timers* timers_db_)
{ {
phy_h = phy_h_; phy_h = phy_h_;
log_h = log_h_; log_h = log_h_;

@ -29,9 +29,9 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include "srsue/hdr/mac/proc_ra.h" #include "srsue/hdr/stack/mac/mac.h"
#include "srsue/hdr/mac/mac.h" #include "srsue/hdr/stack/mac/mux.h"
#include "srsue/hdr/mac/mux.h" #include "srsue/hdr/stack/mac/proc_ra.h"
/* Random access procedure as specified in Section 5.1 of 36.321 */ /* Random access procedure as specified in Section 5.1 of 36.321 */
@ -44,7 +44,7 @@ uint32_t backoff_table[16] = {0, 10, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480
// Table 7.6-1: DELTA_PREAMBLE values. // Table 7.6-1: DELTA_PREAMBLE values.
int delta_preamble_db_table[5] = {0, 0, -3, -3, 8}; int delta_preamble_db_table[5] = {0, 0, -3, -3, 8};
void ra_proc::init(phy_interface_mac* phy_h_, void ra_proc::init(phy_interface_mac_lte* phy_h_,
rrc_interface_mac* rrc_, rrc_interface_mac* rrc_,
srslte::log* log_h_, srslte::log* log_h_,
mac_interface_rrc::ue_rnti_t* rntis_, mac_interface_rrc::ue_rnti_t* rntis_,
@ -113,7 +113,7 @@ void ra_proc::read_params()
rach_cfg.nof_groupA_preambles = rach_cfg.nof_preambles; rach_cfg.nof_groupA_preambles = rach_cfg.nof_preambles;
} }
phy_interface_mac::prach_info_t prach_info = phy_h->prach_get_info(); phy_interface_mac_lte::prach_info_t prach_info = phy_h->prach_get_info();
delta_preamble_db = delta_preamble_db_table[prach_info.preamble_format % 5]; delta_preamble_db = delta_preamble_db_table[prach_info.preamble_format % 5];
if (rach_cfg.contentionResolutionTimer > 0) { if (rach_cfg.contentionResolutionTimer > 0) {
@ -276,7 +276,7 @@ bool ra_proc::is_rar_window(int* rar_window_start, int* rar_window_length)
void ra_proc::step_pdcch_setup() void ra_proc::step_pdcch_setup()
{ {
phy_interface_mac::prach_info_t info = phy_h->prach_get_info(); phy_interface_mac_lte::prach_info_t info = phy_h->prach_get_info();
if (info.is_transmitted) { if (info.is_transmitted) {
ra_rnti = 1 + info.tti_ra % 10 + info.f_id; ra_rnti = 1 + info.tti_ra % 10 + info.f_id;
rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d, f_id=%d\n", sel_preamble, ra_rnti, info.tti_ra, info.f_id); rInfo("seq=%d, ra-rnti=0x%x, ra-tti=%d, f_id=%d\n", sel_preamble, ra_rnti, info.tti_ra, info.f_id);
@ -287,9 +287,9 @@ void ra_proc::step_pdcch_setup()
} }
} }
void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_dl_t grant, mac_interface_phy::tb_action_dl_t* action) void ra_proc::new_grant_dl(mac_interface_phy_lte::mac_grant_dl_t grant, mac_interface_phy_lte::tb_action_dl_t* action)
{ {
bzero(action, sizeof(mac_interface_phy::tb_action_dl_t)); bzero(action, sizeof(mac_interface_phy_lte::tb_action_dl_t));
if (grant.tb[0].tbs < MAX_RAR_PDU_LEN) { if (grant.tb[0].tbs < MAX_RAR_PDU_LEN) {
rDebug("DL dci found RA-RNTI=%d\n", ra_rnti); rDebug("DL dci found RA-RNTI=%d\n", ra_rnti);
@ -385,7 +385,7 @@ void ra_proc::tb_decoded_ok() {
void ra_proc::step_response_reception(uint32_t tti) void ra_proc::step_response_reception(uint32_t tti)
{ {
// do nothing. Processing done in tb_decoded_ok() // do nothing. Processing done in tb_decoded_ok()
phy_interface_mac::prach_info_t prach_info = phy_h->prach_get_info(); phy_interface_mac_lte::prach_info_t prach_info = phy_h->prach_get_info();
if (prach_info.is_transmitted && !rar_received) { if (prach_info.is_transmitted && !rar_received) {
uint32_t interval = srslte_tti_interval(tti, prach_info.tti_ra + 3 + rach_cfg.responseWindowSize); uint32_t interval = srslte_tti_interval(tti, prach_info.tti_ra + 3 + rach_cfg.responseWindowSize);
if (interval > 1 && interval < 100) { if (interval > 1 && interval < 100) {

@ -24,8 +24,7 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/proc_sr.h" #include "srsue/hdr/stack/mac/proc_sr.h"
namespace srsue { namespace srsue {
@ -33,7 +32,7 @@ sr_proc::sr_proc() {
initiated = false; initiated = false;
} }
void sr_proc::init(phy_interface_mac* phy_h_, rrc_interface_mac* rrc_, srslte::log* log_h_) void sr_proc::init(phy_interface_mac_lte* phy_h_, rrc_interface_mac* rrc_, srslte::log* log_h_)
{ {
log_h = log_h_; log_h = log_h_;
rrc = rrc_; rrc = rrc_;

@ -24,7 +24,7 @@
#define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__) #define Info(fmt, ...) log_h->info(fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) log_h->debug(fmt, ##__VA_ARGS__)
#include "srsue/hdr/mac/ul_harq.h" #include "srsue/hdr/stack/mac/ul_harq.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/mac_pcap.h" #include "srslte/common/mac_pcap.h"
@ -88,9 +88,10 @@ void ul_harq_entity::start_pcap(srslte::mac_pcap* pcap_)
} }
/***************** PHY->MAC interface for UL processes **************************/ /***************** PHY->MAC interface for UL processes **************************/
void ul_harq_entity::new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, mac_interface_phy::tb_action_ul_t* action) void ul_harq_entity::new_grant_ul(mac_interface_phy_lte::mac_grant_ul_t grant,
mac_interface_phy_lte::tb_action_ul_t* action)
{ {
bzero(action, sizeof(mac_interface_phy::tb_action_ul_t)); bzero(action, sizeof(mac_interface_phy_lte::tb_action_ul_t));
if (grant.pid >= SRSLTE_MAX_HARQ_PROC) { if (grant.pid >= SRSLTE_MAX_HARQ_PROC) {
Error("Invalid PID: %d\n", grant.pid); Error("Invalid PID: %d\n", grant.pid);
@ -133,7 +134,7 @@ ul_harq_entity::ul_harq_process::ul_harq_process()
pdu_ptr = NULL; pdu_ptr = NULL;
payload_buffer = NULL; payload_buffer = NULL;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_ul_t)); bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_ul_t));
harq_feedback = false; harq_feedback = false;
is_initiated = false; is_initiated = false;
@ -180,7 +181,7 @@ void ul_harq_entity::ul_harq_process::reset()
current_tx_nb = 0; current_tx_nb = 0;
current_irv = 0; current_irv = 0;
is_grant_configured = false; is_grant_configured = false;
bzero(&cur_grant, sizeof(mac_interface_phy::mac_grant_ul_t)); bzero(&cur_grant, sizeof(mac_interface_phy_lte::mac_grant_ul_t));
} }
void ul_harq_entity::ul_harq_process::reset_ndi() void ul_harq_entity::ul_harq_process::reset_ndi()
@ -190,8 +191,8 @@ void ul_harq_entity::ul_harq_process::reset_ndi()
#define grant_is_rar() (grant.rnti == harq_entity->rntis->temp_rnti) #define grant_is_rar() (grant.rnti == harq_entity->rntis->temp_rnti)
void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy::mac_grant_ul_t grant, void ul_harq_entity::ul_harq_process::new_grant_ul(mac_interface_phy_lte::mac_grant_ul_t grant,
mac_interface_phy::tb_action_ul_t* action) mac_interface_phy_lte::tb_action_ul_t* action)
{ {
if (grant.phich_available) { if (grant.phich_available) {
if (grant.tb.ndi_present && (grant.tb.ndi == get_ndi()) && (grant.tb.tbs != 0)) { if (grant.tb.ndi_present && (grant.tb.ndi == get_ndi()) && (grant.tb.tbs != 0)) {
@ -327,8 +328,8 @@ int ul_harq_entity::ul_harq_process::get_current_tbs()
} }
// Retransmission with or w/o dci (Section 5.4.2.2) // Retransmission with or w/o dci (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_retx(mac_interface_phy::mac_grant_ul_t grant, void ul_harq_entity::ul_harq_process::generate_retx(mac_interface_phy_lte::mac_grant_ul_t grant,
mac_interface_phy::tb_action_ul_t* action) mac_interface_phy_lte::tb_action_ul_t* action)
{ {
int irv_of_rv[4] = {0, 3, 1, 2}; int irv_of_rv[4] = {0, 3, 1, 2};
@ -367,8 +368,8 @@ void ul_harq_entity::ul_harq_process::generate_retx(mac_interface_phy::mac_grant
} }
// New transmission (Section 5.4.2.2) // New transmission (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_new_tx(mac_interface_phy::mac_grant_ul_t grant, void ul_harq_entity::ul_harq_process::generate_new_tx(mac_interface_phy_lte::mac_grant_ul_t grant,
mac_interface_phy::tb_action_ul_t* action) mac_interface_phy_lte::tb_action_ul_t* action)
{ {
// Compute average number of retransmissions per packet considering previous packet // Compute average number of retransmissions per packet considering previous packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float)current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++); harq_entity->average_retx = SRSLTE_VEC_CMA((float)current_tx_nb, harq_entity->average_retx, harq_entity->nof_pkts++);
@ -383,7 +384,7 @@ void ul_harq_entity::ul_harq_process::generate_new_tx(mac_interface_phy::mac_gra
} }
// Transmission of pending frame (Section 5.4.2.2) // Transmission of pending frame (Section 5.4.2.2)
void ul_harq_entity::ul_harq_process::generate_tx(mac_interface_phy::tb_action_ul_t* action) void ul_harq_entity::ul_harq_process::generate_tx(mac_interface_phy_lte::tb_action_ul_t* action)
{ {
current_tx_nb++; current_tx_nb++;

@ -19,7 +19,7 @@
* *
*/ */
#include "srsue/hdr/rrc/rrc.h" #include "srsue/hdr/stack/rrc/rrc.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 "srslte/common/security.h" #include "srslte/common/security.h"
@ -110,7 +110,7 @@ void rrc::log_rrc_message(const std::string source, const direction_t dir, const
} }
} }
void rrc::init(phy_interface_rrc* phy_, void rrc::init(phy_interface_rrc_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_,
@ -119,7 +119,7 @@ void rrc::init(phy_interface_rrc* phy_,
gw_interface_rrc* gw_, gw_interface_rrc* gw_,
mac_interface_timers* mac_timers_, mac_interface_timers* mac_timers_,
srslte::log* rrc_log_, srslte::log* rrc_log_,
rrc_args_t* args_) const rrc_args_t& args_)
{ {
pool = byte_buffer_pool::get_instance(); pool = byte_buffer_pool::get_instance();
phy = phy_; phy = phy_;
@ -131,6 +131,8 @@ void rrc::init(phy_interface_rrc* phy_,
gw = gw_; gw = gw_;
rrc_log = rrc_log_; rrc_log = rrc_log_;
args = args_;
// Use MAC timers // Use MAC timers
mac_timers = mac_timers_; mac_timers = mac_timers_;
state = RRC_STATE_IDLE; state = RRC_STATE_IDLE;
@ -140,16 +142,6 @@ void rrc::init(phy_interface_rrc* phy_,
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
if (args_) {
args = *args_;
} else {
args.ue_category_str = SRSLTE_UE_CATEGORY_DEFAULT;
args.ue_category = strtol(SRSLTE_UE_CATEGORY_DEFAULT, NULL, 10);
args.supported_bands[0] = SRSLTE_RELEASE_DEFAULT;
args.nof_supported_bands = 1;
args.feature_group = 0xe6041000;
}
t300 = mac_timers->timer_get_unique_id(); t300 = mac_timers->timer_get_unique_id();
t301 = mac_timers->timer_get_unique_id(); t301 = mac_timers->timer_get_unique_id();
t302 = mac_timers->timer_get_unique_id(); t302 = mac_timers->timer_get_unique_id();
@ -205,10 +197,6 @@ bool rrc::have_drb() {
return drb_up; return drb_up;
} }
void rrc::set_args(rrc_args_t args_) {
args = args_;
}
/* /*
* Low priority thread to run functions that can not be executed from main thread * Low priority thread to run functions that can not be executed from main thread
*/ */
@ -370,10 +358,10 @@ int rrc::plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS])
rrc_log->info("Starting PLMN search\n"); rrc_log->info("Starting PLMN search\n");
uint32_t nof_plmns = 0; uint32_t nof_plmns = 0;
phy_interface_rrc::cell_search_ret_t ret; phy_interface_rrc_lte::cell_search_ret_t ret;
do { do {
ret = cell_search(); ret = cell_search();
if (ret.found == phy_interface_rrc::cell_search_ret_t::CELL_FOUND) { if (ret.found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) {
if (serving_cell->has_sib1()) { if (serving_cell->has_sib1()) {
// Save PLMN and TAC to NAS // Save PLMN and TAC to NAS
for (uint32_t i = 0; i < serving_cell->nof_plmns(); i++) { for (uint32_t i = 0; i < serving_cell->nof_plmns(); i++) {
@ -389,15 +377,15 @@ int rrc::plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS])
rrc_log->error("SIB1 not acquired\n"); rrc_log->error("SIB1 not acquired\n");
} }
} }
} while (ret.last_freq == phy_interface_rrc::cell_search_ret_t::MORE_FREQS && } while (ret.last_freq == phy_interface_rrc_lte::cell_search_ret_t::MORE_FREQS &&
ret.found != phy_interface_rrc::cell_search_ret_t::ERROR); ret.found != phy_interface_rrc_lte::cell_search_ret_t::ERROR);
// Process all pending measurements before returning // Process all pending measurements before returning
process_phy_meas(); process_phy_meas();
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
if (ret.found == phy_interface_rrc::cell_search_ret_t::ERROR) { if (ret.found == phy_interface_rrc_lte::cell_search_ret_t::ERROR) {
return -1; return -1;
} else { } else {
return nof_plmns; return nof_plmns;
@ -822,14 +810,14 @@ bool rrc::si_acquire(uint32_t sib_index)
/* Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet /* Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet
*/ */
phy_interface_rrc::cell_search_ret_t rrc::cell_search() phy_interface_rrc_lte::cell_search_ret_t rrc::cell_search()
{ {
phy_interface_rrc::phy_cell_t new_cell; phy_interface_rrc_lte::phy_cell_t new_cell;
phy_interface_rrc::cell_search_ret_t ret = phy->cell_search(&new_cell); phy_interface_rrc_lte::cell_search_ret_t ret = phy->cell_search(&new_cell);
switch(ret.found) { switch(ret.found) {
case phy_interface_rrc::cell_search_ret_t::CELL_FOUND: case phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND:
rrc_log->info("Cell found in this frequency. Setting new serving cell...\n"); rrc_log->info("Cell found in this frequency. Setting new serving cell...\n");
// Create cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search. // Create cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search.
@ -852,10 +840,10 @@ phy_interface_rrc::cell_search_ret_t rrc::cell_search()
rrc_log->warning("Could not camp on found cell. Trying next one...\n"); rrc_log->warning("Could not camp on found cell. Trying next one...\n");
} }
break; break;
case phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND: case phy_interface_rrc_lte::cell_search_ret_t::CELL_NOT_FOUND:
rrc_log->info("No cells found.\n"); rrc_log->info("No cells found.\n");
break; break;
case phy_interface_rrc::cell_search_ret_t::ERROR: case phy_interface_rrc_lte::cell_search_ret_t::ERROR:
rrc_log->error("In cell search. Finishing PLMN search\n"); rrc_log->error("In cell search. Finishing PLMN search\n");
break; break;
} }
@ -914,9 +902,9 @@ rrc::cs_ret_t rrc::cell_selection()
// If can not find any suitable cell, search again // If can not find any suitable cell, search again
rrc_log->info("Cell selection and reselection in IDLE did not find any suitable cell. Searching again\n"); rrc_log->info("Cell selection and reselection in IDLE did not find any suitable cell. Searching again\n");
// If can not camp on any cell, search again for new cells // If can not camp on any cell, search again for new cells
phy_interface_rrc::cell_search_ret_t ret = cell_search(); phy_interface_rrc_lte::cell_search_ret_t ret = cell_search();
return (ret.found == phy_interface_rrc::cell_search_ret_t::CELL_FOUND)?CHANGED_CELL:NO_CELL; return (ret.found == phy_interface_rrc_lte::cell_search_ret_t::CELL_FOUND) ? CHANGED_CELL : NO_CELL;
} }
// Cell selection criteria Section 5.2.3.2 of 36.304 // Cell selection criteria Section 5.2.3.2 of 36.304
@ -958,7 +946,8 @@ void rrc::cell_reselection(float rsrp, float rsrq)
} }
// Set new serving cell // Set new serving cell
void rrc::set_serving_cell(phy_interface_rrc::phy_cell_t phy_cell) { void rrc::set_serving_cell(phy_interface_rrc_lte::phy_cell_t phy_cell)
{
int cell_idx = find_neighbour_cell(phy_cell.earfcn, phy_cell.cell.id); int cell_idx = find_neighbour_cell(phy_cell.earfcn, phy_cell.cell.id);
if (cell_idx >= 0) { if (cell_idx >= 0) {
set_serving_cell(cell_idx); set_serving_cell(cell_idx);
@ -1089,14 +1078,15 @@ bool rrc::add_neighbour_cell(cell_t *new_cell) {
// If only neighbour PCI is provided, copy full cell from serving cell // If only neighbour PCI is provided, copy full cell from serving cell
bool rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) { bool rrc::add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp) {
phy_interface_rrc::phy_cell_t phy_cell; phy_interface_rrc_lte::phy_cell_t phy_cell;
phy_cell = serving_cell->phy_cell; phy_cell = serving_cell->phy_cell;
phy_cell.earfcn = earfcn; phy_cell.earfcn = earfcn;
phy_cell.cell.id = pci; phy_cell.cell.id = pci;
return add_neighbour_cell(phy_cell, rsrp); return add_neighbour_cell(phy_cell, rsrp);
} }
bool rrc::add_neighbour_cell(phy_interface_rrc::phy_cell_t phy_cell, float rsrp) { bool rrc::add_neighbour_cell(phy_interface_rrc_lte::phy_cell_t phy_cell, float rsrp)
{
if (phy_cell.earfcn == 0) { if (phy_cell.earfcn == 0) {
phy_cell.earfcn = serving_cell->get_earfcn(); phy_cell.earfcn = serving_cell->get_earfcn();
} }
@ -1137,18 +1127,8 @@ int rrc::find_neighbour_cell(uint32_t earfcn, uint32_t pci) {
* *
* *
*******************************************************************************/ *******************************************************************************/
std::string rrc::print_mbms()
void rrc::print_mbms()
{ {
if (!rrc_log) {
return;
}
if (!serving_cell->has_mcch) {
rrc_log->console("MCCH not available for current cell\n");
return;
}
asn1::rrc::mcch_msg_type_c msg = serving_cell->mcch.msg; asn1::rrc::mcch_msg_type_c msg = serving_cell->mcch.msg;
std::stringstream ss; std::stringstream ss;
for (uint32_t i = 0; i < msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9.size(); i++) { for (uint32_t i = 0; i < msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9.size(); i++) {
@ -1169,9 +1149,7 @@ void rrc::print_mbms()
ss << ", LCID: " << sess->lc_ch_id_r9 << std::endl; ss << ", LCID: " << sess->lc_ch_id_r9 << std::endl;
} }
} }
// rrc_log->console(ss.str().c_str()); return ss.str();
std::cout << ss.str();
return;
} }
bool rrc::mbms_service_start(uint32_t serv, uint32_t port) bool rrc::mbms_service_start(uint32_t serv, uint32_t port)
@ -1182,6 +1160,8 @@ bool rrc::mbms_service_start(uint32_t serv, uint32_t port)
return ret; return ret;
} }
rrc_log->info("%s\n", print_mbms().c_str());
asn1::rrc::mcch_msg_type_c msg = serving_cell->mcch.msg; asn1::rrc::mcch_msg_type_c msg = serving_cell->mcch.msg;
for (uint32_t i = 0; i < msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9.size(); i++) { for (uint32_t i = 0; i < msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9.size(); i++) {
pmch_info_r9_s* pmch = &msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[i]; pmch_info_r9_s* pmch = &msg.c1().mbsfn_area_cfg_r9().pmch_info_list_r9[i];
@ -1992,7 +1972,7 @@ void rrc::write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
{ {
if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) { if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) {
//TODO: handle MCCH notifications and update MCCH //TODO: handle MCCH notifications and update MCCH
if(0 == lcid && !serving_cell->has_mcch) { if (0 == lcid && !serving_cell->has_mcch) {
asn1::bit_ref bref(pdu->msg, pdu->N_bytes); asn1::bit_ref bref(pdu->msg, pdu->N_bytes);
if (serving_cell->mcch.unpack(bref) != asn1::SRSASN_SUCCESS or if (serving_cell->mcch.unpack(bref) != asn1::SRSASN_SUCCESS or
serving_cell->mcch.msg.type().value != mcch_msg_type_c::types_opts::c1) { serving_cell->mcch.msg.type().value != mcch_msg_type_c::types_opts::c1) {
@ -2018,7 +1998,6 @@ void rrc::write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
/******************************************************************************* /*******************************************************************************
* *
* *
*
* Packet processing * Packet processing
* *
* *
@ -2474,7 +2453,7 @@ void rrc::apply_rr_config_common(rr_cfg_common_s* config, bool send_lower_layers
current_mac_cfg.set_rach_cfg_common(config->rach_cfg_common); current_mac_cfg.set_rach_cfg_common(config->rach_cfg_common);
} }
phy_interface_rrc::phy_cfg_common_t* common = &current_phy_cfg.common; phy_interface_rrc_lte::phy_cfg_common_t* common = &current_phy_cfg.common;
if (config->prach_cfg.prach_cfg_info_present) { if (config->prach_cfg.prach_cfg_info_present) {
common->prach_cnfg.prach_cfg_info = config->prach_cfg.prach_cfg_info; common->prach_cnfg.prach_cfg_info = config->prach_cfg.prach_cfg_info;

@ -0,0 +1,188 @@
/*
* 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 "srsue/hdr/stack/ue_stack_lte.h"
#include "srslte/srslte.h"
using namespace srslte;
namespace srsue {
ue_stack_lte::ue_stack_lte() : running(false), args(), logger(nullptr), usim(nullptr), phy(nullptr) {}
ue_stack_lte::~ue_stack_lte()
{
stop();
}
std::string ue_stack_lte::get_type()
{
return "lte";
}
int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_)
{
phy = phy_;
if (init(args_, logger_)) {
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
{
args = args_;
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);
nas_log.init("NAS ", logger);
gw_log.init("GW ", logger);
usim_log.init("USIM", logger);
pool_log.init("POOL", logger);
pool_log.set_level(srslte::LOG_LEVEL_ERROR);
byte_buffer_pool::get_instance()->set_log(&pool_log);
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);
nas_log.set_level(args.log.nas_level);
gw_log.set_level(args.log.gw_level);
usim_log.set_level(args.log.usim_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);
nas_log.set_hex_limit(args.log.nas_hex_limit);
gw_log.set_hex_limit(args.log.gw_hex_limit);
usim_log.set_hex_limit(args.log.usim_hex_limit);
// Set up pcap
if (args.pcap.enable) {
mac_pcap.open(args.pcap.filename.c_str());
mac.start_pcap(&mac_pcap);
}
if (args.pcap.nas_enable) {
nas_pcap.open(args.pcap.nas_filename.c_str());
nas.start_pcap(&nas_pcap);
}
// Init USIM first to allow early exit in case reader couldn't be found
usim = usim_base::get_instance(&args.usim);
if (usim->init(&args.usim, &usim_log)) {
usim_log.console("Failed to initialize USIM.\n");
return SRSLTE_ERROR;
}
mac.init(phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, NULL, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
nas.init(usim, &rrc, &gw, &nas_log, args.nas);
gw.init(&pdcp, &nas, &gw_log, args.gw);
rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log, args.rrc);
running = true;
return SRSLTE_SUCCESS;
}
void ue_stack_lte::stop()
{
if (running) {
usim->stop();
nas.stop();
rrc.stop();
// Caution here order of stop is very important to avoid locks
// Stop RLC and PDCP before GW to avoid locking on queue
rlc.stop();
pdcp.stop();
gw.stop();
mac.stop();
if (args.pcap.enable) {
mac_pcap.close();
}
if (args.pcap.nas_enable) {
nas_pcap.close();
}
running = false;
}
}
bool ue_stack_lte::switch_on()
{
if (running) {
return nas.attach_request();
}
return false;
}
bool ue_stack_lte::switch_off()
{
// generate detach request
nas.detach_request();
// wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2)
const uint32_t RB_ID_SRB1 = 1;
int cnt = 0, timeout = 5;
while (rlc.has_data(RB_ID_SRB1) && ++cnt <= timeout) {
sleep(1);
}
bool detach_sent = true;
if (rlc.has_data(RB_ID_SRB1)) {
nas_log.warning("Detach couldn't be sent after %ds.\n", timeout);
detach_sent = false;
}
return detach_sent;
}
bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
{
if (EMM_STATE_REGISTERED == nas.get_state()) {
if (RRC_STATE_CONNECTED == rrc.get_state()) {
mac.get_metrics(metrics->mac);
rlc.get_metrics(metrics->rlc);
gw.get_metrics(metrics->gw);
return true;
}
}
return false;
}
bool ue_stack_lte::is_rrc_connected()
{
return rrc.is_connected();
}
}

@ -19,7 +19,7 @@
* *
*/ */
#include "srsue/hdr/upper/gw.h" #include "srsue/hdr/stack/upper/gw.h"
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
@ -67,26 +67,27 @@ struct in6_ifreq {
namespace srsue { namespace srsue {
#define DRB1_LCID 3
gw::gw() gw::gw()
:if_up(false) :if_up(false)
{ {
current_ip_addr = 0; current_ip_addr = 0;
default_netmask = true;
tundevname = "";
} }
void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, srslte::srslte_gw_config_t cfg_) void gw::init(pdcp_interface_gw* pdcp_, nas_interface_gw* nas_, srslte::log* gw_log_, gw_args_t args_)
{ {
pool = srslte::byte_buffer_pool::get_instance(); pool = srslte::byte_buffer_pool::get_instance();
pdcp = pdcp_; pdcp = pdcp_;
nas = nas_; nas = nas_;
gw_log = gw_log_; gw_log = gw_log_;
cfg = cfg_; args = args_;
run_enable = true; run_enable = true;
gettimeofday(&metrics_time[1], NULL); gettimeofday(&metrics_time[1], NULL);
dl_tput_bytes = 0; dl_tput_bytes = 0;
ul_tput_bytes = 0; ul_tput_bytes = 0;
// MBSFN // MBSFN
mbsfn_sock_fd = socket(AF_INET, SOCK_DGRAM, 0); mbsfn_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (mbsfn_sock_fd < 0) { if (mbsfn_sock_fd < 0) {
@ -147,18 +148,6 @@ void gw::get_metrics(gw_metrics_t &m)
ul_tput_bytes = 0; ul_tput_bytes = 0;
} }
void gw::set_netmask(std::string netmask)
{
default_netmask = false;
this->netmask = netmask;
}
void gw::set_tundevname(const std::string & devname)
{
tundevname = devname;
}
/******************************************************************************* /*******************************************************************************
PDCP interface PDCP interface
*******************************************************************************/ *******************************************************************************/
@ -292,9 +281,10 @@ void gw::run_thread()
if (pkt_len == pdu->N_bytes) { if (pkt_len == pdu->N_bytes) {
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
while(run_enable && !pdcp->is_lcid_enabled(cfg.lcid) && attach_wait < ATTACH_WAIT_TOUT) { while (run_enable && !pdcp->is_lcid_enabled(DRB1_LCID) && attach_wait < ATTACH_WAIT_TOUT) {
if (!attach_wait) { if (!attach_wait) {
gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_wait, ATTACH_WAIT_TOUT); gw_log->info(
"LCID=%d not active, requesting NAS attach (%d/%d)\n", DRB1_LCID, attach_wait, ATTACH_WAIT_TOUT);
if (!nas->attach_request()) { if (!nas->attach_request()) {
gw_log->warning("Could not re-establish the connection\n"); gw_log->warning("Could not re-establish the connection\n");
} }
@ -310,10 +300,10 @@ void gw::run_thread()
} }
// Send PDU directly to PDCP // Send PDU directly to PDCP
if (pdcp->is_lcid_enabled(cfg.lcid)) { if (pdcp->is_lcid_enabled(DRB1_LCID)) {
pdu->set_timestamp(); pdu->set_timestamp();
ul_tput_bytes += pdu->N_bytes; ul_tput_bytes += pdu->N_bytes;
pdcp->write_sdu(cfg.lcid, std::move(pdu), false); pdcp->write_sdu(DRB1_LCID, std::move(pdu), false);
do { do {
pdu = srslte::allocate_unique_buffer(*pool); pdu = srslte::allocate_unique_buffer(*pool);
if (!pdu) { if (!pdu) {
@ -360,7 +350,8 @@ srslte::error_t gw::init_if(char *err_str)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, tundevname.c_str(), std::min(tundevname.length(), (size_t)(IFNAMSIZ-1))); strncpy(
ifr.ifr_ifrn.ifrn_name, args.tun_dev_name.c_str(), std::min(args.tun_dev_name.length(), (size_t)(IFNAMSIZ - 1)));
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0; ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0;
if (0 > ioctl(tun_fd, TUNSETIFF, &ifr)) { if (0 > ioctl(tun_fd, TUNSETIFF, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
@ -420,11 +411,7 @@ srslte::error_t gw::setup_if_addr4(uint32_t ip_addr, char *err_str)
return (srslte::ERROR_CANT_START); return (srslte::ERROR_CANT_START);
} }
ifr.ifr_netmask.sa_family = AF_INET; ifr.ifr_netmask.sa_family = AF_INET;
const char *mask = "255.255.255.0"; ((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(args.tun_dev_netmask.c_str());
if (!default_netmask) {
mask = netmask.c_str();
}
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(mask);
if (0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) { if (0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to set socket netmask: %s\n", err_str); gw_log->debug("Failed to set socket netmask: %s\n", err_str);
@ -505,10 +492,10 @@ bool gw::find_ipv6_addr(struct in6_addr *in6_out)
char buf[1024]; char buf[1024];
} req; } req;
gw_log->debug("Trying to obtain IPv6 addr of %s interface\n", tundevname.c_str()); gw_log->debug("Trying to obtain IPv6 addr of %s interface\n", args.tun_dev_name.c_str());
//Get Interface Index //Get Interface Index
if_index = if_nametoindex(tundevname.c_str()); if_index = if_nametoindex(args.tun_dev_name.c_str());
if(if_index == 0){ if(if_index == 0){
gw_log->error("Could not find interface index\n"); gw_log->error("Could not find interface index\n");
goto err_out; goto err_out;
@ -607,7 +594,7 @@ void gw::del_ipv6_addr(struct in6_addr *in6p)
} req; } req;
//Get Interface Index //Get Interface Index
if_index = if_nametoindex(tundevname.c_str()); if_index = if_nametoindex(args.tun_dev_name.c_str());
if(if_index == 0){ if(if_index == 0){
gw_log->error("Could not find interface index\n"); gw_log->error("Could not find interface index\n");
goto out; goto out;

@ -19,7 +19,7 @@
* *
*/ */
#include "srsue/hdr/upper/nas.h" #include "srsue/hdr/stack/upper/nas.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 "srslte/common/security.h" #include "srslte/common/security.h"
@ -34,7 +34,7 @@
#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 "srslte/common/security.h" #include "srslte/common/security.h"
#include "srsue/hdr/upper/nas.h" #include "srsue/hdr/stack/upper/nas.h"
using namespace srslte; using namespace srslte;
using namespace asn1::rrc; using namespace asn1::rrc;

@ -22,7 +22,7 @@
#include <sstream> #include <sstream>
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include "srsue/hdr/upper/pcsc_usim.h" #include "srsue/hdr/stack/upper/pcsc_usim.h"
#include "string.h" #include "string.h"
#define CHECK_SIM_PIN 1 #define CHECK_SIM_PIN 1
@ -30,7 +30,7 @@
using namespace srslte; using namespace srslte;
using namespace asn1::rrc; using namespace asn1::rrc;
namespace srsue{ namespace srsue {
pcsc_usim::pcsc_usim() : initiated(false) pcsc_usim::pcsc_usim() : initiated(false)
{ {

@ -19,9 +19,9 @@
* *
*/ */
#include <sstream> #include "srsue/hdr/stack/upper/usim.h"
#include "srsue/hdr/upper/usim.h"
#include "srslte/common/bcd_helpers.h" #include "srslte/common/bcd_helpers.h"
#include <sstream>
using namespace srslte; using namespace srslte;
using namespace asn1::rrc; using namespace asn1::rrc;

@ -19,16 +19,16 @@
* *
*/ */
#include "srsue/hdr/upper/usim_base.h" #include "srsue/hdr/stack/upper/usim_base.h"
#include "srsue/hdr/upper/usim.h" #include "srsue/hdr/stack/upper/usim.h"
#ifdef HAVE_PCSC #ifdef HAVE_PCSC
#include "srsue/hdr/upper/pcsc_usim.h" #include "srsue/hdr/stack/upper/pcsc_usim.h"
#endif #endif
namespace srsue{ namespace srsue {
usim_base* usim_base::get_instance(usim_args_t *args, srslte::log *usim_log_) usim_base* usim_base::get_instance(usim_args_t* args)
{ {
usim_base* instance = NULL; usim_base* instance = NULL;
if (args->mode == "soft") { if (args->mode == "soft") {

@ -20,391 +20,251 @@
*/ */
#include "srsue/hdr/ue.h" #include "srsue/hdr/ue.h"
#include "srslte/build_info.h"
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include <pthread.h> #include "srsue/hdr/phy/phy.h"
#include <iostream> #include "srsue/hdr/radio/ue_radio.h"
#include <string> #include "srsue/hdr/stack/ue_stack_lte.h"
#include <algorithm> #include <algorithm>
#include <iostream>
#include <iterator> #include <iterator>
#include <pthread.h>
#include <sstream> #include <sstream>
#include <string>
using namespace srslte; using namespace srslte;
namespace srsue{ namespace srsue {
ue::ue() ue::ue() : logger(NULL)
:started(false), mac_log()
{ {
usim = NULL; // print build info
logger = NULL; std::cout << std::endl << get_build_string() << std::endl;
args = NULL;
// load FFTW wisdom
srslte_dft_load();
pool = byte_buffer_pool::get_instance();
} }
ue::~ue() ue::~ue()
{ {
for (uint32_t i = 0; i < phy_log.size(); i++) { byte_buffer_pool::cleanup();
if (phy_log[i]) {
delete(phy_log[i]);
}
}
if (usim) {
delete usim;
}
}
bool ue::init(all_args_t *args_) {
args = args_;
int nof_phy_threads = args->expert.phy.nof_phy_threads; // save FFTW wisdom
if (nof_phy_threads > srsue::phy::MAX_WORKERS) { srslte_dft_exit();
nof_phy_threads = srsue::phy::MAX_WORKERS; }
}
if (!args->log.filename.compare("stdout")) { int ue::init(const all_args_t& args_)
{
// Setup logging
if (!args_.log.filename.compare("stdout")) {
logger = &logger_stdout; logger = &logger_stdout;
} else { } 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("\n\n");
logger_file.log(get_build_string().c_str()); logger_file.log(get_build_string().c_str());
logger = &logger_file; logger = &logger_file;
} }
rf_log.init("RF ", logger); // Init UE log
// Create array of pointers to phy_logs log.init("UE ", logger);
for (int i=0;i<nof_phy_threads;i++) { log.set_level(srslte::LOG_LEVEL_INFO);
srslte::log_filter *mylog = new srslte::log_filter;
char tmp[16];
sprintf(tmp, "PHY%d",i);
mylog->init(tmp, logger, true);
phy_log.push_back(mylog);
}
mac_log.init("MAC ", logger, true); // Validate arguments
rlc_log.init("RLC ", logger); if (parse_args(args_)) {
pdcp_log.init("PDCP", logger); log.console("Error processing arguments.\n");
rrc_log.init("RRC ", logger); return SRSLTE_ERROR;
nas_log.init("NAS ", logger);
gw_log.init("GW ", logger);
usim_log.init("USIM", logger);
pool_log.init("POOL", logger);
pool_log.set_level(srslte::LOG_LEVEL_ERROR);
byte_buffer_pool::get_instance()->set_log(&pool_log);
// Init logs
rf_log.set_level(srslte::LOG_LEVEL_INFO);
rf_log.info("Starting UE\n");
for (int i=0;i<nof_phy_threads;i++) {
((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level));
} }
/* here we add a log layer to handle logging from the phy library*/ // Instantiate layers and stack together our UE
if (level(args->log.phy_lib_level) != LOG_LEVEL_NONE) { if (args.stack.type == "lte") {
srslte::log_filter *lib_log = new srslte::log_filter; std::unique_ptr<ue_stack_lte> lte_stack = std::unique_ptr<ue_stack_lte>(new ue_stack_lte());
char tmp[16]; if (!lte_stack) {
sprintf(tmp, "PHY_LIB"); log.console("Error creating LTE stack instance.\n");
lib_log->init(tmp, logger, true); return SRSLTE_ERROR;
phy_log.push_back(lib_log);
((srslte::log_filter*) phy_log[nof_phy_threads])->set_level(level(args->log.phy_lib_level));
} else {
phy_log.push_back(NULL);
} }
mac_log.set_level(level(args->log.mac_level)); std::unique_ptr<srsue::phy> lte_phy = std::unique_ptr<srsue::phy>(new srsue::phy());
rlc_log.set_level(level(args->log.rlc_level)); if (!lte_phy) {
pdcp_log.set_level(level(args->log.pdcp_level)); log.console("Error creating LTE PHY instance.\n");
rrc_log.set_level(level(args->log.rrc_level)); return SRSLTE_ERROR;
nas_log.set_level(level(args->log.nas_level));
gw_log.set_level(level(args->log.gw_level));
usim_log.set_level(level(args->log.usim_level));
for (int i=0;i<nof_phy_threads + 1;i++) {
if (phy_log[i]) {
((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);
nas_log.set_hex_limit(args->log.nas_hex_limit);
gw_log.set_hex_limit(args->log.gw_hex_limit);
usim_log.set_hex_limit(args->log.usim_hex_limit);
// Set up pcap and trace
if(args->pcap.enable) {
mac_pcap.open(args->pcap.filename.c_str());
mac.start_pcap(&mac_pcap);
}
if(args->pcap.nas_enable) {
nas_pcap.open(args->pcap.nas_filename.c_str());
nas.start_pcap(&nas_pcap);
} }
// populate EARFCN list std::unique_ptr<ue_radio> lte_radio = std::unique_ptr<ue_radio>(new ue_radio());
std::vector<uint32_t> earfcn_list; if (!lte_radio) {
if (!args->rf.dl_earfcn.empty()) { log.console("Error creating radio multi instance.\n");
std::stringstream ss(args->rf.dl_earfcn); return SRSLTE_ERROR;
int idx = 0;
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
const int earfcn = atoi(substr.c_str());
args->rrc.supported_bands[idx] = srslte_band_get_band(earfcn);
args->rrc.nof_supported_bands = ++idx;
earfcn_list.push_back(earfcn);
} }
} else {
rrc_log.error("Error: dl_earfcn list is empty\n");
rrc_log.console("Error: dl_earfcn list is empty\n");
return false;
}
// Consider Carrier Aggregation support if more than one
args->rrc.support_ca = (args->rf.nof_rf_channels * args->rf.nof_radios) > 1;
// Init layers
// Init USIM first to allow early exit in case reader couldn't be found // init layers
usim = usim_base::get_instance(&args->usim, &usim_log); if (lte_radio->init(args.rf, logger, lte_phy.get())) {
if (usim->init(&args->usim, &usim_log)) { log.console("Error initializing radio.\n");
usim_log.console("Failed to initialize USIM.\n"); return SRSLTE_ERROR;
return false;
} }
// PHY inits in background, start before radio if (lte_phy->init(args.phy, logger, lte_stack.get(), lte_radio.get())) {
args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; log.console("Error initializing PHY.\n");
args->expert.phy.ue_category = args->rrc.ue_category; return SRSLTE_ERROR;
phy.init(radios, &mac, &rrc, phy_log, &args->expert.phy);
// Calculate number of carriers available in all radios
args->expert.phy.nof_radios = args->rf.nof_radios;
args->expert.phy.nof_rf_channels = args->rf.nof_rf_channels;
args->expert.phy.nof_carriers = args->rf.nof_radios * args->rf.nof_rf_channels;
// Generate RF-Channel to Carrier map
for (uint32_t i = 0; i < args->expert.phy.nof_carriers; i++) {
carrier_map_t* m = &args->expert.phy.carrier_map[i];
m->radio_idx = i / args->rf.nof_rf_channels;
m->channel_idx = (i % args->rf.nof_rf_channels) * args->rf.nof_rx_ant;
phy_log[0]->debug("Mapping carrier %d to channel %d in radio %d\n", i, m->channel_idx, m->radio_idx);
} }
/* Start Radio */ if (lte_stack->init(args.stack, logger, lte_phy.get())) {
char *dev_name = NULL; log.console("Error initializing stack.\n");
if (args->rf.device_name.compare("auto")) { return SRSLTE_ERROR;
dev_name = (char*) args->rf.device_name.c_str();
} }
char* dev_args[SRSLTE_MAX_RADIOS] = {NULL}; // move ownership
for (int i = 0; i < SRSLTE_MAX_RADIOS; i++) { stack = std::move(lte_stack);
if (args->rf.device_args[0].compare("auto")) { phy = std::move(lte_phy);
dev_args[i] = (char*)args->rf.device_args[i].c_str(); radio = std::move(lte_radio);
} } else {
log.console("Invalid stack type %s. Supported values are [lte].\n", args.stack.type.c_str());
return SRSLTE_ERROR;
} }
phy_log[0]->console("Opening %d RF devices with %d RF channels...\n", log.console("Waiting PHY to initialize ... ");
args->rf.nof_radios, phy->wait_initialize();
args->rf.nof_rf_channels * args->rf.nof_rx_ant); log.console("done!\n");
for (uint32_t r = 0; r < args->rf.nof_radios; r++) {
if (!radios[r].init(phy_log[0], dev_args[r], dev_name, args->rf.nof_rf_channels * args->rf.nof_rx_ant)) {
phy_log[0]->console(
"Failed to find device %s with args %s\n", args->rf.device_name.c_str(), args->rf.device_args[0].c_str());
return false;
}
// Set RF options return SRSLTE_SUCCESS;
if (args->rf.time_adv_nsamples.compare("auto")) { }
int t = atoi(args->rf.time_adv_nsamples.c_str());
radios[r].set_tx_adv(abs(t));
radios[r].set_tx_adv_neg(t < 0);
}
if (args->rf.burst_preamble.compare("auto")) {
radios[r].set_burst_preamble(atof(args->rf.burst_preamble.c_str()));
}
if (args->rf.continuous_tx.compare("auto")) {
phy_log[0]->console("set continuous %s\n", args->rf.continuous_tx.c_str());
radios[r].set_continuous_tx(args->rf.continuous_tx.compare("yes") ? false : true);
}
// Set PHY options int ue::parse_args(const all_args_t& args_)
{
// set member variable
args = args_;
if (args->rf.rx_gain < 0) { // carry out basic sanity checks
radios[r].start_agc(false); if (args.stack.rrc.mbms_service_id > -1) {
} else { if (!args.phy.interpolate_subframe_enabled) {
radios[r].set_rx_gain(args->rf.rx_gain); log.error("interpolate_subframe_enabled = %d, While using MBMS, "
"please set interpolate_subframe_enabled to true\n",
args.phy.interpolate_subframe_enabled);
return SRSLTE_ERROR;
} }
if (args->rf.tx_gain > 0) { if (args.phy.nof_phy_threads > 2) {
radios[r].set_tx_gain(args->rf.tx_gain); log.error("nof_phy_threads = %d, While using MBMS, please set "
} else { "number of phy threads to 1 or 2\n",
radios[r].set_tx_gain(args->rf.rx_gain); args.phy.nof_phy_threads);
phy_log[0]->console("\nWarning: TX gain was not set. Using open-loop power control (not working properly)\n\n"); return SRSLTE_ERROR;
} }
if ((0 == args.phy.snr_estim_alg.find("refs"))) {
radios[r].register_error_handler(rf_msg); log.error("snr_estim_alg = refs, While using MBMS, please set "
radios[r].set_freq_offset(args->rf.freq_offset); "algorithm to pss or empty \n");
return SRSLTE_ERROR;
} }
if (args->rf.tx_gain > 0) {
args->expert.phy.ul_pwr_ctrl_en = false;
} else {
args->expert.phy.ul_pwr_ctrl_en = true;
} }
mac.init(&phy, &rlc, &rrc, &mac_log, args->expert.phy.nof_carriers); // replicate some RF parameter to make them available to PHY
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); args.phy.nof_rx_ant = args.rf.nof_rx_ant;
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); args.phy.ue_category = args.stack.rrc.ue_category;
nas.init(usim, &rrc, &gw, &nas_log, args->nas);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
gw.set_netmask(args->expert.ip_netmask);
gw.set_tundevname(args->expert.ip_devname);
// set args and initialize RRC
rrc.init(&phy, &mac, &rlc, &pdcp, &nas, usim, &gw, &mac, &rrc_log, &args->rrc);
phy.set_earfcn(earfcn_list); // Calculate number of carriers available in all radios
args.phy.nof_radios = args.rf.nof_radios;
args.phy.nof_rf_channels = args.rf.nof_rf_channels;
args.phy.nof_carriers = args.rf.nof_radios * args.rf.nof_rf_channels;
if (args->rf.dl_freq > 0 && args->rf.ul_freq > 0) { if (args.phy.nof_carriers > SRSLTE_MAX_CARRIERS) {
phy.force_freq(args->rf.dl_freq, args->rf.ul_freq); log.error("Too many carriers (%d > %d)\n", args.phy.nof_carriers, SRSLTE_MAX_CARRIERS);
return SRSLTE_ERROR;
} }
phy_log[0]->console("Waiting PHY to initialize...\n"); // Generate RF-Channel to Carrier map
phy.wait_initialize(); for (uint32_t i = 0; i < args.phy.nof_carriers; i++) {
carrier_map_t* m = &args.phy.carrier_map[i];
m->radio_idx = i / args.rf.nof_rf_channels;
m->channel_idx = (i % args.rf.nof_rf_channels) * args.rf.nof_rx_ant;
log.debug("Mapping carrier %d to channel %d in radio %d\n", i, m->channel_idx, m->radio_idx);
}
// Enable AGC once PHY is initialized // populate EARFCN list
if (args->rf.rx_gain < 0) { if (!args.phy.dl_earfcn.empty()) {
phy.set_agc_enable(true); std::stringstream ss(args.phy.dl_earfcn);
int idx = 0;
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
const int earfcn = atoi(substr.c_str());
args.stack.rrc.supported_bands[idx] = srslte_band_get_band(earfcn);
args.stack.rrc.nof_supported_bands = ++idx;
args.phy.earfcn_list.push_back(earfcn);
}
} else {
log.error("Error: dl_earfcn list is empty\n");
log.console("Error: dl_earfcn list is empty\n");
return SRSLTE_ERROR;
} }
phy_log[0]->console("...\n"); // Set UE category
args.stack.rrc.ue_category = atoi(args.stack.rrc.ue_category_str.c_str());
started = true; // Consider Carrier Aggregation support if more than one
return true; args.stack.rrc.support_ca = (args.rf.nof_rf_channels * args.rf.nof_radios) > 1;
}
void ue::pregenerate_signals(bool enable) return SRSLTE_SUCCESS;
{
phy.enable_pregen_signals(enable);
} }
void ue::stop() void ue::stop()
{ {
if(started) // tear down UE in reverse order
{ if (stack) {
usim->stop(); stack->stop();
nas.stop();
rrc.stop();
// Caution here order of stop is very important to avoid locks
// Stop RLC and PDCP before GW to avoid locking on queue
rlc.stop();
pdcp.stop();
gw.stop();
// PHY must be stopped before radio otherwise it will lock on rf_recv()
mac.stop();
phy.stop();
for (uint32_t r = 0; r < args->rf.nof_radios; r++) {
radios[r].stop();
} }
usleep(1e5); if (phy) {
if(args->pcap.enable) { phy->stop();
mac_pcap.close();
}
if(args->pcap.nas_enable) {
nas_pcap.close();
} }
started = false;
if (radio) {
radio->stop();
} }
} }
bool ue::switch_on() { bool ue::switch_on() {
return nas.attach_request(); return stack->switch_on();
} }
bool ue::switch_off() { bool ue::switch_off() {
// stop UL data return stack->switch_off();
gw.stop();
// generate detach request
nas.detach_request();
// wait for max. 5s for it to be sent (according to TS 24.301 Sec 25.5.2.2)
const uint32_t RB_ID_SRB1 = 1;
int cnt = 0, timeout = 5;
while (rlc.has_data(RB_ID_SRB1) && ++cnt <= timeout) {
sleep(1);
}
bool detach_sent = true;
if (rlc.has_data(RB_ID_SRB1)) {
nas_log.warning("Detach couldn't be sent after %ds.\n", timeout);
detach_sent = false;
}
return detach_sent;
} }
bool ue::is_attached() bool ue::is_rrc_connected()
{ {
return rrc.is_connected(); return stack->is_rrc_connected();
}
void ue::start_plot() {
phy.start_plot();
} }
void ue::print_pool() { void ue::start_plot()
byte_buffer_pool::get_instance()->print_all_buffers(); {
phy->start_plot();
} }
bool ue::get_metrics(ue_metrics_t &m) bool ue::get_metrics(ue_metrics_t* m)
{ {
bzero(&m, sizeof(ue_metrics_t)); bzero(m, sizeof(ue_metrics_t));
m.rf = rf_metrics; phy->get_metrics(&m->phy);
bzero(&rf_metrics, sizeof(rf_metrics_t)); radio->get_metrics(&m->rf);
rf_metrics.rf_error = false; // Reset error flag stack->get_metrics(&m->stack);
if(EMM_STATE_REGISTERED == nas.get_state()) {
if(RRC_STATE_CONNECTED == rrc.get_state()) {
phy.get_metrics(m.phy);
mac.get_metrics(m.mac);
rlc.get_metrics(m.rlc);
gw.get_metrics(m.gw);
return true; return true;
}
}
return false;
} }
std::string ue::get_build_mode()
void ue::radio_overflow() {
phy.radio_overflow();
}
void ue::print_mbms()
{ {
rrc.print_mbms(); return std::string(srslte_get_build_mode());
} }
bool ue::mbms_service_start(uint32_t serv, uint32_t port) std::string ue::get_build_info()
{ {
return rrc.mbms_service_start(serv, port); if (std::string(srslte_get_build_info()).find(" ") != std::string::npos) {
return std::string(srslte_get_version());
}
return std::string(srslte_get_build_info());
} }
void ue::rf_msg(srslte_rf_error_t error) std::string ue::get_build_string()
{ {
ue_base *ue = ue_base::get_instance(LTE); std::stringstream ss;
ue->handle_rf_msg(error); ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl;
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { return ss.str();
ue->radio_overflow();
} else
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_RX) {
ue->stop();
ue->cleanup();
exit(-1);
}
} }
} // namespace srsue } // namespace srsue

@ -1,144 +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/.
*
*/
#include "srsue/hdr/ue_base.h"
#include "srsue/hdr/ue.h"
#include "srslte/srslte.h"
#include "srslte/build_info.h"
#include <pthread.h>
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
using namespace srslte;
namespace srsue {
static ue_base* instance = NULL;
pthread_mutex_t ue_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
ue_base* ue_base::get_instance(srsue_instance_type_t type)
{
pthread_mutex_lock(&ue_instance_mutex);
if(NULL == instance) {
switch (type) {
case LTE:
instance = new ue();
break;
default:
perror("Unknown UE type.\n");
}
}
pthread_mutex_unlock(&ue_instance_mutex);
return(instance);
}
ue_base::ue_base() {
// print build info
std::cout << std::endl << get_build_string() << std::endl;
// load FFTW wisdom
srslte_dft_load();
pool = byte_buffer_pool::get_instance();
}
ue_base::~ue_base() {
byte_buffer_pool::cleanup();
}
void ue_base::cleanup(void)
{
// save FFTW wisdom
srslte_dft_exit();
pthread_mutex_lock(&ue_instance_mutex);
if(NULL != instance) {
delete instance;
instance = NULL;
}
pthread_mutex_unlock(&ue_instance_mutex);
}
void ue_base::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 (detected in %s)\n", error.opt?"rx call":"asynchronous thread");
} 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 ue_base::level(std::string l)
{
std::transform(l.begin(), l.end(), l.begin(), ::toupper);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
}
std::string ue_base::get_build_mode()
{
return std::string(srslte_get_build_mode());
}
std::string ue_base::get_build_info()
{
if (std::string(srslte_get_build_info()).find(" ") != std::string::npos) {
return std::string(srslte_get_version());
}
return std::string(srslte_get_build_info());
}
std::string ue_base::get_build_string()
{
std::stringstream ss;
ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl;
return ss.str();
}
} // namespace srsue

@ -21,7 +21,7 @@
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srsue/hdr/mac/mac.h" #include "srsue/hdr/stack/mac/mac.h"
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
@ -62,11 +62,11 @@ private:
srslte::log_filter* log; srslte::log_filter* log;
}; };
class phy_dummy : public phy_interface_mac class phy_dummy : public phy_interface_mac_lte
{ {
public: public:
phy_dummy() : scell_cmd(0){}; phy_dummy() : scell_cmd(0){};
// phy_interface_mac // phy_interface_mac_lte
void configure_prach_params(){}; void configure_prach_params(){};
virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm){}; virtual void prach_send(uint32_t preamble_idx, int allowed_subframe, float target_power_dbm){};
prach_info_t prach_get_info() prach_info_t prach_get_info()
@ -144,8 +144,8 @@ int mac_unpack_test()
mac.init(&phy, &rlc, &rrc, &mac_log); mac.init(&phy, &rlc, &rrc, &mac_log);
// create dummy DL action and grant and push MAC PDU // create dummy DL action and grant and push MAC PDU
mac_interface_phy::tb_action_dl_t dl_action; mac_interface_phy_lte::tb_action_dl_t dl_action;
mac_interface_phy::mac_grant_dl_t mac_grant; mac_interface_phy_lte::mac_grant_dl_t mac_grant;
bzero(&dl_action, sizeof(dl_action)); bzero(&dl_action, sizeof(dl_action));
bzero(&mac_grant, sizeof(mac_grant)); bzero(&mac_grant, sizeof(mac_grant));
mac_grant.rnti = 0xbeaf; mac_grant.rnti = 0xbeaf;

@ -40,27 +40,24 @@ char *csv_file_name = NULL;
class ue_dummy : public ue_metrics_interface class ue_dummy : public ue_metrics_interface
{ {
public: public:
bool get_metrics(ue_metrics_t &m) bool get_metrics(ue_metrics_t* m)
{ {
// fill dummy values // fill dummy values
bzero(&m, sizeof(ue_metrics_t)); bzero(m, sizeof(ue_metrics_t));
m.rf.rf_o = 10; m->rf.rf_o = 10;
m.phy.nof_active_cc = 2; m->phy.nof_active_cc = 2;
m.phy.dl[0].rsrp = -10.0f; m->phy.dl[0].rsrp = -10.0f;
m.phy.dl[0].pathloss = 74; m->phy.dl[0].pathloss = 74;
m.mac[0].rx_pkts = 100; m->stack.mac[0].rx_pkts = 100;
m.mac[0].rx_errors = 0; m->stack.mac[0].rx_errors = 0;
m.mac[1].rx_pkts = 100; m->stack.mac[1].rx_pkts = 100;
m.mac[1].rx_errors = 100; m->stack.mac[1].rx_errors = 100;
return true; return true;
} }
bool is_attached() bool is_rrc_connected() { return (rand() % 2 == 0); }
{
return (rand() % 2 == 0);
}
}; };
} }

@ -25,12 +25,12 @@
#include "srslte/upper/pdcp.h" #include "srslte/upper/pdcp.h"
#include "srslte/upper/pdcp_entity.h" #include "srslte/upper/pdcp_entity.h"
#include "srslte/upper/rlc.h" #include "srslte/upper/rlc.h"
#include "srsue/hdr/mac/mac.h" #include "srsue/hdr/stack/mac/mac.h"
#include "srsue/hdr/rrc/rrc.h" #include "srsue/hdr/stack/rrc/rrc.h"
#include "srsue/hdr/upper/gw.h" #include "srsue/hdr/stack/upper/gw.h"
#include "srsue/hdr/upper/nas.h" #include "srsue/hdr/stack/upper/nas.h"
#include "srsue/hdr/upper/usim.h" #include "srsue/hdr/stack/upper/usim.h"
#include "srsue/hdr/upper/usim_base.h" #include "srsue/hdr/stack/upper/usim_base.h"
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
@ -235,9 +235,9 @@ int mme_attach_request_test()
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg); nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
srslte_gw_config_t gw_config(3); gw_args_t gw_args;
gw.init(&pdcp_dummy, &nas, &gw_log, gw_config); gw_args.tun_dev_name = "tun0";
gw.set_tundevname("tun0"); gw.init(&pdcp_dummy, &nas, &gw_log, gw_args);
// trigger test // trigger test
nas.attach_request(); nas.attach_request();

@ -22,8 +22,8 @@
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
#include "srsue/hdr/upper/pcsc_usim.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srsue/hdr/stack/upper/pcsc_usim.h"
using namespace srsue; using namespace srsue;
using namespace std; using namespace std;

@ -19,10 +19,10 @@
* *
*/ */
#include <iostream>
#include "srsue/hdr/upper/usim.h"
#include "srslte/common/log_filter.h" #include "srslte/common/log_filter.h"
#include "srsue/hdr/stack/upper/usim.h"
#include <assert.h> #include <assert.h>
#include <iostream>
using namespace srsue; using namespace srsue;

@ -1,5 +1,18 @@
##################################################################### #####################################################################
# srsUE configuration file # srsUE configuration file
#####################################################################
#
# General UE configuration
#
# radio: Type of radio object to be used (multi)
# phy: Type of L1 object to be used (lte_soft)
# stack: Type of L2/L3 stack to be used (lte)
#####################################################################
[ue]
#radio = multi
#phy = lte_soft
#stack = lte
##################################################################### #####################################################################
# RF configuration # RF configuration
# #
@ -75,7 +88,7 @@ nas_filename = /tmp/nas.pcap
# configured. # configured.
# Format: e.g. phy_hex_limit = 32 # Format: e.g. phy_hex_limit = 32
# #
# Logging layers: phy, mac, rlc, pdcp, rrc, nas, gw, usim, all # Logging layers: rf, phy, mac, rlc, pdcp, rrc, nas, gw, usim, all
# Logging levels: debug, info, warning, error, none # Logging levels: debug, info, warning, error, none
# #
# filename: File path to use for log output. Can be set to stdout # filename: File path to use for log output. Can be set to stdout
@ -153,16 +166,22 @@ imei = 353490069873319
#eia = 1,2 #eia = 1,2
#eea = 0,1,2 #eea = 0,1,2
#####################################################################
# GW configuration
#
# tun_dev_name: Name of the tun_srsue device. Default: tun_srsue
# tun_dev_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0
#####################################################################
[gw]
#tun_dev_name = tun_srsue
#tun_dev_netmask = 255.255.255.0
[gui] [gui]
enable = false enable = false
##################################################################### #####################################################################
# Expert configuration options # Expert configuration options
# #
# ip_netmask: Netmask of the tun_srsue device. Default: 255.255.255.0
# ip_devname: Nanme of the tun_srsue device. Default: tun_srsue
# rssi_sensor_enabled: Enable or disable RF frontend RSSI sensor. Required for RSRP metrics but
# can cause UHD instability for long-duration testing. Default true.
# rx_gain_offset: RX Gain offset to add to rx_gain to calibrate RSRP readings # rx_gain_offset: RX Gain offset to add to rx_gain to calibrate RSRP readings
# prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only., # prach_gain: PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only.,
# Default is to use tx_gain in [rf] section. # Default is to use tx_gain in [rf] section.

Loading…
Cancel
Save