add srsenb::rrc class

master
Francisco Paisana 5 years ago
parent 0916e29de4
commit 613003ac53

@ -16590,8 +16590,7 @@ struct rlc_cfg_v1510_s {
// RLC-Config-v1530 ::= CHOICE
struct rlc_cfg_v1530_c {
struct setup_s_ {
};
struct setup_s_ {};
typedef setup_e types;
// choice methods

@ -0,0 +1,55 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_RRC_NR_ASN1_UTILS_H
#define SRSLTE_RRC_NR_ASN1_UTILS_H
#include "srslte/interfaces/rrc_interface_types.h"
#include "srslte/interfaces/sched_interface.h"
/************************
* Forward declarations
***********************/
namespace asn1 {
namespace rrc_nr {
struct plmn_id_s;
struct sib1_s;
} // namespace rrc_nr
} // namespace asn1
/************************
* Conversion Helpers
***********************/
namespace srslte {
plmn_id_t make_plmn_id_t(const asn1::rrc_nr::plmn_id_s& asn1_type);
void to_asn1(asn1::rrc_nr::plmn_id_s* asn1_type, const plmn_id_t& cfg);
} // namespace srslte
namespace srsenb {
int set_sched_cell_cfg_sib1(srsenb::sched_interface::cell_cfg_t* sched_cfg, const asn1::rrc_nr::sib1_s& sib1);
}
#endif // SRSLTE_RRC_NR_ASN1_UTILS_H

@ -47,7 +47,7 @@ target_link_libraries(s1ap_asn1 asn1_utils srslte_common)
if (ENABLE_5GNR)
# RRC NR ASN1
add_library(rrc_nr_asn1 STATIC rrc_nr_asn1.cc)
add_library(rrc_nr_asn1 STATIC rrc_nr_asn1.cc rrc_nr_asn1_utils.cc)
target_compile_options(rrc_nr_asn1 PRIVATE "-Os")
target_link_libraries(rrc_nr_asn1 asn1_utils srslte_common)

@ -0,0 +1,88 @@
/*
* Copyright 2013-2020 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 "srslte/asn1/rrc_nr_asn1_utils.h"
#include "srslte/asn1/rrc_nr_asn1.h"
#include "srslte/config.h"
#include <algorithm>
namespace srslte {
/***************************
* PLMN ID
**************************/
bool plmn_is_valid(const asn1::rrc_nr::plmn_id_s& asn1_type)
{
return asn1_type.mcc_present and (asn1_type.mnc.size() == 3 or asn1_type.mnc.size() == 2);
}
plmn_id_t make_plmn_id_t(const asn1::rrc_nr::plmn_id_s& asn1_type)
{
if (not plmn_is_valid(asn1_type)) {
return {};
}
plmn_id_t plmn;
std::copy(&asn1_type.mcc[0], &asn1_type.mcc[3], &plmn.mcc[0]);
plmn.nof_mnc_digits = asn1_type.mnc.size();
std::copy(&asn1_type.mnc[0], &asn1_type.mnc[plmn.nof_mnc_digits], &plmn.mnc[0]);
return plmn;
}
void to_asn1(asn1::rrc_nr::plmn_id_s* asn1_type, const plmn_id_t& cfg)
{
asn1_type->mcc_present = true;
std::copy(&cfg.mcc[0], &cfg.mcc[3], &asn1_type->mcc[0]);
asn1_type->mnc.resize(cfg.nof_mnc_digits);
std::copy(&cfg.mnc[0], &cfg.mnc[cfg.nof_mnc_digits], &asn1_type->mnc[0]);
}
} // namespace srslte
namespace srsenb {
int set_sched_cell_cfg_sib1(srsenb::sched_interface::cell_cfg_t* sched_cfg, const asn1::rrc_nr::sib1_s& sib1)
{
bzero(sched_cfg, sizeof(srsenb::sched_interface::cell_cfg_t));
// set SIB1 and SIB2+ period
sched_cfg->sibs[0].period_rf = 16; // SIB1 is always 16 rf
for (uint32_t i = 0; i < sib1.si_sched_info.sched_info_list.size(); i++) {
sched_cfg->sibs[i + 1].period_rf = sib1.si_sched_info.sched_info_list[i].si_periodicity.to_number();
}
// si-WindowLength
sched_cfg->si_window_ms = sib1.si_sched_info.si_win_len.to_number();
// setup PRACH
if (not sib1.si_sched_info.si_request_cfg.rach_occasions_si_present) {
asn1::log_error("Expected RA Resp Win present\n");
return SRSLTE_ERROR;
}
sched_cfg->prach_rar_window = sib1.si_sched_info.si_request_cfg.rach_occasions_si.rach_cfg_si.ra_resp_win.to_number();
sched_cfg->prach_freq_offset = sib1.si_sched_info.si_request_cfg.rach_occasions_si.rach_cfg_si.msg1_freq_start;
sched_cfg->maxharq_msg3tx = sib1.si_sched_info.si_request_cfg.rach_occasions_si.rach_cfg_si.preamb_trans_max;
return SRSLTE_SUCCESS;
}
} // namespace srsenb

@ -56,7 +56,7 @@ public:
public:
field_enum_str(const char* name_,
T* store_ptr_,
const char (*value_str_)[20],
const char** value_str_,
uint32_t nof_items_,
bool* enabled_value_ = NULL)
{
@ -113,7 +113,7 @@ public:
private:
const char* name;
T* store_ptr;
const char (*value_str)[20];
const char** value_str;
uint32_t nof_items;
bool* enabled_value;
};

@ -22,6 +22,7 @@
#ifndef SRSLTE_RRC_CONFIG_H
#define SRSLTE_RRC_CONFIG_H
#include "rrc_config_common.h"
#include "srslte/asn1/rrc_asn1.h"
#include "srslte/common/security.h"
#include "srslte/interfaces/enb_rrc_interface_types.h"
@ -36,20 +37,6 @@ struct rrc_cfg_sr_t {
uint32_t nof_subframes;
};
enum rrc_cfg_cqi_mode_t { RRC_CFG_CQI_MODE_PERIODIC = 0, RRC_CFG_CQI_MODE_APERIODIC, RRC_CFG_CQI_MODE_N_ITEMS };
static const char rrc_cfg_cqi_mode_text[RRC_CFG_CQI_MODE_N_ITEMS][20] = {"periodic", "aperiodic"};
typedef struct {
uint32_t sf_mapping[80];
uint32_t nof_subframes;
uint32_t nof_prb;
uint32_t period;
uint32_t m_ri;
bool simultaneousAckCQI;
rrc_cfg_cqi_mode_t mode;
} rrc_cfg_cqi_t;
typedef struct {
bool configured;
asn1::rrc::lc_ch_cfg_s::ul_specific_params_s_ lc_cfg;

@ -0,0 +1,49 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_RRC_CONFIG_COMMON_H
#define SRSLTE_RRC_CONFIG_COMMON_H
#include <cstdint>
namespace srsenb {
enum rrc_cfg_cqi_mode_t { RRC_CFG_CQI_MODE_PERIODIC = 0, RRC_CFG_CQI_MODE_APERIODIC, RRC_CFG_CQI_MODE_N_ITEMS };
static const char* rrc_cfg_cqi_mode_text[] = {"periodic", "aperiodic"};
inline const char* to_string(rrc_cfg_cqi_mode_t mode)
{
return mode < RRC_CFG_CQI_MODE_N_ITEMS ? rrc_cfg_cqi_mode_text[mode] : "invalid CQI mode";
}
struct rrc_cfg_cqi_t {
uint32_t sf_mapping[80];
uint32_t nof_subframes;
uint32_t nof_prb;
uint32_t period;
uint32_t m_ri;
bool simultaneousAckCQI;
rrc_cfg_cqi_mode_t mode;
};
} // namespace srsenb
#endif // SRSLTE_RRC_CONFIG_COMMON_H

@ -0,0 +1,176 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSENB_RRC_NR_H
#define SRSENB_RRC_NR_H
#include "rrc_config_common.h"
#include "rrc_metrics.h"
#include "srsenb/hdr/stack/enb_stack_base.h"
#include "srslte/asn1/rrc_nr_asn1.h"
#include "srslte/common/block_queue.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "srslte/common/logmap.h"
#include "srslte/common/threads.h"
#include "srslte/common/timeout.h"
#include "srslte/interfaces/gnb_interfaces.h"
#include "srsue/hdr/stack/upper/gw.h"
#include <map>
#include <queue>
namespace srsenb {
enum class rrc_nr_state_t { RRC_IDLE, RRC_INACTIVE, RRC_CONNECTED };
// TODO: Make this common to NR and LTE
struct rrc_nr_cfg_sr_t {
uint32_t period;
// asn1::rrc::sched_request_cfg_c::setup_s_::dsr_trans_max_e_ dsr_max;
uint32_t nof_prb;
uint32_t sf_mapping[80];
uint32_t nof_subframes;
};
// Expert arguments to create GW without core NW
struct core_less_args_t {
std::string ip_addr;
srsue::gw_args_t gw_args;
uint8_t drb_lcid;
uint16_t rnti;
};
struct rrc_nr_cfg_t {
asn1::rrc_nr::mib_s mib;
asn1::rrc_nr::sib1_s sib1;
asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_item_c_ sibs[ASN1_RRC_NR_MAX_SIB];
uint32_t nof_sibs;
rrc_nr_cfg_sr_t sr_cfg;
rrc_cfg_cqi_t cqi_cfg;
srslte_cell_t cell;
std::string log_level;
uint32_t log_hex_limit;
srsenb::core_less_args_t coreless;
};
class rrc_nr final : public rrc_interface_pdcp_nr,
public rrc_interface_mac_nr,
public rrc_interface_rlc_nr,
public rrc_interface_ngap_nr
{
public:
explicit rrc_nr(srslte::timer_handler* timers_);
void init(const rrc_nr_cfg_t& cfg,
phy_interface_stack_nr* phy,
mac_interface_rrc_nr* mac,
rlc_interface_rrc_nr* rlc,
pdcp_interface_rrc_nr* pdcp,
ngap_interface_rrc_nr* ngap_,
gtpu_interface_rrc_nr* gtpu);
void stop();
void get_metrics(srsenb::rrc_metrics_t& m);
rrc_nr_cfg_t update_default_cfg(const rrc_nr_cfg_t& rrc_cfg);
void add_user(uint16_t rnti);
void config_mac();
uint32_t generate_sibs();
int read_pdu_bcch_bch(const uint32_t tti, srslte::unique_byte_buffer_t& buffer) final;
int read_pdu_bcch_dlsch(uint32_t sib_index, srslte::unique_byte_buffer_t& buffer) final;
// RLC interface
// TODO
void read_pdu_pcch(uint8_t* payload, uint32_t payload_size) {}
void max_retx_attempted(uint16_t rnti) {}
// PDCP interface
void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) final;
class ue
{
public:
ue(rrc_nr* parent_, uint16_t rnti_);
void send_connection_setup();
void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg);
// getters
bool is_connected() { return state == rrc_nr_state_t::RRC_CONNECTED; }
bool is_idle() { return state == rrc_nr_state_t::RRC_IDLE; }
bool is_inactive() { return state == rrc_nr_state_t::RRC_INACTIVE; }
// setters
private:
enum class progress_state_t { WAIT_FOR_CON_SETUP_COMPLETE, NONE };
srslte::byte_buffer_pool* pool;
rrc_nr* parent;
uint16_t rnti;
// state
rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE;
progress_state_t prog_state = progress_state_t::NONE;
uint8_t transaction_id = 0;
srslte::timer_handler::unique_timer rrc_setup_periodic_timer;
};
private:
rrc_nr_cfg_t cfg = {};
// interfaces
phy_interface_stack_nr* phy = nullptr;
mac_interface_rrc_nr* mac = nullptr;
rlc_interface_rrc_nr* rlc = nullptr;
pdcp_interface_rrc_nr* pdcp = nullptr;
gtpu_interface_rrc_nr* gtpu = nullptr;
ngap_interface_rrc_nr* ngap = nullptr;
// args
srslte::byte_buffer_pool* pool = nullptr;
srslte::log_ref m_log;
srslte::timer_handler* timers = nullptr;
// derived
uint32_t slot_dur_ms = 0;
// vars
std::map<uint16_t, std::unique_ptr<ue> > users;
bool running = false;
std::vector<srslte::unique_byte_buffer_t> sib_buffer;
srslte::unique_byte_buffer_t mib_buffer = nullptr;
uint32_t nof_si_messages = 0;
// Private Methods
void handle_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu);
// logging
typedef enum { Rx = 0, Tx } direction_t;
template <class T>
void log_rrc_message(const std::string& source, direction_t dir, const srslte::byte_buffer_t* pdu, const T& msg);
};
} // namespace srsenb
#endif // SRSENB_RRC_NR_H

@ -21,3 +21,7 @@
set(SOURCES rrc.cc rrc_ue.cc rrc_mobility.cc rrc_cell_cfg.cc rrc_bearer_cfg.cc)
add_library(srsenb_rrc STATIC ${SOURCES})
if (ENABLE_5GNR)
set(SOURCES rrc_nr.cc)
add_library(srsgnb_rrc STATIC ${SOURCES})
endif ()

@ -0,0 +1,400 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsenb/hdr/stack/rrc/rrc_nr.h"
#include "srsenb/hdr/stack/upper/common_enb.h"
#include "srslte/asn1/rrc_nr_asn1_utils.h"
#include "srslte/interfaces/nr_common_interface_types.h"
using namespace asn1::rrc_nr;
namespace srsenb {
rrc_nr::rrc_nr(srslte::timer_handler* timers_) :
m_log("RRC"),
pool(srslte::byte_buffer_pool::get_instance()),
timers(timers_)
{}
void rrc_nr::init(const rrc_nr_cfg_t& cfg_,
phy_interface_stack_nr* phy_,
mac_interface_rrc_nr* mac_,
rlc_interface_rrc_nr* rlc_,
pdcp_interface_rrc_nr* pdcp_,
ngap_interface_rrc_nr* ngap_,
gtpu_interface_rrc_nr* gtpu_)
{
phy = phy_;
mac = mac_;
rlc = rlc_;
pdcp = pdcp_;
gtpu = gtpu_;
ngap = ngap_;
// FIXME: overwriting because we are not passing config right now
cfg = update_default_cfg(cfg_);
// config logging
m_log->set_level(cfg.log_level);
m_log->set_hex_limit(cfg.log_hex_limit);
// derived
slot_dur_ms = 1;
nof_si_messages = generate_sibs();
config_mac();
// add dummy user
m_log->info("Creating dummy DRB for RNTI=%d on LCID=%d\n", cfg.coreless.rnti, cfg.coreless.drb_lcid);
add_user(cfg.coreless.rnti);
srslte::rlc_config_t rlc_cnfg = srslte::rlc_config_t::default_rlc_um_nr_config(6);
rlc->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, rlc_cnfg);
srslte::pdcp_config_t pdcp_cnfg{cfg.coreless.drb_lcid,
srslte::PDCP_RB_IS_DRB,
srslte::SECURITY_DIRECTION_DOWNLINK,
srslte::SECURITY_DIRECTION_UPLINK,
srslte::PDCP_SN_LEN_18,
srslte::pdcp_t_reordering_t::ms500,
srslte::pdcp_discard_timer_t::infinity};
pdcp->add_bearer(cfg.coreless.rnti, cfg.coreless.drb_lcid, pdcp_cnfg);
m_log->info("Started\n");
running = true;
}
void rrc_nr::stop()
{
if (running) {
running = false;
}
users.clear();
}
template <class T>
void rrc_nr::log_rrc_message(const std::string& source,
const direction_t dir,
const srslte::byte_buffer_t* pdu,
const T& msg)
{
if (m_log->get_level() == srslte::LOG_LEVEL_INFO) {
m_log->info("%s - %s %s (%d B)\n",
source.c_str(),
dir == Tx ? "Tx" : "Rx",
msg.msg.c1().type().to_string().c_str(),
pdu->N_bytes);
} else if (m_log->get_level() >= srslte::LOG_LEVEL_DEBUG) {
asn1::json_writer json_writer;
msg.to_json(json_writer);
m_log->debug_hex(pdu->msg,
pdu->N_bytes,
"%s - %s %s (%d B)\n",
source.c_str(),
dir == Tx ? "Tx" : "Rx",
msg.msg.c1().type().to_string().c_str(),
pdu->N_bytes);
m_log->debug("Content:\n%s\n", json_writer.to_string().c_str());
}
}
rrc_nr_cfg_t rrc_nr::update_default_cfg(const rrc_nr_cfg_t& current)
{
// NOTE: This function is temporary.
rrc_nr_cfg_t cfg_default = current;
// Fill MIB
cfg_default.mib.sub_carrier_spacing_common.value = mib_s::sub_carrier_spacing_common_opts::scs15or60;
cfg_default.mib.ssb_subcarrier_offset = 0;
cfg_default.mib.intra_freq_resel.value = mib_s::intra_freq_resel_opts::allowed;
cfg_default.mib.cell_barred.value = mib_s::cell_barred_opts::not_barred;
cfg_default.mib.pdcch_cfg_sib1.search_space_zero = 0;
cfg_default.mib.pdcch_cfg_sib1.ctrl_res_set_zero = 0;
cfg_default.mib.dmrs_type_a_position.value = mib_s::dmrs_type_a_position_opts::pos2;
cfg_default.mib.sys_frame_num.from_number(0);
cfg_default.cell.nof_prb = 25;
cfg_default.cell.nof_ports = 1;
cfg_default.cell.id = 0;
cfg_default.cell.cp = SRSLTE_CP_NORM;
cfg_default.cell.frame_type = SRSLTE_FDD;
cfg_default.cell.phich_length = SRSLTE_PHICH_NORM;
cfg_default.cell.phich_resources = SRSLTE_PHICH_R_1;
// Fill SIB1
cfg_default.sib1.cell_access_related_info.plmn_id_list.resize(1);
cfg_default.sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list.resize(1);
srslte::plmn_id_t plmn;
plmn.from_string("90170");
srslte::to_asn1(&cfg_default.sib1.cell_access_related_info.plmn_id_list[0].plmn_id_list[0], plmn);
cfg_default.sib1.cell_access_related_info.plmn_id_list[0].cell_id.from_number(1);
cfg_default.sib1.cell_access_related_info.plmn_id_list[0].cell_reserved_for_oper.value =
plmn_id_info_s::cell_reserved_for_oper_opts::not_reserved;
cfg_default.sib1.si_sched_info_present = true;
cfg_default.sib1.si_sched_info.si_request_cfg.rach_occasions_si_present = true;
cfg_default.sib1.si_sched_info.si_request_cfg.rach_occasions_si.rach_cfg_si.ra_resp_win.value =
rach_cfg_generic_s::ra_resp_win_opts::sl8;
cfg_default.sib1.si_sched_info.si_win_len.value = si_sched_info_s::si_win_len_opts::s20;
cfg_default.sib1.si_sched_info.sched_info_list.resize(1);
cfg_default.sib1.si_sched_info.sched_info_list[0].si_broadcast_status.value =
sched_info_s::si_broadcast_status_opts::broadcasting;
cfg_default.sib1.si_sched_info.sched_info_list[0].si_periodicity.value = sched_info_s::si_periodicity_opts::rf16;
cfg_default.sib1.si_sched_info.sched_info_list[0].sib_map_info.resize(1);
// scheduling of SI messages
cfg_default.sib1.si_sched_info.sched_info_list[0].sib_map_info[0].type.value = sib_type_info_s::type_opts::sib_type2;
cfg_default.sib1.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag_present = true;
cfg_default.sib1.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag = 0;
// Fill SIB2+
cfg_default.nof_sibs = 1;
sib2_s& sib2 = cfg_default.sibs[0].set_sib2();
sib2.cell_resel_info_common.q_hyst.value = sib2_s::cell_resel_info_common_s_::q_hyst_opts::db5;
// FIXME: Fill SIB2 values
// set loglevel
cfg_default.log_level = "debug";
cfg_default.log_hex_limit = 10000;
return cfg_default;
}
// This function is called from PRACH worker (can wait)
void rrc_nr::add_user(uint16_t rnti)
{
if (users.count(rnti) == 0) {
users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue(this, rnti))));
rlc->add_user(rnti);
pdcp->add_user(rnti);
m_log->info("Added new user rnti=0x%x\n", rnti);
} else {
m_log->error("Adding user rnti=0x%x (already exists)\n", rnti);
}
}
void rrc_nr::config_mac()
{
// Fill MAC scheduler configuration for SIBs
srsenb::sched_interface::cell_cfg_t sched_cfg;
set_sched_cell_cfg_sib1(&sched_cfg, cfg.sib1);
// set SIB length
for (uint32_t i = 0; i < nof_si_messages + 1; i++) {
sched_cfg.sibs[i].len = sib_buffer[i]->N_bytes;
}
// PUCCH width
sched_cfg.nrb_pucch = SRSLTE_MAX(cfg.sr_cfg.nof_prb, cfg.cqi_cfg.nof_prb);
m_log->info("Allocating %d PRBs for PUCCH\n", sched_cfg.nrb_pucch);
// Copy Cell configuration
sched_cfg.cell = cfg.cell;
// Configure MAC scheduler
mac->cell_cfg(&sched_cfg);
}
uint32_t rrc_nr::generate_sibs()
{
// MIB packing
bcch_bch_msg_s mib_msg;
mib_s& mib = mib_msg.msg.set_mib();
mib = cfg.mib;
{
srslte::unique_byte_buffer_t mib_buf = srslte::allocate_unique_buffer(*pool);
asn1::bit_ref bref(mib_buf->msg, mib_buf->get_tailroom());
mib_msg.pack(bref);
mib_buf->N_bytes = bref.distance_bytes();
m_log->debug_hex(mib_buf->msg, mib_buf->N_bytes, "MIB payload (%d B)\n", mib_buf->N_bytes);
mib_buffer = std::move(mib_buf);
}
si_sched_info_s::sched_info_list_l_& sched_info = cfg.sib1.si_sched_info.sched_info_list;
uint32_t nof_messages = cfg.sib1.si_sched_info_present ? cfg.sib1.si_sched_info.sched_info_list.size() : 0;
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
// all SIBs in a SI message msg[i] share the same periodicity
sib_buffer.reserve(nof_messages + 1);
asn1::dyn_array<bcch_dl_sch_msg_s> msg(nof_messages + 1);
// Copy SIB1 to first SI message
msg[0].msg.set_c1().set_sib_type1() = cfg.sib1;
// Copy rest of SIBs
for (uint32_t sched_info_elem = 0; sched_info_elem < nof_messages; sched_info_elem++) {
uint32_t msg_index = sched_info_elem + 1; // first msg is SIB1, therefore start with second
msg[msg_index].msg.set_c1().set_sys_info().crit_exts.set_sys_info_r15();
auto& sib_list = msg[msg_index].msg.c1().sys_info().crit_exts.sys_info_r15().sib_type_and_info;
for (uint32_t mapping = 0; mapping < sched_info[sched_info_elem].sib_map_info.size(); ++mapping) {
uint32_t sibidx = sched_info[sched_info_elem].sib_map_info[mapping].type; // SIB2 == 0
sib_list.push_back(cfg.sibs[sibidx]);
}
}
// Pack payload for all messages
for (uint32_t msg_index = 0; msg_index < nof_messages + 1; msg_index++) {
srslte::unique_byte_buffer_t sib = srslte::allocate_unique_buffer(*pool);
asn1::bit_ref bref(sib->msg, sib->get_tailroom());
msg[msg_index].pack(bref);
sib->N_bytes = bref.distance_bytes();
sib_buffer.push_back(std::move(sib));
// Log SIBs in JSON format
log_rrc_message("SIB payload", Tx, sib_buffer.back().get(), msg[msg_index]);
}
return sib_buffer.size() - 1;
}
/*******************************************************************************
MAC interface
*******************************************************************************/
int rrc_nr::read_pdu_bcch_bch(const uint32_t tti, srslte::unique_byte_buffer_t& buffer)
{
if (mib_buffer == nullptr || buffer->get_tailroom() < mib_buffer->N_bytes) {
return SRSLTE_ERROR;
}
memcpy(buffer->msg, mib_buffer->msg, mib_buffer->N_bytes);
buffer->N_bytes = mib_buffer->N_bytes;
return SRSLTE_SUCCESS;
}
int rrc_nr::read_pdu_bcch_dlsch(uint32_t sib_index, srslte::unique_byte_buffer_t& buffer)
{
if (sib_index >= sib_buffer.size()) {
m_log->error("SIB %d is not a configured SIB.\n", sib_index);
return SRSLTE_ERROR;
}
if (buffer->get_tailroom() < sib_buffer[sib_index]->N_bytes) {
m_log->error("Not enough space to fit SIB %d into buffer (%d < %d)\n",
sib_index,
buffer->get_tailroom(),
sib_buffer[sib_index]->N_bytes);
return SRSLTE_ERROR;
}
memcpy(buffer->msg, sib_buffer[sib_index]->msg, sib_buffer[sib_index]->N_bytes);
buffer->N_bytes = sib_buffer[sib_index]->N_bytes;
return SRSLTE_SUCCESS;
}
void rrc_nr::get_metrics(srsenb::rrc_metrics_t& m)
{
// return metrics
}
void rrc_nr::handle_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu)
{
if (pdu) {
m_log->info_hex(pdu->msg, pdu->N_bytes, "Rx %s PDU", srslte::to_string(static_cast<srslte::rb_id_nr_t>(lcid)));
}
if (users.count(rnti) == 1) {
switch (lcid) {
case srsenb::RB_ID_SRB0:
// parse_ul_ccch(rnti, std::move(pdu));
break;
case srsenb::RB_ID_SRB1:
case srsenb::RB_ID_SRB2:
// parse_ul_dcch(p.rnti, p.lcid, std::move(p.pdu));
break;
default:
m_log->error("Rx PDU with invalid bearer id: %d", lcid);
break;
}
} else {
m_log->warning("Discarding PDU for removed rnti=0x%x\n", rnti);
}
}
/*******************************************************************************
PDCP interface
*******************************************************************************/
void rrc_nr::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu)
{
handle_pdu(rnti, lcid, std::move(pdu));
}
/*******************************************************************************
UE class
Every function in UE class is called from a mutex environment thus does not
need extra protection.
*******************************************************************************/
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_) : parent(parent_), rnti(rnti_)
{
pool = srslte::byte_buffer_pool::get_instance();
// setup periodic RRCSetup send
rrc_setup_periodic_timer = parent->timers->get_unique_timer();
rrc_setup_periodic_timer.set(5000, [this](uint32_t tid) {
send_connection_setup();
rrc_setup_periodic_timer.run();
});
rrc_setup_periodic_timer.run();
}
void rrc_nr::ue::send_connection_setup()
{
dl_ccch_msg_s dl_ccch_msg;
dl_ccch_msg.msg.set_c1().set_rrc_setup().rrc_transaction_id = ((transaction_id++) % 4u);
rrc_setup_ies_s& setup = dl_ccch_msg.msg.c1().rrc_setup().crit_exts.set_rrc_setup();
radio_bearer_cfg_s& rr_cfg = setup.radio_bearer_cfg;
// Add DRB1 to cfg
rr_cfg.drb_to_add_mod_list_present = true;
rr_cfg.drb_to_add_mod_list.resize(1);
auto& drb_item = rr_cfg.drb_to_add_mod_list[0];
drb_item.drb_id = 1;
drb_item.pdcp_cfg_present = true;
drb_item.pdcp_cfg.ciphering_disabled_present = true;
// drb_item.cn_assoc_present = true;
// drb_item.cn_assoc.set_eps_bearer_id() = ;
drb_item.recover_pdcp_present = false;
// TODO: send config to RLC/PDCP
send_dl_ccch(&dl_ccch_msg);
}
void rrc_nr::ue::send_dl_ccch(dl_ccch_msg_s* dl_ccch_msg)
{
// Allocate a new PDU buffer, pack the message and send to PDCP
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool);
if (pdu == nullptr) {
parent->m_log->error("Allocating pdu\n");
}
asn1::bit_ref bref(pdu->msg, pdu->get_tailroom());
if (dl_ccch_msg->pack(bref) == asn1::SRSASN_ERROR_ENCODE_FAIL) {
parent->m_log->error("Failed to pack DL-CCCH message. Discarding msg.\n");
}
pdu->N_bytes = 1u + (uint32_t)bref.distance_bytes(pdu->msg);
char buf[32] = {};
sprintf(buf, "SRB0 - rnti=0x%x", rnti);
parent->log_rrc_message(buf, Tx, pdu.get(), *dl_ccch_msg);
parent->rlc->write_sdu(rnti, RB_ID_SRB0, std::move(pdu));
}
} // namespace srsenb
Loading…
Cancel
Save