Backport some changes from FAPI branch (#2124)

* Reorder DCI FORMAT enum

* Fix endianness issue

* Fix return codes in phy_ue_db

* Log members should be destructed after the layers.

* Add JSON metrics and Events. Add Alarm log channel. Simplify MAC metrics struct.

* Restore metrics_stdout change
This commit is contained in:
Ismael Gomez 2020-12-16 13:48:48 +01:00 committed by GitHub
parent ea36e46635
commit 0498439d41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 545 additions and 37 deletions

View File

@ -0,0 +1,70 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSENB_ENB_EVENTS_H
#define SRSENB_ENB_EVENTS_H
#include <cstdint>
#include <memory>
namespace srslog {
class log_channel;
}
namespace srsenb {
/// This interface logs different kinds of events to the configured channel. By default, if no log channel is configured
/// logging will be disabled.
class event_logger_interface
{
public:
virtual ~event_logger_interface() = default;
/// Logs into the underlying log channel the RRC connected event.
virtual void log_rrc_connected(unsigned cause) = 0;
/// Logs into the underlying log channel the RRC disconnected event.
virtual void log_rrc_disconnect(unsigned reason) = 0;
/// Logs into the underlying log channel the S1 context create event.
virtual void log_s1_ctx_create(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) = 0;
/// Logs into the underlying log channel the S1 context delete event.
virtual void log_s1_ctx_delete(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) = 0;
/// Logs into the underlying log channel the when a sector has been started.
virtual void log_sector_start(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) = 0;
/// Logs into the underlying log channel the when a sector has been stopped.
virtual void log_sector_stop(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) = 0;
};
/// Singleton class to provide global access to the event_logger_interface interface.
class event_logger
{
event_logger() = default;
public:
/// Returns the instance of the event logger.
static event_logger_interface& get();
/// Uses the specified log channel for event logging.
/// NOTE: This method is not thread safe.
static void configure(srslog::log_channel& c);
private:
static std::unique_ptr<event_logger_interface> pimpl;
};
} // namespace srsenb
#endif // SRSENB_ENB_EVENTS_H

View File

@ -284,8 +284,8 @@ typedef enum {
SRSLTE_DCI_FORMAT0 = 0,
SRSLTE_DCI_FORMAT1,
SRSLTE_DCI_FORMAT1A,
SRSLTE_DCI_FORMAT1C,
SRSLTE_DCI_FORMAT1B,
SRSLTE_DCI_FORMAT1C,
SRSLTE_DCI_FORMAT1D,
SRSLTE_DCI_FORMAT2,
SRSLTE_DCI_FORMAT2A,

View File

@ -8,6 +8,7 @@
set(SOURCES arch_select.cc
enb_events.cc
backtrace.c
buffer_pool.cc
crash_handler.c

View File

@ -0,0 +1,150 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/common/enb_events.h"
#include "srslte/srslog/context.h"
#include "srslte/srslog/log_channel.h"
using namespace srsenb;
namespace {
/// Null object implementation that is used when no log channel is configured.
class null_event_logger : public event_logger_interface
{
public:
void log_rrc_connected(unsigned cause) override {}
void log_rrc_disconnect(unsigned reason) override {}
void log_s1_ctx_create(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override {}
void log_s1_ctx_delete(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override {}
void log_sector_start(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override {}
void log_sector_stop(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override {}
};
} // namespace
namespace {
/// Common metrics to all events.
DECLARE_METRIC("type", metric_type_tag, std::string, "");
DECLARE_METRIC("event_name", metric_event_name, std::string, "");
/// Context for sector start/stop.
DECLARE_METRIC("pci", metric_pci, uint32_t, "");
DECLARE_METRIC("cell_identity", metric_cell_identity, uint32_t, "");
DECLARE_METRIC("sector_id", metric_sector_id, uint32_t, "");
DECLARE_METRIC_SET("event_data", mset_sector_event, metric_pci, metric_cell_identity, metric_sector_id);
using sector_event_t = srslog::build_context_type<metric_type_tag, metric_event_name, mset_sector_event>;
/// Context for RRC connect/disconnect.
DECLARE_METRIC("cause", metric_cause, uint32_t, "");
DECLARE_METRIC_SET("event_data", mset_rrc_event, metric_cause);
using rrc_event_t = srslog::build_context_type<metric_type_tag, metric_event_name, mset_rrc_event>;
/// Context for S1 context create/delete.
DECLARE_METRIC("mme_ue_s1ap_id", metric_ue_mme_id, uint32_t, "");
DECLARE_METRIC("enb_ue_s1ap_id", metric_ue_enb_id, uint32_t, "");
DECLARE_METRIC("rnti", metric_rnti, uint16_t, "");
DECLARE_METRIC_SET("event_data", mset_s1apctx_event, metric_ue_mme_id, metric_ue_enb_id, metric_rnti);
using s1apctx_event_t = srslog::build_context_type<metric_type_tag, metric_event_name, mset_s1apctx_event>;
/// Logs events into the configured log channel.
class logging_event_logger : public event_logger_interface
{
public:
explicit logging_event_logger(srslog::log_channel& c) : event_channel(c) {}
void log_rrc_connected(unsigned cause) override
{
rrc_event_t ctx("");
ctx.write<metric_type_tag>("event");
ctx.write<metric_event_name>("rrc_connect");
ctx.get<mset_rrc_event>().write<metric_cause>(cause);
event_channel(ctx);
}
void log_rrc_disconnect(unsigned reason) override
{
rrc_event_t ctx("");
ctx.write<metric_type_tag>("event");
ctx.write<metric_event_name>("rrc_disconnect");
ctx.get<mset_rrc_event>().write<metric_cause>(reason);
event_channel(ctx);
}
void log_s1_ctx_create(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override
{
s1apctx_event_t ctx("");
ctx.write<metric_type_tag>("event");
ctx.write<metric_event_name>("s1_context_create");
ctx.get<mset_s1apctx_event>().write<metric_ue_mme_id>(mme_id);
ctx.get<mset_s1apctx_event>().write<metric_ue_enb_id>(enb_id);
ctx.get<mset_s1apctx_event>().write<metric_rnti>(rnti);
event_channel(ctx);
}
void log_s1_ctx_delete(uint32_t mme_id, uint32_t enb_id, uint16_t rnti) override
{
s1apctx_event_t ctx("");
ctx.write<metric_type_tag>("event");
ctx.write<metric_event_name>("s1_context_delete");
ctx.get<mset_s1apctx_event>().write<metric_ue_mme_id>(mme_id);
ctx.get<mset_s1apctx_event>().write<metric_ue_enb_id>(enb_id);
ctx.get<mset_s1apctx_event>().write<metric_rnti>(rnti);
event_channel(ctx);
}
void log_sector_start(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override
{
sector_event_t ctx("");
ctx.write<metric_type_tag>("event");
ctx.write<metric_event_name>("sector_start");
ctx.get<mset_sector_event>().write<metric_pci>(pci);
ctx.get<mset_sector_event>().write<metric_cell_identity>(cell_id);
ctx.get<mset_sector_event>().write<metric_sector_id>(cc_idx);
event_channel(ctx);
}
void log_sector_stop(uint32_t cc_idx, uint32_t pci, uint32_t cell_id) override
{
sector_event_t ctx("");
ctx.write<metric_type_tag>("event");
ctx.write<metric_event_name>("sector_stop");
ctx.get<mset_sector_event>().write<metric_pci>(pci);
ctx.get<mset_sector_event>().write<metric_cell_identity>(cell_id);
ctx.get<mset_sector_event>().write<metric_sector_id>(cc_idx);
event_channel(ctx);
}
private:
srslog::log_channel& event_channel;
};
} // namespace
std::unique_ptr<event_logger_interface> event_logger::pimpl = std::unique_ptr<null_event_logger>(new null_event_logger);
event_logger_interface& event_logger::get()
{
return *pimpl;
}
void event_logger::configure(srslog::log_channel& c)
{
pimpl = std::unique_ptr<logging_event_logger>(new logging_event_logger(c));
}

View File

@ -565,13 +565,13 @@ bool sch_subh::is_var_len_ce()
uint16_t sch_subh::get_c_rnti()
{
return (uint16_t)payload[0] << 8 | payload[1];
return le16toh((uint16_t)payload[0] << 8 | payload[1]);
}
uint64_t sch_subh::get_con_res_id()
{
return ((uint64_t)payload[5]) | (((uint64_t)payload[4]) << 8) | (((uint64_t)payload[3]) << 16) |
(((uint64_t)payload[2]) << 24) | (((uint64_t)payload[1]) << 32) | (((uint64_t)payload[0]) << 40);
return le64toh(((uint64_t)payload[5]) | (((uint64_t)payload[4]) << 8) | (((uint64_t)payload[3]) << 16) |
(((uint64_t)payload[2]) << 24) | (((uint64_t)payload[1]) << 32) | (((uint64_t)payload[0]) << 40));
}
float sch_subh::get_phr()
@ -711,6 +711,7 @@ bool sch_subh::set_bsr(uint32_t buff_size[4], ul_sch_lcid format)
bool sch_subh::set_c_rnti(uint16_t crnti)
{
crnti = htole32(crnti);
if (((sch_pdu*)parent)->has_space_ce(2)) {
w_payload_ce[0] = (uint8_t)((crnti & 0xff00) >> 8);
w_payload_ce[1] = (uint8_t)((crnti & 0x00ff));
@ -724,6 +725,7 @@ bool sch_subh::set_c_rnti(uint16_t crnti)
}
bool sch_subh::set_con_res_id(uint64_t con_res_id)
{
con_res_id = htole64(con_res_id);
if (((sch_pdu*)parent)->has_space_ce(6)) {
w_payload_ce[0] = (uint8_t)((con_res_id & 0xff0000000000) >> 40);
w_payload_ce[1] = (uint8_t)((con_res_id & 0x00ff00000000) >> 32);

View File

@ -294,6 +294,10 @@ enable = false
#metrics_period_secs = 1
#metrics_csv_enable = false
#metrics_csv_filename = /tmp/enb_metrics.csv
#report_json_enable = true
#report_json_filename = /tmp/enb_report.json
#alarms_log_enable = true
#alarms_filename = /tmp/enb_alarms.log
#pregenerate_signals = false
#tx_amplitude = 0.6
#rrc_inactivity_timer = 30000

View File

@ -29,6 +29,7 @@
#include "srsenb/hdr/phy/enb_phy_base.h"
#include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsenb/hdr/stack/rrc/rrc_config.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/buffer_pool.h"
@ -81,6 +82,10 @@ struct general_args_t {
float metrics_period_secs;
bool metrics_csv_enable;
std::string metrics_csv_filename;
bool report_json_enable;
std::string report_json_filename;
bool alarms_log_enable;
std::string alarms_filename;
bool print_buffer_state;
std::string eia_pref_list;
std::string eea_pref_list;
@ -129,11 +134,6 @@ private:
int parse_args(const all_args_t& args_, rrc_cfg_t& rrc_cfg);
// eNB components
std::unique_ptr<enb_stack_base> stack;
std::unique_ptr<srslte::radio_base> radio;
std::unique_ptr<enb_phy_base> phy;
srslte::logger* logger = nullptr;
srslte::log_ref log; // Own logger for eNB
@ -145,6 +145,12 @@ private:
bool started = false;
phy_cfg_t phy_cfg = {};
rrc_cfg_t rrc_cfg = {};
// eNB components
std::unique_ptr<enb_stack_base> stack = nullptr;
std::unique_ptr<srslte::radio_base> radio = nullptr;
std::unique_ptr<enb_phy_base> phy = nullptr;
srslte::LOG_LEVEL_ENUM level(std::string l);

42
srsenb/hdr/metrics_json.h Normal file
View File

@ -0,0 +1,42 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
/******************************************************************************
* File: metrics_json.h
* Description: Metrics class printing to a json file.
*****************************************************************************/
#ifndef SRSENB_METRICS_JSON_H
#define SRSENB_METRICS_JSON_H
#include "srslte/interfaces/enb_metrics_interface.h"
#include "srslte/srslog/log_channel.h"
namespace srsenb {
class metrics_json : public srslte::metrics_listener<enb_metrics_t>
{
public:
metrics_json(srslog::log_channel& c) : log_c(c) {}
void set_metrics(const enb_metrics_t& m, const uint32_t period_usec) override;
void set_handle(enb_metrics_interface* enb_);
void stop() override {}
private:
srslog::log_channel& log_c;
enb_metrics_interface* enb;
};
} // namespace srsenb
#endif // SRSENB_METRICS_JSON_H

View File

@ -283,6 +283,14 @@ public:
*/
bool is_pcell(uint16_t rnti, uint32_t enb_cc_idx) const;
/**
* Asserts a given eNb cell is part of the given RNTI
* @param rnti identifier of the UE
* @param enb_cc_idx eNb cell/carrier index
* @return It returns true if the cell is part of the UE, othwerwise it returns false
*/
bool ue_has_cell(uint16_t rnti, uint32_t enb_cc_idx) const;
/**
* Get the current down-link physical layer configuration for an RNTI and an eNb cell/carrier
*
@ -330,7 +338,7 @@ public:
* @param dci carries the Transport Block and required scheduling information
*
*/
void set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_dci_dl_t& dci);
bool set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_dci_dl_t& dci);
/**
* Fills the Uplink Control Information (UCI) configuration and returns true/false idicating if UCI bits are required.
@ -339,14 +347,14 @@ public:
* @param rnti is the UE identifier
* @param aperiodic_cqi_request indicates if aperiodic CQI was requested
* @param uci_cfg brings the UCI configuration
* @return true if UCI decoding is required and false otherwise
* @return 1 if UCI decoding is required, 0 if not, -1 if error
*/
bool fill_uci_cfg(uint32_t tti,
uint32_t enb_cc_idx,
uint16_t rnti,
bool aperiodic_cqi_request,
bool is_pusch_available,
srslte_uci_cfg_t& uci_cfg);
int fill_uci_cfg(uint32_t tti,
uint32_t enb_cc_idx,
uint16_t rnti,
bool aperiodic_cqi_request,
bool is_pusch_available,
srslte_uci_cfg_t& uci_cfg);
/**
* Sends the decoded Uplink Control Information by PUCCH or PUSCH to MAC

View File

@ -23,7 +23,7 @@ endif (RPATH)
add_library(enb_cfg_parser STATIC parser.cc enb_cfg_parser.cc)
target_link_libraries(enb_cfg_parser ${LIBCONFIGPP_LIBRARIES})
add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc)
add_executable(srsenb main.cc enb.cc metrics_stdout.cc metrics_csv.cc metrics_json.cc)
set(SRSENB_SOURCES srsenb_phy srsenb_stack srsenb_upper srsenb_mac srsenb_rrc srslog)
set(SRSLTE_SOURCES srslte_common srslte_mac srslte_phy srslte_upper srslte_radio rrc_asn1 s1ap_asn1 enb_cfg_parser srslog)

View File

@ -14,6 +14,7 @@
#include "srsenb/hdr/stack/enb_stack_lte.h"
#include "srsenb/src/enb_cfg_parser.h"
#include "srslte/build_info.h"
#include "srslte/common/enb_events.h"
#include "srslte/radio/radio_null.h"
#ifdef HAVE_5GNR
#include "srsenb/hdr/phy/vnf_phy_nr.h"
@ -46,7 +47,6 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_)
log->info("%s", get_build_string().c_str());
// Validate arguments
rrc_cfg_t rrc_cfg = {};
if (parse_args(args_, rrc_cfg)) {
srslte::console("Error processing arguments.\n");
return SRSLTE_ERROR;
@ -145,6 +145,11 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_)
started = true; // set to true in any case to allow stopping the eNB if an error happened
// Now that everything is setup, log sector start events.
for (unsigned i = 0, e = rrc_cfg.cell_list.size(); i != e; ++i) {
event_logger::get().log_sector_start(i, rrc_cfg.cell_list[i].pci, rrc_cfg.cell_list[i].cell_id);
}
if (ret == SRSLTE_SUCCESS) {
srslte::console("\n==== eNodeB started ===\n");
srslte::console("Type <t> to view trace\n");
@ -152,6 +157,7 @@ int enb::init(const all_args_t& args_, srslte::logger* logger_)
// if any of the layers failed to start, make sure the rest is stopped in a controlled manner
stop();
}
return ret;
}
@ -171,15 +177,20 @@ void enb::stop()
radio->stop();
}
// Now that everything is teared down, log sector stop events.
for (unsigned i = 0, e = rrc_cfg.cell_list.size(); i != e; ++i) {
event_logger::get().log_sector_stop(i, rrc_cfg.cell_list[i].pci, rrc_cfg.cell_list[i].cell_id);
}
started = false;
}
}
int enb::parse_args(const all_args_t& args_, rrc_cfg_t& rrc_cfg)
int enb::parse_args(const all_args_t& args_, rrc_cfg_t& _rrc_cfg)
{
// set member variable
args = args_;
return enb_conf_sections::parse_cfg_files(&args, &rrc_cfg, &phy_cfg);
return enb_conf_sections::parse_cfg_files(&args, &_rrc_cfg, &phy_cfg);
}
void enb::start_plot()

View File

@ -32,7 +32,9 @@
#include "srsenb/hdr/enb.h"
#include "srsenb/hdr/metrics_csv.h"
#include "srsenb/hdr/metrics_json.h"
#include "srsenb/hdr/metrics_stdout.h"
#include "srslte/common/enb_events.h"
using namespace std;
using namespace srsenb;
@ -191,6 +193,10 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("expert.equalizer_mode", bpo::value<string>(&args->phy.equalizer_mode)->default_value("mmse"), "Equalizer mode")
("expert.estimator_fil_w", bpo::value<float>(&args->phy.estimator_fil_w)->default_value(0.1), "Chooses the coefficients for the 3-tap channel estimator centered filter.")
("expert.lte_sample_rates", bpo::value<bool>(&use_standard_lte_rates)->default_value(false), "Whether to use default LTE sample rates instead of shorter variants.")
("expert.report_json_enable", bpo::value<bool>(&args->general.report_json_enable)->default_value(true), "Write eNB report to JSON file")
("expert.report_json_filename", bpo::value<string>(&args->general.report_json_filename)->default_value("/tmp/enb_report.json"), "Report JSON filename")
("expert.alarms_log_enable", bpo::value<bool>(&args->general.alarms_log_enable)->default_value(true), "Log alarms")
("expert.alarms_filename", bpo::value<string>(&args->general.alarms_filename)->default_value("/tmp/enb_alarms.log"), "Alarms filename")
("expert.rrc_inactivity_timer", bpo::value<uint32_t>(&args->general.rrc_inactivity_timer)->default_value(30000), "Inactivity timer in ms.")
("expert.print_buffer_state", bpo::value<bool>(&args->general.print_buffer_state)->default_value(false), "Prints on the console the buffer state every 10 seconds")
("expert.eea_pref_list", bpo::value<string>(&args->general.eea_pref_list)->default_value("EEA0, EEA2, EEA1"), "Ordered preference list for the selection of encryption algorithm (EEA) (default: EEA0, EEA2, EEA1).")
@ -478,6 +484,11 @@ int main(int argc, char* argv[])
}
srslte::srslog_wrapper log_wrapper(*chan);
// Alarms log channel creation.
srslog::sink& alarm_sink = srslog::fetch_file_sink(args.general.alarms_filename);
srslog::log_channel& alarms_channel = srslog::fetch_log_channel("alarms", alarm_sink, {"ALRM", '\0', false});
alarms_channel.set_enabled(args.general.alarms_log_enable);
// Start the log backend.
srslog::init();
@ -487,6 +498,17 @@ int main(int argc, char* argv[])
srslte::check_scaling_governor(args.rf.device_name);
// Set up the JSON log channel used by metrics and events.
srslog::sink& json_sink =
srslog::fetch_file_sink(args.general.report_json_filename, 0, srslog::create_json_formatter());
srslog::log_channel& json_channel = srslog::fetch_log_channel("JSON_channel", json_sink, {});
json_channel.set_enabled(args.general.report_json_enable);
// Configure the event logger just before starting the eNB class.
if (args.general.report_json_enable) {
event_logger::configure(json_channel);
}
// Create eNB
unique_ptr<srsenb::enb> enb{new srsenb::enb};
if (enb->init(args, &log_wrapper) != SRSLTE_SUCCESS) {
@ -505,6 +527,12 @@ int main(int argc, char* argv[])
metrics_file.set_handle(enb.get());
}
srsenb::metrics_json json_metrics(json_channel);
if (args.general.report_json_enable) {
metricshub.add_listener(&json_metrics);
json_metrics.set_handle(enb.get());
}
// create input thread
std::thread input(&input_loop, &metrics_screen, (enb_command_interface*)enb.get());

166
srsenb/src/metrics_json.cc Normal file
View File

@ -0,0 +1,166 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srsenb/hdr/metrics_json.h"
#include "srslte/srslog/context.h"
using namespace srsenb;
void metrics_json::set_handle(enb_metrics_interface* enb_)
{
enb = enb_;
}
namespace {
/// Bearer container metrics.
DECLARE_METRIC("bearer_id", metric_bearer_id, uint32_t, "");
DECLARE_METRIC("qci", metric_qci, uint32_t, "");
DECLARE_METRIC_SET("bearer_container", mset_bearer_container, metric_bearer_id, metric_qci);
/// UE container metrics.
DECLARE_METRIC("ue_rnti", metric_ue_rnti, uint32_t, "");
DECLARE_METRIC("dl_cqi", metric_dl_cqi, float, "");
DECLARE_METRIC("dl_mcs", metric_dl_mcs, float, "");
DECLARE_METRIC("dl_bitrate", metric_dl_bitrate, float, "");
DECLARE_METRIC("dl_bler", metric_dl_bler, float, "");
DECLARE_METRIC("ul_snr", metric_ul_snr, float, "");
DECLARE_METRIC("ul_mcs", metric_ul_mcs, float, "");
DECLARE_METRIC("ul_bitrate", metric_ul_bitrate, float, "");
DECLARE_METRIC("ul_bler", metric_ul_bler, float, "");
DECLARE_METRIC("ul_phr", metric_ul_phr, float, "");
DECLARE_METRIC("bsr", metric_bsr, int, "");
DECLARE_METRIC_LIST("bearer_list", mlist_bearers, std::vector<mset_bearer_container>);
DECLARE_METRIC_SET("ue_container",
mset_ue_container,
metric_ue_rnti,
metric_dl_cqi,
metric_dl_mcs,
metric_dl_bitrate,
metric_dl_bler,
metric_ul_snr,
metric_ul_mcs,
metric_ul_bitrate,
metric_ul_bler,
metric_ul_phr,
metric_bsr,
mlist_bearers);
/// Sector container metrics.
DECLARE_METRIC("sector_id", metric_sector_id, uint32_t, "");
DECLARE_METRIC("sector_rach", metric_sector_rach, uint32_t, "");
DECLARE_METRIC_LIST("ue_list", mlist_ues, std::vector<mset_ue_container>);
DECLARE_METRIC_SET("sector_container", mset_sector_container, metric_sector_id, metric_sector_rach, mlist_ues);
/// Metrics root object.
DECLARE_METRIC("type", metric_type_tag, std::string, "");
DECLARE_METRIC_LIST("sector_list", mlist_sector, std::vector<mset_sector_container>);
/// Metrics context.
using metric_context_t = srslog::build_context_type<metric_type_tag, mlist_sector>;
} // namespace
/// Fill the metrics for the i'th UE in the enb metrics struct.
static void fill_ue_metrics(mset_ue_container& ue, const enb_metrics_t& m, unsigned i)
{
ue.write<metric_ue_rnti>(m.stack.mac.ues[i].rnti);
ue.write<metric_dl_cqi>(std::max(0.1f, m.stack.mac.ues[i].dl_cqi));
if (!std::isnan(m.phy[i].dl.mcs)) {
ue.write<metric_dl_mcs>(std::max(0.1f, m.phy[i].dl.mcs));
}
if (m.stack.mac.ues[i].tx_brate > 0) {
ue.write<metric_dl_bitrate>(
std::max(0.1f, (float)m.stack.mac.ues[i].tx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f)));
}
if (m.stack.mac.ues[i].tx_pkts > 0 && m.stack.mac.ues[i].tx_errors > 0) {
ue.write<metric_dl_bler>(std::max(0.1f, (float)100 * m.stack.mac.ues[i].tx_errors / m.stack.mac.ues[i].tx_pkts));
}
if (!std::isnan(m.phy[i].ul.sinr)) {
ue.write<metric_ul_snr>(std::max(0.1f, m.phy[i].ul.sinr));
}
if (!std::isnan(m.phy[i].ul.mcs)) {
ue.write<metric_ul_mcs>(std::max(0.1f, m.phy[i].ul.mcs));
}
if (m.stack.mac.ues[i].rx_brate > 0) {
ue.write<metric_ul_bitrate>(
std::max(0.1f, (float)m.stack.mac.ues[i].rx_brate / (m.stack.mac.ues[i].nof_tti * 0.001f)));
}
if (m.stack.mac.ues[i].rx_pkts > 0 && m.stack.mac.ues[i].rx_errors > 0) {
ue.write<metric_ul_bler>(std::max(0.1f, (float)100 * m.stack.mac.ues[i].rx_errors / m.stack.mac.ues[i].rx_pkts));
}
ue.write<metric_ul_phr>(m.stack.mac.ues[i].phr);
ue.write<metric_bsr>(m.stack.mac.ues[i].ul_buffer);
// For each data bearer of this UE...
auto& bearer_list = ue.get<mlist_bearers>();
for (const auto& drb : m.stack.rrc.ues[i].drb_qci_map) {
bearer_list.emplace_back();
auto& bearer_container = bearer_list.back();
bearer_container.write<metric_bearer_id>(drb.first);
bearer_container.write<metric_qci>(drb.second);
}
}
/// Returns false if the input index is out of bounds in the metrics struct.
static bool has_valid_metric_ranges(const enb_metrics_t& m, unsigned index)
{
if (index >= m.phy.size()) {
return false;
}
if (index >= m.stack.mac.ues.size()) {
return false;
}
return true;
}
void metrics_json::set_metrics(const enb_metrics_t& m, const uint32_t period_usec)
{
if (!enb) {
return;
}
if (m.stack.mac.cc_rach_counter.empty()) {
return;
}
metric_context_t ctx("JSON Metrics");
// Fill root object.
ctx.write<metric_type_tag>("metrics");
auto& sector_list = ctx.get<mlist_sector>();
sector_list.resize(m.stack.mac.cc_rach_counter.size());
// For each sector...
for (unsigned cc_idx = 0, e = sector_list.size(); cc_idx != e; ++cc_idx) {
auto& sector = sector_list[cc_idx];
sector.write<metric_sector_id>(cc_idx);
sector.write<metric_sector_rach>(m.stack.mac.cc_rach_counter[cc_idx]);
// For each UE in this sector...
for (unsigned i = 0; i != m.stack.rrc.ues.size(); ++i) {
if (!has_valid_metric_ranges(m, i)) {
continue;
}
// Only record UEs that belong to this sector.
if (m.stack.mac.ues[i].cc_idx != cc_idx) {
continue;
}
sector.get<mlist_ues>().emplace_back();
fill_ue_metrics(sector.get<mlist_ues>().back(), m, i);
}
}
// Log the context.
log_c(ctx);
}

View File

@ -390,6 +390,11 @@ void phy_ue_db::activate_deactivate_scell(uint16_t rnti, uint32_t ue_cc_idx, boo
cell_info.state = (activate) ? cell_state_secondary_active : cell_state_secondary_inactive;
}
bool phy_ue_db::ue_has_cell(uint16_t rnti, uint32_t enb_cc_idx) const
{
return _assert_enb_cc(rnti, enb_cc_idx) == SRSLTE_SUCCESS;
}
bool phy_ue_db::is_pcell(uint16_t rnti, uint32_t enb_cc_idx) const
{
std::lock_guard<std::mutex> lock(mutex);
@ -440,16 +445,16 @@ srslte_dci_cfg_t phy_ue_db::get_dci_ul_config(uint16_t rnti, uint32_t enb_cc_idx
return _get_rnti_config(rnti, enb_cc_idx).dl_cfg.dci;
}
void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_dci_dl_t& dci)
bool phy_ue_db::set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_dci_dl_t& dci)
{
std::lock_guard<std::mutex> lock(mutex);
// Assert rnti and cell exits and it is active
if (_assert_active_enb_cc(dci.rnti, enb_cc_idx) != SRSLTE_SUCCESS) {
return;
return false;
}
common_ue& ue = ue_db[dci.rnti];
common_ue& ue = ue_db.at(dci.rnti);
uint32_t ue_cc_idx = _get_ue_cc_idx(dci.rnti, enb_cc_idx);
srslte_pdsch_ack_cc_t& pdsch_ack_cc = ue.pdsch_ack[tti].cc[ue_cc_idx];
@ -473,14 +478,15 @@ void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_
pdsch_ack_m.value[tb_idx] = 2;
}
}
return true;
}
bool phy_ue_db::fill_uci_cfg(uint32_t tti,
uint32_t enb_cc_idx,
uint16_t rnti,
bool aperiodic_cqi_request,
bool is_pusch_available,
srslte_uci_cfg_t& uci_cfg)
int phy_ue_db::fill_uci_cfg(uint32_t tti,
uint32_t enb_cc_idx,
uint16_t rnti,
bool aperiodic_cqi_request,
bool is_pusch_available,
srslte_uci_cfg_t& uci_cfg)
{
std::lock_guard<std::mutex> lock(mutex);
@ -489,12 +495,12 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti,
// Assert Cell List configuration
if (_assert_cell_list_cfg() != SRSLTE_SUCCESS) {
return false;
return -1;
}
// Assert eNb Cell/Carrier for the given RNTI
if (_assert_active_enb_cc(rnti, enb_cc_idx) != SRSLTE_SUCCESS) {
return false;
return -1;
}
// Get the eNb cell/carrier index with lowest serving cell index (ue_cc_idx) that has an available grant.
@ -503,17 +509,17 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti,
// There is a PUSCH grant available for the provided RNTI in at least one serving cell and this call is for PUCCH
if (pusch_grant_available and not is_pusch_available) {
return false;
return 0;
}
// There is a PUSCH grant and enb_cc_idx with lowest ue_cc_idx with a grant
if (pusch_grant_available and uci_enb_cc_id != enb_cc_idx) {
return false;
return 0;
}
// No PUSCH grant for this TTI and cell and no enb_cc_idx is not the PCell
if (not pusch_grant_available and _get_ue_cc_idx(rnti, enb_cc_idx) != 0) {
return false;
return 0;
}
common_ue& ue = ue_db.at(rnti);
@ -564,7 +570,7 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti,
uci_required |= (srslte_uci_cfg_total_ack(&uci_cfg) > 0);
// Return whether UCI needs to be decoded
return uci_required;
return uci_required ? 1 : 0;
}
void phy_ue_db::send_uci_data(uint32_t tti,

View File

@ -15,6 +15,7 @@
#include "srsenb/hdr/stack/rrc/rrc_mobility.h"
#include "srsenb/hdr/stack/rrc/ue_rr_cfg.h"
#include "srslte/asn1/rrc_utils.h"
#include "srslte/common/enb_events.h"
#include "srslte/common/int_helpers.h"
using namespace asn1::rrc;
@ -305,6 +306,9 @@ void rrc::ue::handle_rrc_con_setup_complete(rrc_conn_setup_complete_s* msg, srsl
parent->s1ap->initial_ue(rnti, s1ap_cause, std::move(pdu));
}
state = RRC_STATE_WAIT_FOR_CON_RECONF_COMPLETE;
// Log event.
event_logger::get().log_rrc_connected(static_cast<unsigned>(s1ap_cause.value));
}
void rrc::ue::send_connection_reject()
@ -642,6 +646,9 @@ void rrc::ue::send_connection_release()
}
send_dl_dcch(&dl_dcch_msg);
// Log rrc release event.
event_logger::get().log_rrc_disconnect(static_cast<unsigned>(rel_ies.release_cause));
}
/*

View File

@ -14,6 +14,7 @@
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srslte/adt/scope_exit.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/enb_events.h"
#include "srslte/common/int_helpers.h"
#include "srslte/common/logmap.h"
@ -1115,6 +1116,9 @@ bool s1ap::ue::send_uectxtreleasecomplete()
container.enb_ue_s1ap_id.value = ctxt.enb_ue_s1ap_id;
container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id;
// Log event.
event_logger::get().log_s1_ctx_delete(ctxt.mme_ue_s1ap_id, ctxt.enb_ue_s1ap_id, ctxt.rnti);
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "UEContextReleaseComplete");
}
@ -1146,6 +1150,9 @@ bool s1ap::ue::send_initial_ctxt_setup_response(const asn1::s1ap::init_context_s
}
}
// Log event.
event_logger::get().log_s1_ctx_create(ctxt.mme_ue_s1ap_id, ctxt.enb_ue_s1ap_id, ctxt.rnti);
return s1ap_ptr->sctp_send_s1ap_pdu(tx_pdu, ctxt.rnti, "InitialContextSetupResponse");
}

View File

@ -1288,7 +1288,7 @@ public:
radio = unique_dummy_radio_t(
new dummy_radio(args.nof_enb_cells * args.cell.nof_ports, args.cell.nof_prb, args.log_level));
/// Create Dummy Stack isntance
/// Create Dummy Stack instance
stack = unique_dummy_stack_t(new dummy_stack(phy_cfg, phy_rrc_cfg, args.log_level, args.rnti));
stack->set_active_cell_list(args.ue_cell_list);