mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' into agpl_next
This commit is contained in:
commit
fb75a5ef0e
|
@ -70,6 +70,7 @@ struct pdcch_cfg_common_s;
|
|||
struct pdcch_cfg_s;
|
||||
struct pdsch_cfg_common_s;
|
||||
struct pucch_cfg_common_s;
|
||||
struct pucch_cfg_s;
|
||||
struct pusch_cfg_common_s;
|
||||
struct mib_s;
|
||||
|
||||
|
@ -144,6 +145,7 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg
|
|||
bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch);
|
||||
bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch);
|
||||
void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg, srsran_pucch_nr_common_cfg_t* pucch);
|
||||
bool fill_phy_pucch_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch);
|
||||
bool fill_phy_pusch_cfg_common(const asn1::rrc_nr::pusch_cfg_common_s& pusch_cfg, srsran_sch_hl_cfg_nr_t* pusch);
|
||||
void fill_phy_carrier_cfg(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg,
|
||||
srsran_carrier_nr_t* carrier_nr);
|
||||
|
|
|
@ -106,6 +106,7 @@ struct k_enb_context_t {
|
|||
};
|
||||
|
||||
struct k_gnb_context_t {
|
||||
as_key_t k_gnb;
|
||||
as_key_t sk_gnb;
|
||||
};
|
||||
|
||||
|
@ -189,6 +190,8 @@ uint8_t security_generate_k_amf(const uint8_t* k_seaf,
|
|||
|
||||
uint8_t security_generate_k_seaf(const uint8_t* k_ausf, const char* serving_network_name, uint8_t* k_seaf);
|
||||
|
||||
uint8_t security_generate_k_gnb(const as_key_t& k_amf, const uint32_t nas_count, as_key_t& k_gnb);
|
||||
|
||||
uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count, uint8_t* k_enb);
|
||||
|
||||
uint8_t security_generate_k_nb_star_common(uint8_t fc,
|
||||
|
|
|
@ -84,8 +84,10 @@ public:
|
|||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
|
||||
// Pop first element
|
||||
// If the FIFO is not empty pop first element
|
||||
if (not fifo.empty()) {
|
||||
fifo.pop_front();
|
||||
}
|
||||
|
||||
// Notify release
|
||||
cvar.notify_all();
|
||||
|
|
|
@ -38,7 +38,7 @@ class pdu_session_cfg_t
|
|||
{
|
||||
public:
|
||||
std::string apn_name;
|
||||
apn_types apn_type;
|
||||
apn_types apn_type = ipv4;
|
||||
std::string apn_user;
|
||||
std::string apn_pass;
|
||||
};
|
||||
|
@ -68,6 +68,8 @@ class nas_5g_interface_rrc_nr
|
|||
{
|
||||
public:
|
||||
virtual int write_pdu(srsran::unique_byte_buffer_t pdu) = 0;
|
||||
virtual int get_k_amf(srsran::as_key_t& k_amf) = 0;
|
||||
virtual uint32_t get_ul_nas_count() = 0;
|
||||
};
|
||||
|
||||
class nas_5g_interface_procedures
|
||||
|
|
|
@ -105,7 +105,6 @@ struct phy_args_t {
|
|||
|
||||
srsran::channel::args_t dl_channel_args;
|
||||
srsran::channel::args_t ul_channel_args;
|
||||
|
||||
};
|
||||
|
||||
/* RAT agnostic Interface MAC -> PHY */
|
||||
|
@ -167,7 +166,7 @@ public:
|
|||
virtual void meas_stop() = 0;
|
||||
|
||||
/* Cell search and selection procedures */
|
||||
virtual bool cell_search() = 0;
|
||||
virtual bool cell_search(int earfcn) = 0;
|
||||
virtual bool cell_select(phy_cell_t cell) = 0;
|
||||
virtual bool cell_is_camping() = 0;
|
||||
};
|
||||
|
|
|
@ -86,6 +86,8 @@ public:
|
|||
class usim_interface_rrc_nr
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg) = 0;
|
||||
virtual bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) = 0;
|
||||
virtual bool update_nr_context(srsran::as_security_config_t* sec_cfg) = 0;
|
||||
};
|
||||
|
|
|
@ -85,7 +85,7 @@ class phy_dummy_interface : public phy_interface_rrc_lte
|
|||
void meas_stop() override {}
|
||||
|
||||
/* Cell search and selection procedures */
|
||||
bool cell_search() override { return true; }
|
||||
bool cell_search(int earfcn) override { return true; }
|
||||
bool cell_select(phy_cell_t cell) override { return true; }
|
||||
bool cell_is_camping() override { return false; }
|
||||
};
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
} else {
|
||||
encryption_direction = direction;
|
||||
}
|
||||
logger.debug("LCID=%d encryption=%s", lcid, srsran_direction_text[integrity_direction]);
|
||||
logger.debug("LCID=%d, encryption=%s", lcid, srsran_direction_text[integrity_direction]);
|
||||
}
|
||||
|
||||
void enable_security_timed(srsran_direction_t direction, uint32_t sn)
|
||||
|
|
|
@ -580,42 +580,41 @@ bool make_phy_csi_report(const csi_report_cfg_s& csi_report_cfg,
|
|||
}
|
||||
|
||||
if (srsran_csi_hl_report_cfg.type == SRSRAN_CSI_REPORT_TYPE_PERIODIC) {
|
||||
srsran_csi_hl_report_cfg.periodic.period =
|
||||
csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.type().to_number();
|
||||
switch (csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.type()) {
|
||||
const auto& csi_periodic = csi_report_cfg.report_cfg_type.periodic();
|
||||
srsran_csi_hl_report_cfg.periodic.period = csi_periodic.report_slot_cfg.type().to_number();
|
||||
switch (csi_periodic.report_slot_cfg.type()) {
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots4:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots4();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots4();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots5:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots5();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots5();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots8:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots8();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots8();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots10:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots10();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots10();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots16:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots16();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots16();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots20:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots20();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots20();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots40:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots40();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots40();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots80:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots80();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots80();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots160:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots160();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots160();
|
||||
break;
|
||||
case csi_report_periodicity_and_offset_c::types_opts::slots320:
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.slots320();
|
||||
srsran_csi_hl_report_cfg.periodic.offset = csi_periodic.report_slot_cfg.slots320();
|
||||
break;
|
||||
default:
|
||||
asn1::log_warning("Invalid option for report_slot_cfg %s",
|
||||
csi_report_cfg.report_cfg_type.periodic().report_slot_cfg.type().to_string());
|
||||
asn1::log_warning("Invalid option for report_slot_cfg %s", csi_periodic.report_slot_cfg.type().to_string());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -699,6 +698,7 @@ bool make_phy_csi_report(const csi_report_cfg_s& csi_report_cfg,
|
|||
asn1::log_warning("Invalid option for cqi_table %s", csi_report_cfg.cqi_table.to_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
*in_srsran_csi_hl_report_cfg = srsran_csi_hl_report_cfg;
|
||||
return true;
|
||||
}
|
||||
|
@ -805,6 +805,10 @@ bool make_phy_res_config(const pucch_res_s& pucch_res,
|
|||
{
|
||||
srsran_pucch_nr_resource_t srsran_pucch_nr_resource = {};
|
||||
srsran_pucch_nr_resource.starting_prb = pucch_res.start_prb;
|
||||
srsran_pucch_nr_resource.intra_slot_hopping = pucch_res.intra_slot_freq_hop_present;
|
||||
if (pucch_res.second_hop_prb_present) {
|
||||
srsran_pucch_nr_resource.second_hop_prb = pucch_res.second_hop_prb;
|
||||
}
|
||||
switch (pucch_res.format.type()) {
|
||||
case pucch_res_s::format_c_::types_opts::format0:
|
||||
srsran_pucch_nr_resource.format = SRSRAN_PUCCH_NR_FORMAT_0;
|
||||
|
@ -1646,6 +1650,21 @@ bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_ce
|
|||
if (not make_phy_csi_report(csi_rep, &csi_hl->reports[i])) {
|
||||
return false;
|
||||
}
|
||||
if (csi_rep.report_cfg_type.type().value == csi_report_cfg_s::report_cfg_type_c_::types_opts::periodic) {
|
||||
const auto& pucch_setup = serv_cell.ul_cfg.init_ul_bwp.pucch_cfg.setup();
|
||||
srsran_pucch_nr_resource_t& resource = csi_hl->reports[i].periodic.resource;
|
||||
uint32_t pucch_resource_id = csi_rep.report_cfg_type.periodic().pucch_csi_res_list[0].pucch_res;
|
||||
const auto& asn1_resource = pucch_setup.res_to_add_mod_list[pucch_resource_id];
|
||||
uint32_t format2_rate = 0;
|
||||
if (pucch_setup.format2_present and
|
||||
pucch_setup.format2.type().value == asn1::setup_release_c<pucch_format_cfg_s>::types_opts::setup and
|
||||
pucch_setup.format2.setup().max_code_rate_present) {
|
||||
format2_rate = pucch_setup.format2.setup().max_code_rate.to_number();
|
||||
}
|
||||
if (not make_phy_res_config(asn1_resource, format2_rate, &resource)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1720,6 +1739,67 @@ void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg
|
|||
}
|
||||
}
|
||||
|
||||
bool fill_phy_pucch_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch)
|
||||
{
|
||||
// sanity check to avoid pucch->sets[n] goes out of bound
|
||||
if (pucch_cfg.res_set_to_add_mod_list.size() > SRSRAN_PUCCH_NR_MAX_NOF_SETS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate over the sets of resourceSetToAddModList
|
||||
for (size_t n = 0; n < pucch_cfg.res_set_to_add_mod_list.size() and
|
||||
pucch_cfg.res_set_to_add_mod_list.size() <= SRSRAN_PUCCH_NR_MAX_NOF_SETS;
|
||||
n++) {
|
||||
auto& res_set = pucch_cfg.res_set_to_add_mod_list[n];
|
||||
pucch->sets[n].nof_resources = res_set.res_list.size();
|
||||
if (res_set.max_payload_size_present) {
|
||||
pucch->sets[n].max_payload_size = res_set.max_payload_size;
|
||||
}
|
||||
// NOTE: res_set.pucch_res_set_id does not have a corresponding field in the PHY struct
|
||||
|
||||
// for each set, iterate over the elements (an element is an index). For each of the element or index, find the
|
||||
// corresponding pucch_res_s object in the pucch_cfg.res_to_add_mod_list
|
||||
for (size_t res_idx = 0; res_idx < res_set.res_list.size(); res_idx++) {
|
||||
size_t pucch_resource_id = res_set.res_list[res_idx];
|
||||
|
||||
// Find the pucch_res_s object corresponding to pucch_resource_id in the pucch_cfg.res_to_add_mod_list
|
||||
size_t m = 0;
|
||||
while (m <= pucch_cfg.res_to_add_mod_list.size()) {
|
||||
if (m == pucch_cfg.res_to_add_mod_list.size()) {
|
||||
// if we get here, the list pucch_cfg.res_to_add_mod_list does not contain any object corresponding to
|
||||
// pucch_resource_id
|
||||
return false;
|
||||
}
|
||||
if (pucch_cfg.res_to_add_mod_list[m].pucch_res_id == pucch_resource_id) {
|
||||
break; // item found, exit the loop
|
||||
}
|
||||
m++;
|
||||
}
|
||||
|
||||
// Below is the object corresponding to pucch_resource_id in the pucch_cfg.res_to_add_mod_list
|
||||
const auto& asn1_resource = pucch_cfg.res_to_add_mod_list[m];
|
||||
|
||||
// sanity check to avoid pucch->sets[n].resources[res_idx] goes out of bound;
|
||||
if (res_idx >= SRSRAN_PUCCH_NR_MAX_NOF_RESOURCES_PER_SET) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& resource = pucch->sets[n].resources[res_idx];
|
||||
uint32_t format2_rate = 0;
|
||||
if (pucch_cfg.format2_present and
|
||||
pucch_cfg.format2.type().value == asn1::setup_release_c<pucch_format_cfg_s>::types_opts::setup and
|
||||
pucch_cfg.format2.setup().max_code_rate_present) {
|
||||
format2_rate = pucch_cfg.format2.setup().max_code_rate.to_number();
|
||||
}
|
||||
if (not make_phy_res_config(asn1_resource, format2_rate, &resource)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch)
|
||||
{
|
||||
for (uint32_t i = 0; i < pdsch_cfg.pdsch_time_domain_alloc_list.size(); i++) {
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "srsran/common/s3g.h"
|
||||
#include "srsran/common/ssl.h"
|
||||
#include "srsran/config.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifdef HAVE_MBEDTLS
|
||||
|
@ -204,6 +203,32 @@ uint8_t security_generate_k_amf(const uint8_t* k_seaf,
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t security_generate_k_gnb(const as_key_t& k_amf, const uint32_t nas_count_, as_key_t& k_gnb)
|
||||
{
|
||||
if (k_amf.empty()) {
|
||||
log_error("Invalid inputs");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// NAS Count
|
||||
std::vector<uint8_t> nas_count;
|
||||
nas_count.resize(4);
|
||||
nas_count[0] = (nas_count_ >> 24) & 0xFF;
|
||||
nas_count[1] = (nas_count_ >> 16) & 0xFF;
|
||||
nas_count[2] = (nas_count_ >> 8) & 0xFF;
|
||||
nas_count[3] = nas_count_ & 0xFF;
|
||||
|
||||
// Access Type Distinguisher 3GPP access = 0x01 (TS 33501 Annex A.9)
|
||||
std::vector<uint8_t> access_type_distinguisher = {1};
|
||||
|
||||
if (kdf_common(FC_5G_KGNB_KN3IWF_DERIVATION, k_amf, nas_count, access_type_distinguisher, k_gnb.data()) !=
|
||||
SRSRAN_SUCCESS) {
|
||||
log_error("Failed to run kdf_common");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t security_generate_k_enb(const uint8_t* k_asme, const uint32_t nas_count_, uint8_t* k_enb)
|
||||
{
|
||||
if (k_asme == NULL || k_enb == NULL) {
|
||||
|
|
|
@ -637,10 +637,23 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Avoid NAN getting into the demodulator
|
||||
for (uint32_t i = 0; i < PBCH_NR_M; i++) {
|
||||
if (isnan(__real__ symbols[i]) || isnan(__imag__ symbols[i])) {
|
||||
symbols[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 7.3.3.2 Modulation
|
||||
int8_t llr[PBCH_NR_E];
|
||||
srsran_demod_soft_demodulate_b(SRSRAN_MOD_QPSK, symbols, llr, PBCH_NR_M);
|
||||
|
||||
// If all LLR are zero, no message could be received
|
||||
if (srsran_vec_avg_power_bf(llr, PBCH_NR_E) == 0) {
|
||||
SRSRAN_MEM_ZERO(msg, srsran_pbch_msg_nr_t, 1);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// TS 38.211 7.3.3 Physical broadcast channel
|
||||
// 7.3.3.1 Scrambling
|
||||
pbch_nr_scramble_rx(cfg, cfg->ssb_idx, llr, llr);
|
||||
|
|
|
@ -641,6 +641,10 @@ if(RF_FOUND)
|
|||
target_link_libraries(prach_test_usrp srsran_rf srsran_phy pthread)
|
||||
endif(RF_FOUND)
|
||||
|
||||
add_executable(prach_nr_test_perf EXCLUDE_FROM_ALL prach_nr_test_perf.c)
|
||||
target_link_libraries(prach_nr_test_perf srsran_phy)
|
||||
# this is just for performance evaluation, not for unit testing
|
||||
|
||||
########################################################################
|
||||
# NR
|
||||
########################################################################
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/**
|
||||
* \copyright Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* \copyright 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 prach_nr_test_perf.c
|
||||
* \brief Performance test for PRACH NR.
|
||||
*
|
||||
* This program simulates several PRACH preamble transmissions (so far, burst format 0 only)
|
||||
* to estimate the probability of detection and of false alarm. The probability of detection
|
||||
* is the conditional probability of detecting the preamble when the preamble is present.
|
||||
* An error consists in detecting no preambles, detecting only preambles different from the
|
||||
* reference one, or detecting the correct preamble with a timing error beyond tolerance.
|
||||
* The probability of false alarm is the probability of detecting any preamble when input
|
||||
* is only noise.
|
||||
*
|
||||
* The simulation setup can be controlled by means of the following arguments.
|
||||
* - <tt>-N num</tt>: sets the number of experiments to \c num.
|
||||
* - <tt>-n num</tt>: sets the total number of UL PRBs to \c num.
|
||||
* - <tt>-f num</tt>: sets the preamble format to \c num (for now, format 0 only).
|
||||
* - <tt>-s val</tt>: sets the nominal SNR to \c val dB.
|
||||
* - <tt>-v </tt>: activates verbose output.
|
||||
*
|
||||
* Example:
|
||||
* \code{.cpp}
|
||||
* prach_nr_test_perf -n 52 -s -14.6
|
||||
* \endcode
|
||||
*
|
||||
* \todo Restricted preamble formats not implemented yet. Fading channel and SIMO.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "srsran/srsran.h"
|
||||
|
||||
#define MAX_LEN 70176
|
||||
|
||||
static uint32_t nof_prb = 52;
|
||||
static uint32_t config_idx = 0;
|
||||
static int nof_runs = 100;
|
||||
static float snr_dB = -14.5F;
|
||||
static bool is_verbose = false;
|
||||
|
||||
static void usage(char* prog)
|
||||
{
|
||||
printf("Usage: %s\n", prog);
|
||||
printf("\t-N Number of experiments [Default %d]\n", nof_runs);
|
||||
printf("\t-n Uplink number of PRB [Default %d]\n", nof_prb);
|
||||
printf("\t-f Preamble format [Default %d]\n", config_idx);
|
||||
printf("\t-s SNR in dB [Default %.2f]\n", snr_dB);
|
||||
printf("\t-v Activate verbose output [Default %s]\n", is_verbose ? "true" : "false");
|
||||
}
|
||||
|
||||
static void parse_args(int argc, char** argv)
|
||||
{
|
||||
int opt = 0;
|
||||
while ((opt = getopt(argc, argv, "N:n:f:s:v")) != -1) {
|
||||
switch (opt) {
|
||||
case 'N':
|
||||
nof_runs = (int)strtol(optarg, NULL, 10);
|
||||
break;
|
||||
case 'n':
|
||||
nof_prb = (uint32_t)strtol(optarg, NULL, 10);
|
||||
break;
|
||||
case 'f':
|
||||
config_idx = (uint32_t)strtol(optarg, NULL, 10);
|
||||
break;
|
||||
case 's':
|
||||
snr_dB = strtof(optarg, NULL);
|
||||
break;
|
||||
case 'v':
|
||||
is_verbose = true;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
parse_args(argc, argv);
|
||||
if (config_idx != 0) {
|
||||
ERROR("Preamble format not yet implemented");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
srsran_prach_t prach;
|
||||
|
||||
const int fft_size = srsran_symbol_sz(nof_prb);
|
||||
const float main_scs_kHz = 15; // UL subcarrier spacing (i.e., Delta f)
|
||||
const float sampling_time_us = 1000.0F / (main_scs_kHz * (float)fft_size);
|
||||
const int slot_length = 15 * fft_size; // number of samples in a slot
|
||||
|
||||
if (srsran_prach_init(&prach, fft_size)) {
|
||||
ERROR("Initializing PRACH");
|
||||
srsran_prach_free(&prach);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
cf_t preamble[MAX_LEN];
|
||||
srsran_vec_cf_zero(preamble, MAX_LEN);
|
||||
|
||||
srsran_prach_cfg_t prach_cfg;
|
||||
ZERO_OBJECT(prach_cfg);
|
||||
|
||||
// Setup according to TS38.104 Section 8.4
|
||||
prach_cfg.is_nr = true;
|
||||
prach_cfg.config_idx = 0; // preamble format 0
|
||||
prach_cfg.hs_flag = false; // no high speed
|
||||
prach_cfg.freq_offset = 0;
|
||||
prach_cfg.root_seq_idx = 22; // logical (root sequence) index i
|
||||
prach_cfg.zero_corr_zone = 1; // zero correlation zone -> implies Ncs = 13
|
||||
prach_cfg.num_ra_preambles = 0; // use default
|
||||
const uint32_t seq_index = 32; // sequence index "v"
|
||||
const float prach_scs_kHz = 1.25F; // PRACH subcarrier spacing (i.e., Delta f^RA)
|
||||
const float max_time_error_us = 1.04F; // time error tolerance
|
||||
const int nof_offset_steps = 10;
|
||||
|
||||
if (srsran_prach_set_cfg(&prach, &prach_cfg, nof_prb)) {
|
||||
ERROR("Error initiating PRACH object");
|
||||
srsran_prach_free(&prach);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (srsran_prach_gen(&prach, seq_index, 0, preamble) < SRSRAN_SUCCESS) {
|
||||
ERROR("Generating PRACH preamble");
|
||||
srsran_prach_free(&prach);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
const uint32_t preamble_length = prach.N_seq;
|
||||
|
||||
float prach_pwr_sqrt = sqrtf(srsran_vec_avg_power_cf(preamble, preamble_length));
|
||||
if (!isnormal(prach_pwr_sqrt)) {
|
||||
ERROR("PRACH preamble power is not a finite, nonzero value");
|
||||
srsran_prach_free(&prach);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
srsran_vec_sc_prod_cfc(preamble, 1.0F / prach_pwr_sqrt, preamble, preamble_length);
|
||||
|
||||
int vector_length = 2 * slot_length;
|
||||
cf_t symbols[vector_length];
|
||||
cf_t noise_vec[vector_length];
|
||||
|
||||
uint32_t indices[64] = {0};
|
||||
float offset_est[64] = {0};
|
||||
uint32_t n_indices = 0;
|
||||
|
||||
float time_offset_us = 0;
|
||||
int offset_samples = 0;
|
||||
float noise_var = srsran_convert_dB_to_power(-snr_dB);
|
||||
int ok_detection = 0;
|
||||
int missed_detection = 0;
|
||||
int false_detection_signal_tmp = 0;
|
||||
int false_detection_signal = 0;
|
||||
int false_detection_noise = 0;
|
||||
int offset_est_error = 0;
|
||||
|
||||
// Timing offset base value is equivalent to N_cs/2
|
||||
const uint32_t ZC_length = prach.N_zc; // Zadoff-Chu sequence length (i.e., L_RA)
|
||||
const float base_time_offset_us = (float)prach.N_cs * 1000 / (2.0F * (float)ZC_length * prach_scs_kHz);
|
||||
|
||||
int step = SRSRAN_MAX(nof_runs / 100, 1);
|
||||
for (int i_run = 0; i_run < nof_runs; i_run++) {
|
||||
// show we are doing something
|
||||
if (i_run % (20 * step) == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
if (i_run % step == 0) {
|
||||
printf("*");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
srsran_vec_cf_zero(noise_vec, vector_length);
|
||||
srsran_ch_awgn_c(noise_vec, noise_vec, noise_var, vector_length);
|
||||
if (is_verbose) {
|
||||
float prach_pwr = srsran_vec_avg_power_cf(preamble, preamble_length);
|
||||
float noise_pwr = srsran_vec_avg_power_cf(noise_vec, vector_length);
|
||||
printf(" Tx power: %.3f\n", prach_pwr);
|
||||
printf(" Noise power: %.3f\n", noise_pwr);
|
||||
printf(" Target/measured SNR: %.3f / %.3f dB\n", snr_dB, srsran_convert_power_to_dB(prach_pwr / noise_pwr));
|
||||
}
|
||||
// Cycle timing offset with a 0.1-us step starting from the base value
|
||||
for (int i = 0; i < nof_offset_steps; i++) {
|
||||
time_offset_us = base_time_offset_us + (float)i * 0.1F;
|
||||
offset_samples = (int)roundf(time_offset_us / sampling_time_us);
|
||||
srsran_vec_cf_copy(symbols, noise_vec, vector_length);
|
||||
srsran_vec_sum_ccc(&symbols[offset_samples], preamble, &symbols[offset_samples], preamble_length);
|
||||
|
||||
srsran_prach_detect_offset(&prach, 0, &symbols[prach.N_cp], slot_length, indices, offset_est, NULL, &n_indices);
|
||||
false_detection_signal_tmp = 0;
|
||||
for (int j = 0; j < n_indices; j++) {
|
||||
if (indices[j] != seq_index) {
|
||||
false_detection_signal_tmp++;
|
||||
} else if (fabsf(offset_est[j] * 1.0e6F - time_offset_us) > max_time_error_us) {
|
||||
offset_est_error++;
|
||||
} else {
|
||||
ok_detection++;
|
||||
}
|
||||
}
|
||||
false_detection_signal += (n_indices > 1 || false_detection_signal_tmp == 1);
|
||||
// Missed detection if no preamble was detected or no detected preamble is the right one
|
||||
missed_detection += (n_indices == 0 || n_indices == false_detection_signal_tmp);
|
||||
}
|
||||
|
||||
srsran_prach_detect_offset(&prach, 0, &noise_vec[prach.N_cp], slot_length, indices, offset_est, NULL, &n_indices);
|
||||
false_detection_noise += (n_indices > 0);
|
||||
}
|
||||
int total_runs = nof_offset_steps * nof_runs;
|
||||
if (missed_detection + ok_detection + offset_est_error != total_runs) {
|
||||
srsran_prach_free(&prach);
|
||||
ERROR("Counting detection errors");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
printf("\n\nPRACH performance test: format 0, %d PRB, AWGN channel, SNR=%.1f dB\n", nof_prb, snr_dB);
|
||||
printf("\nMissed detection probability: %.3e (%d out of %d)\n",
|
||||
(float)missed_detection / (float)total_runs,
|
||||
missed_detection,
|
||||
total_runs);
|
||||
printf("Probability of timing error: %.3e (%d out of %d)\n",
|
||||
(float)offset_est_error / (float)total_runs,
|
||||
offset_est_error,
|
||||
total_runs);
|
||||
printf("Probability of OK detection: %.3e (%d out of %d)\n",
|
||||
(float)ok_detection / (float)total_runs,
|
||||
ok_detection,
|
||||
total_runs);
|
||||
printf("\nProbability of false detection with preamble: %.3e (%d out of %d)\n",
|
||||
(float)false_detection_signal / (float)total_runs,
|
||||
false_detection_signal,
|
||||
total_runs);
|
||||
printf("Probability of false detection without preamble: %.3e (%d out of %d)\n",
|
||||
(float)false_detection_noise / (float)nof_runs,
|
||||
false_detection_noise,
|
||||
nof_runs);
|
||||
|
||||
srsran_prach_free(&prach);
|
||||
|
||||
printf("Done\n");
|
||||
}
|
|
@ -885,7 +885,7 @@ int rf_skiq_send_timed(void* h,
|
|||
}
|
||||
|
||||
int rf_skiq_send_timed_multi(void* h_,
|
||||
void** data_,
|
||||
void* data_[SRSRAN_MAX_PORTS],
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
|
|
|
@ -794,7 +794,7 @@ int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool bl
|
|||
for (int j = 0; j < decim_factor; j++, n++) {
|
||||
avg += ptr[n];
|
||||
}
|
||||
dst[i] = avg;
|
||||
dst[i] = avg; // divide by decim_factor later via scale
|
||||
}
|
||||
|
||||
rf_zmq_info(handler->id,
|
||||
|
@ -810,6 +810,10 @@ int rf_zmq_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool bl
|
|||
pthread_mutex_lock(&handler->rx_gain_mutex);
|
||||
float scale = srsran_convert_dB_to_amplitude(handler->rx_gain);
|
||||
pthread_mutex_unlock(&handler->rx_gain_mutex);
|
||||
// scale shall also incorporate decim_factor
|
||||
if (decim_factor > 0) {
|
||||
scale = scale / decim_factor;
|
||||
}
|
||||
for (uint32_t c = 0; c < handler->nof_channels; c++) {
|
||||
if (buffers[c]) {
|
||||
srsran_vec_sc_prod_cfc(buffers[c], scale, buffers[c], nsamples);
|
||||
|
|
|
@ -26,18 +26,22 @@
|
|||
#include <complex.h>
|
||||
#include <pthread.h>
|
||||
#include <srsran/phy/common/phy_common.h>
|
||||
#include <srsran/phy/utils/vector.h>
|
||||
#include <stdlib.h>
|
||||
#include <zmq.h>
|
||||
|
||||
#define NOF_RX_ANT 1
|
||||
#define PRINT_SAMPLES 1
|
||||
#define COMPARE_BITS 0
|
||||
#define COMPARE_EPSILON (1e-6f)
|
||||
#define NOF_RX_ANT 4
|
||||
#define NUM_SF (500)
|
||||
#define SF_LEN (1920)
|
||||
#define RF_BUFFER_SIZE (SF_LEN * NUM_SF)
|
||||
#define TX_OFFSET_MS (4)
|
||||
|
||||
static cf_t ue_rx_buffer[RF_BUFFER_SIZE];
|
||||
static cf_t enb_tx_buffer[RF_BUFFER_SIZE];
|
||||
static cf_t enb_rx_buffer[RF_BUFFER_SIZE];
|
||||
static cf_t ue_rx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE];
|
||||
static cf_t enb_tx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE];
|
||||
static cf_t enb_rx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE];
|
||||
|
||||
static srsran_rf_t ue_radio, enb_radio;
|
||||
pthread_t rx_thread;
|
||||
|
@ -62,13 +66,15 @@ void* ue_rx_thread_function(void* args)
|
|||
uint32_t num_rxed_samps = 0;
|
||||
for (uint32_t i = 0; i < num_slots; ++i) {
|
||||
void* data_ptr[SRSRAN_MAX_PORTS] = {NULL};
|
||||
data_ptr[0] = &ue_rx_buffer[i * num_samps_per_slot];
|
||||
for (uint32_t c = 0; c < NOF_RX_ANT; c++) {
|
||||
data_ptr[c] = &ue_rx_buffer[c][i * num_samps_per_slot];
|
||||
}
|
||||
num_rxed_samps += srsran_rf_recv_with_time_multi(&ue_radio, data_ptr, num_samps_per_slot, true, NULL, NULL);
|
||||
}
|
||||
|
||||
printf("received %d samples.\n", num_rxed_samps);
|
||||
|
||||
printf("closing ue norf device\n");
|
||||
printf("closing ue zmq device\n");
|
||||
srsran_rf_close(&ue_radio);
|
||||
|
||||
return NULL;
|
||||
|
@ -87,16 +93,23 @@ void enb_tx_function(const char* tx_args, bool timed_tx)
|
|||
}
|
||||
|
||||
// generate random tx data
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
for (int i = 0; i < RF_BUFFER_SIZE; i++) {
|
||||
enb_tx_buffer[i] = ((float)rand() / (float)RAND_MAX) + _Complex_I * ((float)rand() / (float)RAND_MAX);
|
||||
enb_tx_buffer[c][i] = ((float)rand() / (float)RAND_MAX) + _Complex_I * ((float)rand() / (float)RAND_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
// send data subframe per subframe
|
||||
uint32_t num_txed_samples = 0;
|
||||
|
||||
|
||||
// initial transmission without ts
|
||||
void* data_ptr[SRSRAN_MAX_PORTS] = {NULL};
|
||||
data_ptr[0] = &enb_tx_buffer[num_txed_samples];
|
||||
cf_t tx_buffer[NOF_RX_ANT][SF_LEN];
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof (cf_t));
|
||||
data_ptr[c] = &tx_buffer[c][0];
|
||||
}
|
||||
int ret = srsran_rf_send_multi(&enb_radio, (void**)data_ptr, SF_LEN, true, true, false);
|
||||
num_txed_samples += SF_LEN;
|
||||
|
||||
|
@ -105,11 +118,16 @@ void enb_tx_function(const char* tx_args, bool timed_tx)
|
|||
|
||||
for (uint32_t i = 0; i < NUM_SF - ((timed_tx) ? TX_OFFSET_MS : 1); ++i) {
|
||||
// first recv samples
|
||||
data_ptr[0] = enb_rx_buffer;
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
data_ptr[c] = enb_rx_buffer[c];
|
||||
}
|
||||
srsran_rf_recv_with_time_multi(&enb_radio, data_ptr, SF_LEN, true, &rx_time.full_secs, &rx_time.frac_secs);
|
||||
|
||||
// prepare data buffer
|
||||
data_ptr[0] = &enb_tx_buffer[num_txed_samples];
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof (cf_t));
|
||||
data_ptr[c] = &tx_buffer[c][0];
|
||||
}
|
||||
|
||||
if (timed_tx) {
|
||||
// timed tx relative to receive time (this will cause a cap in the rx'ed samples at the UE resulting in 3 zero
|
||||
|
@ -157,6 +175,8 @@ int run_test(const char* rx_args, const char* tx_args, bool timed_tx)
|
|||
// wait for rx thread
|
||||
pthread_join(rx_thread, NULL);
|
||||
|
||||
// channel-wise comparison
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
// subframe-wise compare tx'ed and rx'ed data (stop 3 subframes earlier for timed tx)
|
||||
for (uint32_t i = 0; i < NUM_SF - (timed_tx ? 3 : 0); ++i) {
|
||||
uint32_t sf_offet = 0;
|
||||
|
@ -165,18 +185,37 @@ int run_test(const char* rx_args, const char* tx_args, bool timed_tx)
|
|||
sf_offet = (TX_OFFSET_MS - 1) * SF_LEN;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// print first 3 samples for each SF
|
||||
#if PRINT_SAMPLES
|
||||
// print first 10 samples for each SF
|
||||
printf("enb_tx_buffer sf%d:\n", i);
|
||||
srsran_vec_fprint_c(stdout, &enb_tx_buffer[i * SF_LEN], 3);
|
||||
srsran_vec_fprint_c(stdout, &enb_tx_buffer[c][i * SF_LEN], 10);
|
||||
printf("ue_rx_buffer sf%d:\n", i);
|
||||
srsran_vec_fprint_c(stdout, &ue_rx_buffer[sf_offet + i * SF_LEN], 3);
|
||||
srsran_vec_fprint_c(stdout, &ue_rx_buffer[c][sf_offet + i * SF_LEN], 10);
|
||||
#endif
|
||||
|
||||
if (memcmp(&ue_rx_buffer[sf_offet + i * SF_LEN], &enb_tx_buffer[i * SF_LEN], SF_LEN) != 0) {
|
||||
#if COMPARE_BITS
|
||||
int d = memcmp(&ue_rx_buffer[sf_offet + i * SF_LEN], &enb_tx_buffer[i * SF_LEN], SF_LEN);
|
||||
if (d) {
|
||||
d = d > 0 ? d : -d;
|
||||
fprintf(stderr, "data mismatch in subframe %d, sample %d\n", i, d);
|
||||
printf("enb_tx_buffer sf%d:\n", i);
|
||||
srsran_vec_fprint_c(stdout, &enb_tx_buffer[i * SF_LEN + d], 10);
|
||||
printf("ue_rx_buffer sf%d:\n", i);
|
||||
srsran_vec_fprint_c(stdout, &ue_rx_buffer[sf_offet + i * SF_LEN + d], 10);
|
||||
goto exit;
|
||||
}
|
||||
#else
|
||||
srsran_vec_sub_ccc(&ue_rx_buffer[c][sf_offet + i * SF_LEN],
|
||||
&enb_tx_buffer[c][i * SF_LEN],
|
||||
&ue_rx_buffer[c][sf_offet + i * SF_LEN],
|
||||
SF_LEN);
|
||||
uint32_t max_ix = srsran_vec_max_abs_ci(&ue_rx_buffer[c][sf_offet + i * SF_LEN], SF_LEN);
|
||||
if (cabsf(ue_rx_buffer[c][sf_offet + i * SF_LEN + max_ix]) > COMPARE_EPSILON) {
|
||||
fprintf(stderr, "data mismatch in subframe %d\n", i);
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ret = SRSRAN_SUCCESS;
|
||||
|
@ -204,56 +243,76 @@ int param_test(const char* args_param, const int num_channels)
|
|||
|
||||
int main()
|
||||
{
|
||||
// two Rx ports
|
||||
if (param_test("rx_port=ipc://dl0,rx_port1=ipc://dl1", 2)) {
|
||||
fprintf(stderr, "Param test failed!\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// // two Rx ports
|
||||
// if (param_test("rx_port=ipc://dl0,rx_port1=ipc://dl1", 2)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
// multiple rx ports, no channel index provided
|
||||
if (param_test("rx_port=ipc://dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,base_srate=1.92e6", 4)) {
|
||||
fprintf(stderr, "Param test failed!\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// // multiple rx ports, no channel index provided
|
||||
// if (param_test("rx_port=ipc://dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,base_srate=1.92e6", 4)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
// One Rx, one Tx and all generic options
|
||||
if (param_test("rx_port0=tcp://"
|
||||
"localhost:2000,rx_format=sc16,tx_format=sc16,tx_type=pub,rx_type=sub,base_srate=1.92e6,id=test",
|
||||
1)) {
|
||||
fprintf(stderr, "Param test failed!\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// // One Rx, one Tx and all generic options
|
||||
// if (param_test("rx_port0=tcp://"
|
||||
// "localhost:2000,rx_format=sc16,tx_format=sc16,tx_type=pub,rx_type=sub,base_srate=1.92e6,id=test",
|
||||
// 1)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
// 1 port, 2 antennas, MIMO freq config
|
||||
if (param_test(
|
||||
"tx_port0=tcp://*:2001,tx_port1=tcp://*:2003,rx_port0=tcp://localhost:2000,rx_port1=tcp://"
|
||||
"localhost:2002,id=ue,base_srate=23.04e6,tx_freq0=2510e6,tx_freq1=2510e6,rx_freq0=2630e6,,rx_freq1=2630e6",
|
||||
2)) {
|
||||
fprintf(stderr, "Param test failed!\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// // 1 port, 2 antennas, MIMO freq config
|
||||
// if (param_test(
|
||||
// "tx_port0=tcp://*:2001,tx_port1=tcp://*:2003,rx_port0=tcp://localhost:2000,rx_port1=tcp://"
|
||||
// "localhost:2002,id=ue,base_srate=23.04e6,tx_freq0=2510e6,tx_freq1=2510e6,rx_freq0=2630e6,,rx_freq1=2630e6",
|
||||
// 2)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
#if NOF_RX_ANT == 1
|
||||
// single tx, single rx with continuous transmissions (no timed tx) using IPC transport
|
||||
if (run_test("rx_port=ipc://link1,id=ue,base_srate=1.92e6", "tx_port=ipc://link1,id=enb,base_srate=1.92e6", false) !=
|
||||
SRSRAN_SUCCESS) {
|
||||
fprintf(stderr, "Single tx, single rx test failed!\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// two trx radios with continous tx (no timed tx) using TCP transport for both directions
|
||||
if (run_test("tx_port=tcp://*:5554,rx_port=tcp://"
|
||||
"localhost:5555,id=ue,base_srate=1.92e6,log_trx_timeout=true,trx_timeout_ms=1000",
|
||||
"rx_port=tcp://localhost:5554,tx_port=tcp://*:5555,id=enb,base_srate=1.92e6",
|
||||
// up to 4 trx radios with continous tx (no decimation, no timed tx)
|
||||
if (run_test("tx_port=tcp://*:5554,tx_port=tcp://*:5556,tx_port=tcp://*:5558,tx_port=tcp://*:5560,rx_port=tcp://"
|
||||
"localhost:5555,rx_port=tcp://localhost:5557,rx_port=tcp://localhost:5559,rx_port=tcp://"
|
||||
"localhost:5561,id=ue,base_srate=1.92e6,log_trx_timeout=true,trx_timeout_ms=1000",
|
||||
"rx_port=tcp://localhost:5554,rx_port=tcp://localhost:5556,rx_port=tcp://localhost:5558,rx_port=tcp://"
|
||||
"localhost:5560,tx_port=tcp://*:5555,tx_port=tcp://*:5557,tx_port=tcp://*:5559,tx_port=tcp://"
|
||||
"*:5561,id=enb,base_srate=1.92e6",
|
||||
false) != SRSRAN_SUCCESS) {
|
||||
fprintf(stderr, "Two TRx radio test failed!\n");
|
||||
fprintf(stderr, "Multi TRx radio test failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// two trx radios with continous tx (no timed tx) using TCP for UL (UE tx) and IPC for eNB DL (eNB tx)
|
||||
if (run_test("tx_port=tcp://*:5554,rx_port=ipc://dl,id=ue,base_srate=1.92e6",
|
||||
"rx_port=tcp://localhost:5554,tx_port=ipc://dl,id=enb,base_srate=1.92e6",
|
||||
// up to 4 trx radios with continous tx (timed tx) using TCP for UL (UE tx) and IPC for eNB DL (eNB tx)
|
||||
if (run_test("tx_port=tcp://*:5554,tx_port=tcp://*:5556,tx_port=tcp://*:5558,tx_port=tcp://*:5560,rx_port=ipc://"
|
||||
"dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,id=ue,base_srate=1.92e6",
|
||||
"rx_port=tcp://localhost:5554,rx_port=tcp://localhost:5556,rx_port=tcp://localhost:5558,rx_port=tcp://"
|
||||
"localhost:5560,tx_port=ipc://dl0,tx_port=ipc://dl1,tx_port=ipc://dl2,tx_port=ipc://"
|
||||
"dl3,id=enb,base_srate=1.92e6",
|
||||
true) != SRSRAN_SUCCESS) {
|
||||
fprintf(stderr, "Two TRx radio test with timed tx failed!\n");
|
||||
fprintf(stderr, "Multi TRx radio test with timed tx failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// up to 4 trx radios with continous tx (timed tx) using TCP for UL (UE tx) and IPC for eNB DL (eNB tx)
|
||||
// with decimation 23.04e6 <-> 1.92e6
|
||||
if (run_test("tx_port=tcp://*:5554,tx_port=tcp://*:5556,tx_port=tcp://*:5558,tx_port=tcp://*:5560,rx_port=ipc://"
|
||||
"dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,id=ue,base_srate=23.04e6",
|
||||
"rx_port=tcp://localhost:5554,rx_port=tcp://localhost:5556,rx_port=tcp://localhost:5558,rx_port=tcp://"
|
||||
"localhost:5560,tx_port=ipc://dl0,tx_port=ipc://dl1,tx_port=ipc://dl2,tx_port=ipc://"
|
||||
"dl3,id=enb,base_srate=23.04e6",
|
||||
true) != SRSRAN_SUCCESS) {
|
||||
fprintf(stderr, "Multi TRx radio test with timed tx and decimation failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
/*
|
||||
* Default NR-PBCH DMRS normalised correlation (RSRP/EPRE) threshold
|
||||
*/
|
||||
#define SSB_PBCH_DMRS_DEFAULT_CORR_THR 0.6f
|
||||
#define SSB_PBCH_DMRS_DEFAULT_CORR_THR 0.5f
|
||||
|
||||
static int ssb_init_corr(srsran_ssb_t* q)
|
||||
{
|
||||
|
@ -865,8 +865,9 @@ static int ssb_pss_search(srsran_ssb_t* q,
|
|||
// Find maximum
|
||||
uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window);
|
||||
|
||||
// Average power, skip window if value is invalid (0.0, nan or inf)
|
||||
float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz);
|
||||
// Average power, take total power of the frequency domain signal after filtering, skip correlation window if
|
||||
// value is invalid (0.0, nan or inf)
|
||||
float avg_pwr_corr = srsran_vec_avg_power_cf(q->tmp_corr, q->corr_sz);
|
||||
if (!isnormal(avg_pwr_corr)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -974,6 +975,11 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
|
|||
t_offset = 0;
|
||||
}
|
||||
|
||||
// Make sure SSB time offset is in bounded in the input buffer
|
||||
if (t_offset + q->ssb_sz > nof_samples) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Demodulate
|
||||
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
|
||||
if (ssb_demodulate(q, in, t_offset, coarse_cfo_hz, ssb_grid) < SRSRAN_SUCCESS) {
|
||||
|
@ -1047,7 +1053,8 @@ static int ssb_select_pbch(srsran_ssb_t* q,
|
|||
uint32_t N_id,
|
||||
const cf_t ssb_grid[SRSRAN_SSB_NOF_RE],
|
||||
uint32_t* found_n_hf,
|
||||
uint32_t* found_ssb_idx_4lsb)
|
||||
uint32_t* found_ssb_idx_4lsb,
|
||||
srsran_dmrs_pbch_meas_t* pbch_meas)
|
||||
{
|
||||
// Prepare PBCH DMRS configuration
|
||||
srsran_dmrs_pbch_cfg_t pbch_dmrs_cfg = {};
|
||||
|
@ -1089,6 +1096,7 @@ static int ssb_select_pbch(srsran_ssb_t* q,
|
|||
// Save findings
|
||||
*found_n_hf = best_n_hf;
|
||||
*found_ssb_idx_4lsb = best_ssb_idx;
|
||||
*pbch_meas = best_meas;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
@ -1186,6 +1194,9 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Set the SSB search result with default value with PBCH CRC unmatched, meaning no cell is found
|
||||
SRSRAN_MEM_ZERO(res, srsran_ssb_search_res_t, 1);
|
||||
|
||||
// Search for PSS in time domain
|
||||
uint32_t N_id_2 = 0;
|
||||
uint32_t t_offset = 0;
|
||||
|
@ -1202,6 +1213,11 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
|
|||
t_offset = 0;
|
||||
}
|
||||
|
||||
// Make sure SSB time offset is in bounded in the input buffer
|
||||
if (t_offset + q->ssb_sz > nof_samples) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Demodulate
|
||||
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
|
||||
if (ssb_demodulate(q, in, t_offset, coarse_cfo_hz, ssb_grid) < SRSRAN_SUCCESS) {
|
||||
|
@ -1223,18 +1239,30 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
|
|||
// Select the most suitable SSB candidate
|
||||
uint32_t n_hf = 0;
|
||||
uint32_t ssb_idx = 0;
|
||||
if (ssb_select_pbch(q, N_id, ssb_grid, &n_hf, &ssb_idx) < SRSRAN_SUCCESS) {
|
||||
srsran_dmrs_pbch_meas_t pbch_meas = {};
|
||||
if (ssb_select_pbch(q, N_id, ssb_grid, &n_hf, &ssb_idx, &pbch_meas) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error selecting PBCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Compute PBCH channel estimates
|
||||
// Avoid decoding if the selected PBCH DMRS do not reach the minimum threshold
|
||||
if (pbch_meas.corr < q->args.pbch_dmrs_thr) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Decode PBCH
|
||||
srsran_pbch_msg_nr_t pbch_msg = {};
|
||||
if (ssb_decode_pbch(q, N_id, n_hf, ssb_idx, ssb_grid, &pbch_msg) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error decoding PBCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// If PBCH was not decoded, skip measurements
|
||||
if (!pbch_msg.crc) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Perform measurements from PSS and SSS
|
||||
srsran_csi_trs_measurements_t measurements = {};
|
||||
if (ssb_measure(q, ssb_grid, N_id, &measurements) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error measuring");
|
||||
|
@ -1336,6 +1364,9 @@ int srsran_ssb_find(srsran_ssb_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Set the PBCH message result with default value (CRC unmatched), meaning no cell is found
|
||||
SRSRAN_MEM_ZERO(pbch_msg, srsran_pbch_msg_nr_t, 1);
|
||||
|
||||
// Copy tail from previous execution into the start of this
|
||||
srsran_vec_cf_copy(q->sf_buffer, &q->sf_buffer[q->sf_sz], q->ssb_sz);
|
||||
|
||||
|
@ -1356,6 +1387,11 @@ int srsran_ssb_find(srsran_ssb_t* q,
|
|||
t_offset = 0;
|
||||
}
|
||||
|
||||
// Make sure SSB time offset is in bounded in the input buffer
|
||||
if (t_offset > q->sf_sz) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Demodulate
|
||||
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
|
||||
if (ssb_demodulate(q, q->sf_buffer, t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
|
||||
|
@ -1372,11 +1408,17 @@ int srsran_ssb_find(srsran_ssb_t* q,
|
|||
// Select the most suitable SSB candidate
|
||||
uint32_t n_hf = 0;
|
||||
uint32_t ssb_idx = 0; // SSB candidate index
|
||||
if (ssb_select_pbch(q, N_id, ssb_grid, &n_hf, &ssb_idx) < SRSRAN_SUCCESS) {
|
||||
srsran_dmrs_pbch_meas_t pbch_meas = {};
|
||||
if (ssb_select_pbch(q, N_id, ssb_grid, &n_hf, &ssb_idx, &pbch_meas) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error selecting PBCH");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Avoid decoding if the selected PBCH DMRS do not reach the minimum threshold
|
||||
if (pbch_meas.corr < q->args.pbch_dmrs_thr) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Calculate the SSB offset in the subframe
|
||||
uint32_t ssb_offset = srsran_ssb_candidate_sf_offset(q, ssb_idx);
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include <srsran/phy/utils/random.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SSB_DECODE_TEST_PCI_STRIDE 53
|
||||
#define SSB_DECODE_TEST_SSB_STRIDE 3
|
||||
|
||||
// NR parameters
|
||||
static uint32_t carrier_nof_prb = 52;
|
||||
static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz;
|
||||
|
@ -128,7 +131,7 @@ static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx)
|
|||
pbch_msg->crc = true;
|
||||
}
|
||||
|
||||
static int test_case_1(srsran_ssb_t* ssb)
|
||||
static int test_case_true(srsran_ssb_t* ssb)
|
||||
{
|
||||
// For benchmarking purposes
|
||||
uint64_t t_encode_usec = 0;
|
||||
|
@ -147,8 +150,8 @@ static int test_case_1(srsran_ssb_t* ssb)
|
|||
|
||||
// For each PCI...
|
||||
uint64_t count = 0;
|
||||
for (uint32_t pci = 0; pci < SRSRAN_NOF_NID_NR; pci += 23) {
|
||||
for (uint32_t ssb_idx = 0; ssb_idx < ssb->Lmax; ssb_idx++, count++) {
|
||||
for (uint32_t pci = 0; pci < SRSRAN_NOF_NID_NR; pci += SSB_DECODE_TEST_PCI_STRIDE) {
|
||||
for (uint32_t ssb_idx = 0; ssb_idx < ssb->Lmax; ssb_idx += SSB_DECODE_TEST_SSB_STRIDE, count++) {
|
||||
struct timeval t[3] = {};
|
||||
|
||||
// Build PBCH message
|
||||
|
@ -158,7 +161,7 @@ static int test_case_1(srsran_ssb_t* ssb)
|
|||
// Print encoded PBCH message
|
||||
char str[512] = {};
|
||||
srsran_pbch_msg_info(&pbch_msg_tx, str, sizeof(str));
|
||||
INFO("test_case_1 - encoded pci=%d %s", pci, str);
|
||||
INFO("test_case_true - encoded pci=%d %s", pci, str);
|
||||
|
||||
// Initialise baseband
|
||||
srsran_vec_cf_zero(buffer, hf_len);
|
||||
|
@ -184,7 +187,7 @@ static int test_case_1(srsran_ssb_t* ssb)
|
|||
|
||||
// Print decoded PBCH message
|
||||
srsran_pbch_msg_info(&pbch_msg_rx, str, sizeof(str));
|
||||
INFO("test_case_1 - decoded pci=%d %s crc=%s", pci, str, pbch_msg_rx.crc ? "OK" : "KO");
|
||||
INFO("test_case_true - decoded pci=%d %s crc=%s", pci, str, pbch_msg_rx.crc ? "OK" : "KO");
|
||||
|
||||
// Assert PBCH message CRC
|
||||
TESTASSERT(pbch_msg_rx.crc);
|
||||
|
@ -200,7 +203,7 @@ static int test_case_1(srsran_ssb_t* ssb)
|
|||
|
||||
// Print decoded PBCH message
|
||||
srsran_pbch_msg_info(&res.pbch_msg, str, sizeof(str));
|
||||
INFO("test_case_1 - found pci=%d %s crc=%s", res.N_id, str, res.pbch_msg.crc ? "OK" : "KO");
|
||||
INFO("test_case_true - found pci=%d %s crc=%s", res.N_id, str, res.pbch_msg.crc ? "OK" : "KO");
|
||||
|
||||
// Assert PBCH message CRC
|
||||
TESTASSERT(res.pbch_msg.crc);
|
||||
|
@ -209,11 +212,11 @@ static int test_case_1(srsran_ssb_t* ssb)
|
|||
}
|
||||
|
||||
if (!count) {
|
||||
ERROR("Error in test case 1: undefined division");
|
||||
ERROR("Error in test case true: undefined division");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
INFO("test_case_1 - %.1f usec/encode; %.1f usec/decode; %.1f usec/decode;",
|
||||
INFO("test_case_true - %.1f usec/encode; %.1f usec/decode; %.1f usec/decode;",
|
||||
(double)t_encode_usec / (double)(count),
|
||||
(double)t_decode_usec / (double)(count),
|
||||
(double)t_search_usec / (double)(count));
|
||||
|
@ -221,6 +224,77 @@ static int test_case_1(srsran_ssb_t* ssb)
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_case_false(srsran_ssb_t* ssb)
|
||||
{
|
||||
// For benchmarking purposes
|
||||
uint64_t t_decode_usec = 0;
|
||||
uint64_t t_search_usec = 0;
|
||||
|
||||
// SSB configuration
|
||||
srsran_ssb_cfg_t ssb_cfg = {};
|
||||
ssb_cfg.srate_hz = srate_hz;
|
||||
ssb_cfg.center_freq_hz = carrier_freq_hz;
|
||||
ssb_cfg.ssb_freq_hz = ssb_freq_hz;
|
||||
ssb_cfg.scs = ssb_scs;
|
||||
ssb_cfg.pattern = ssb_pattern;
|
||||
|
||||
TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS);
|
||||
|
||||
// For each PCI...
|
||||
uint32_t count = 0;
|
||||
for (uint32_t pci = 0; pci < SRSRAN_NOF_NID_NR; pci += SSB_DECODE_TEST_PCI_STRIDE, count++) {
|
||||
struct timeval t[3] = {};
|
||||
|
||||
// Initialise baseband
|
||||
srsran_vec_cf_zero(buffer, hf_len);
|
||||
|
||||
// Channel, as it is zero it only adds noise
|
||||
srsran_channel_awgn_run_c(&awgn, buffer, buffer, hf_len);
|
||||
|
||||
// Decode
|
||||
gettimeofday(&t[1], NULL);
|
||||
srsran_pbch_msg_nr_t pbch_msg_rx = {};
|
||||
TESTASSERT(srsran_ssb_decode_pbch(ssb, pci, false, 0, buffer, &pbch_msg_rx) == SRSRAN_SUCCESS);
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
t_decode_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;
|
||||
|
||||
// Print decoded PBCH message
|
||||
char str[512] = {};
|
||||
srsran_pbch_msg_info(&pbch_msg_rx, str, sizeof(str));
|
||||
INFO("test_case_false - decoded pci=%d %s crc=%s", pci, str, pbch_msg_rx.crc ? "OK" : "KO");
|
||||
|
||||
// Assert PBCH message CRC is not okay
|
||||
TESTASSERT(!pbch_msg_rx.crc);
|
||||
|
||||
// Search
|
||||
srsran_ssb_search_res_t res = {};
|
||||
gettimeofday(&t[1], NULL);
|
||||
TESTASSERT(srsran_ssb_search(ssb, buffer, hf_len, &res) == SRSRAN_SUCCESS);
|
||||
gettimeofday(&t[2], NULL);
|
||||
get_time_interval(t);
|
||||
t_search_usec += t[0].tv_usec + t[0].tv_sec * 1000000UL;
|
||||
|
||||
// Print decoded PBCH message
|
||||
srsran_pbch_msg_info(&res.pbch_msg, str, sizeof(str));
|
||||
INFO("test_case_false - false found pci=%d %s crc=%s", res.N_id, str, res.pbch_msg.crc ? "OK" : "KO");
|
||||
|
||||
// Assert PBCH message CRC
|
||||
TESTASSERT(!res.pbch_msg.crc);
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
ERROR("Error in test case true: undefined division");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
INFO("test_case_false - %.1f usec/decode; %.1f usec/decode;",
|
||||
(double)t_decode_usec / (double)(count),
|
||||
(double)t_search_usec / (double)(count));
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = SRSRAN_ERROR;
|
||||
|
@ -257,7 +331,12 @@ int main(int argc, char** argv)
|
|||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (test_case_1(&ssb) != SRSRAN_SUCCESS) {
|
||||
if (test_case_true(&ssb) != SRSRAN_SUCCESS) {
|
||||
ERROR("test case failed");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (test_case_false(&ssb) != SRSRAN_SUCCESS) {
|
||||
ERROR("test case failed");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
|
|
@ -167,6 +167,26 @@ int test_generate_k_nas()
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int test_generate_k_gnb()
|
||||
{
|
||||
auto& logger = srslog::fetch_basic_logger("LOG", false);
|
||||
|
||||
as_key_t k_gnb_o;
|
||||
|
||||
as_key_t k_gnb = {0x49, 0x3a, 0x16, 0xc5, 0x8b, 0x77, 0xb6, 0x27, 0xfa, 0x3f, 0x1a, 0xc6, 0x34, 0x4c, 0x18, 0x30,
|
||||
0x39, 0xf0, 0x1b, 0xa0, 0xcb, 0x76, 0x36, 0xbb, 0xcc, 0xc4, 0x36, 0x5b, 0x02, 0x3b, 0xd5, 0x62};
|
||||
|
||||
as_key_t k_amf = {0xd6, 0x55, 0xf1, 0x61, 0x42, 0x03, 0x5d, 0x4d, 0x72, 0xca, 0x39, 0x58, 0x3d, 0x22, 0x8d, 0x2d,
|
||||
0xd2, 0xec, 0x0c, 0xa7, 0x92, 0x9a, 0xd0, 0x07, 0xf5, 0x3b, 0x38, 0x2d, 0x05, 0x54, 0x44, 0x05};
|
||||
|
||||
uint32_t nas_ul_count = 0;
|
||||
|
||||
TESTASSERT(srsran::security_generate_k_gnb(k_amf, nas_ul_count, k_gnb_o) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(k_gnb_o == k_gnb);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int test_generate_k_enb()
|
||||
{
|
||||
auto& logger = srslog::fetch_basic_logger("LOG", false);
|
||||
|
@ -442,7 +462,7 @@ int main(int argc, char** argv)
|
|||
TESTASSERT(test_generate_up_keys() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_generate_k_enb_star() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_generate_k_nh() == SRSRAN_SUCCESS);
|
||||
|
||||
TESTASSERT(test_generate_k_gnb() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_generate_res_star() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_generate_k_ausf() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(test_generate_k_seaf() == SRSRAN_SUCCESS);
|
||||
|
|
|
@ -270,6 +270,7 @@ private:
|
|||
|
||||
void
|
||||
set_state(s1ap_proc_id_t state, const erab_id_list& erabs_updated, const erab_item_list& erabs_failed_to_update);
|
||||
s1ap_proc_id_t get_state() const { return current_state; }
|
||||
|
||||
ue_ctxt_t ctxt = {};
|
||||
uint16_t stream_id = 1;
|
||||
|
|
|
@ -785,6 +785,14 @@ bool s1ap::handle_initialctxtsetuprequest(const init_context_setup_request_s& ms
|
|||
return false;
|
||||
}
|
||||
|
||||
if (u->get_state() == s1ap_proc_id_t::init_context_setup_request) {
|
||||
logger.warning("Initial Context Setup Request already in progress. Ignoring ICS request.");
|
||||
asn1::s1ap::cause_c cause;
|
||||
cause.set_protocol().value = cause_protocol_opts::msg_not_compatible_with_receiver_state;
|
||||
send_error_indication(cause, msg->enb_ue_s1ap_id.value.value, msg->mme_ue_s1ap_id.value.value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup UE ctxt in RRC
|
||||
if (not rrc->setup_ue_ctxt(u->ctxt.rnti, msg)) {
|
||||
return false;
|
||||
|
@ -1999,6 +2007,9 @@ s1ap::ue* s1ap::handle_s1apmsg_ue_id(uint32_t enb_id, uint32_t mme_id)
|
|||
ue* user_ptr = users.find_ue_enbid(enb_id);
|
||||
ue* user_mme_ptr = nullptr;
|
||||
cause_c cause;
|
||||
|
||||
logger.info("Checking UE S1 logical connection. eNB UE S1AP ID=%d, MME UE S1AP ID=%d", enb_id, mme_id);
|
||||
|
||||
if (user_ptr != nullptr) {
|
||||
if (user_ptr->ctxt.mme_ue_s1ap_id == mme_id) {
|
||||
// No ID inconsistency found
|
||||
|
|
|
@ -92,8 +92,8 @@ struct sched_nr_cell_cfg_t {
|
|||
uint32_t pci;
|
||||
uint32_t dl_cell_nof_prb;
|
||||
uint32_t ul_cell_nof_prb;
|
||||
asn1::copy_ptr<asn1::rrc_nr::dl_cfg_common_sib_s> dl_cfg_common;
|
||||
asn1::copy_ptr<asn1::rrc_nr::ul_cfg_common_sib_s> ul_cfg_common;
|
||||
asn1::rrc_nr::dl_cfg_common_sib_s dl_cfg_common;
|
||||
asn1::rrc_nr::ul_cfg_common_sib_s ul_cfg_common;
|
||||
srsran::optional<asn1::rrc_nr::tdd_ul_dl_cfg_common_s> tdd_ul_dl_cfg_common;
|
||||
ssb_positions_in_burst_t ssb_positions_in_burst;
|
||||
uint32_t ssb_periodicity_ms = 0;
|
||||
|
@ -107,8 +107,6 @@ struct sched_nr_cell_cfg_t {
|
|||
double dl_center_frequency_hz;
|
||||
double ul_center_frequency_hz;
|
||||
double ssb_center_freq_hz;
|
||||
uint32_t offset_to_carrier;
|
||||
srsran_subcarrier_spacing_t scs;
|
||||
};
|
||||
|
||||
class sched_nr_interface
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
namespace srsenb {
|
||||
|
||||
class enb_bearer_manager;
|
||||
class du_config_manager;
|
||||
|
||||
enum class rrc_nr_state_t { RRC_IDLE, RRC_INACTIVE, RRC_CONNECTED };
|
||||
|
||||
|
@ -151,8 +152,8 @@ private:
|
|||
asn1::rrc_nr::sp_cell_cfg_s base_sp_cell_cfg;
|
||||
|
||||
// vars
|
||||
std::unique_ptr<du_config_manager> du_cfg;
|
||||
struct cell_ctxt_t {
|
||||
asn1::rrc_nr::mib_s mib;
|
||||
asn1::rrc_nr::sib1_s sib1;
|
||||
asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_l_ sibs;
|
||||
srsran::unique_byte_buffer_t mib_buffer = nullptr;
|
||||
|
|
|
@ -47,11 +47,13 @@ struct rrc_cell_cfg_nr_t {
|
|||
uint32_t ul_arfcn; // UL freq also in phy_cell
|
||||
uint32_t dl_absolute_freq_point_a; // derived from DL ARFCN
|
||||
uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN
|
||||
uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn)
|
||||
uint32_t band;
|
||||
uint32_t coreset0_idx; // Table 13-{1,...15} row index
|
||||
srsran_duplex_mode_t duplex_mode;
|
||||
srsran_ssb_cfg_t ssb_cfg;
|
||||
double ssb_freq_hz;
|
||||
uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn)
|
||||
srsran_subcarrier_spacing_t ssb_scs;
|
||||
srsran_ssb_patern_t ssb_pattern;
|
||||
};
|
||||
|
||||
typedef std::vector<rrc_cell_cfg_nr_t> rrc_cell_list_nr_t;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 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 SRSRAN_RRC_NR_DU_MANAGER_H
|
||||
#define SRSRAN_RRC_NR_DU_MANAGER_H
|
||||
|
||||
#include "rrc_nr_config.h"
|
||||
#include "srsgnb/hdr/stack/mac/sched_nr_interface.h"
|
||||
#include "srsran/asn1/rrc_nr.h"
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
class du_cell_config
|
||||
{
|
||||
public:
|
||||
uint32_t cc;
|
||||
uint32_t pci;
|
||||
|
||||
asn1::rrc_nr::mib_s mib;
|
||||
srsran::unique_byte_buffer_t packed_mib;
|
||||
|
||||
asn1::rrc_nr::sib1_s sib1;
|
||||
srsran::unique_byte_buffer_t packed_sib1;
|
||||
|
||||
const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg_common() const
|
||||
{
|
||||
return sib1.serving_cell_cfg_common;
|
||||
}
|
||||
|
||||
/// SI messages (index=0 for SIB1)
|
||||
srsran::const_byte_span packed_si_msg(uint32_t idx) { return srsran::make_span(packed_sib1); }
|
||||
size_t nof_si_msgs() const { return 1; }
|
||||
};
|
||||
|
||||
class du_config_manager
|
||||
{
|
||||
public:
|
||||
explicit du_config_manager(const rrc_nr_cfg_t& cfg);
|
||||
~du_config_manager();
|
||||
|
||||
const rrc_nr_cfg_t& cfg;
|
||||
|
||||
int add_cell();
|
||||
|
||||
const du_cell_config& cell(uint32_t cc) const
|
||||
{
|
||||
srsran_assert(cc < cells.size(), "Unknown DU Cell Index=%d", cc);
|
||||
return *cells[cc];
|
||||
}
|
||||
|
||||
private:
|
||||
srslog::basic_logger& logger;
|
||||
|
||||
std::vector<std::unique_ptr<du_cell_config> > cells;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSRAN_RRC_NR_DU_MANAGER_H
|
|
@ -117,6 +117,9 @@ private:
|
|||
/// Update MAC based on ASN1 message
|
||||
int update_mac(const asn1::rrc_nr::cell_group_cfg_s& cell_group_config, bool is_config_complete);
|
||||
|
||||
/// Update AS security config on active RB
|
||||
int update_as_security(uint32_t lcid, bool enable_integrity, bool enable_ciphering);
|
||||
|
||||
int pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfig);
|
||||
int pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_secondary_cell_config);
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ public:
|
|||
for (ue_event_t& ev : current_slot_ue_events) {
|
||||
auto ue_it = ues.find(ev.rnti);
|
||||
if (ue_it == ues.end()) {
|
||||
sched_logger.warning("SCHED: \"%s\" called for inexistent rnti=0x%x.", ev.event_name, ev.rnti);
|
||||
sched_logger.warning("SCHED: \"%s\" called for unknown rnti=0x%x.", ev.event_name, ev.rnti);
|
||||
ev.rnti = SRSRAN_INVALID_RNTI;
|
||||
} else if (ue_it->second->has_ca()) {
|
||||
// events specific to existing UEs with CA
|
||||
|
@ -161,7 +161,7 @@ public:
|
|||
}
|
||||
auto ue_it = ues.find(ev.rnti);
|
||||
if (ue_it == ues.end()) {
|
||||
sched_logger.warning("SCHED: \"%s\" called for inexistent rnti=0x%x.", ev.event_name, ev.rnti);
|
||||
sched_logger.warning("SCHED: \"%s\" called for unknown rnti=0x%x.", ev.event_name, ev.rnti);
|
||||
ev.rnti = SRSRAN_INVALID_RNTI;
|
||||
} else if (not ue_it->second->has_ca() and ue_it->second->carriers[cc] != nullptr) {
|
||||
ev.callback(*ue_it->second, evlogger);
|
||||
|
@ -174,7 +174,7 @@ public:
|
|||
if (ue_it != ues.end() and ue_it->second->carriers[cc] != nullptr) {
|
||||
ev.callback(*ue_it->second->carriers[cc], evlogger);
|
||||
} else {
|
||||
sched_logger.warning("SCHED: \"%s\" called for inexistent rnti=0x%x,cc=%d.", ev.event_name, ev.rnti, ev.cc);
|
||||
sched_logger.warning("SCHED: \"%s\" called for unknown rnti=0x%x,cc=%d.", ev.event_name, ev.rnti, ev.cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,15 +149,11 @@ cell_config_manager::cell_config_manager(uint32_t cc_,
|
|||
carrier.dl_center_frequency_hz = cell.dl_center_frequency_hz;
|
||||
carrier.ul_center_frequency_hz = cell.ul_center_frequency_hz;
|
||||
carrier.ssb_center_freq_hz = cell.ssb_center_freq_hz;
|
||||
carrier.offset_to_carrier = cell.offset_to_carrier;
|
||||
carrier.scs = cell.scs;
|
||||
carrier.nof_prb = cell.dl_cell_nof_prb;
|
||||
carrier.start = 0; // TODO: Check
|
||||
carrier.max_mimo_layers = cell.nof_layers;
|
||||
if (cell.dl_cfg_common.is_present()) {
|
||||
carrier.offset_to_carrier = cell.dl_cfg_common->freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier;
|
||||
carrier.scs = (srsran_subcarrier_spacing_t)cell.dl_cfg_common->init_dl_bwp.generic_params.subcarrier_spacing.value;
|
||||
}
|
||||
carrier.offset_to_carrier = cell.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier;
|
||||
carrier.scs = (srsran_subcarrier_spacing_t)cell.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value;
|
||||
|
||||
// TDD-UL-DL-ConfigCommon
|
||||
duplex.mode = SRSRAN_DUPLEX_MODE_FDD;
|
||||
|
|
|
@ -35,7 +35,7 @@ uint32_t coreset_nof_cces(const srsran_coreset_t& coreset)
|
|||
void make_mib_cfg(const sched_nr_cell_cfg_t& cfg, srsran_mib_nr_t* mib)
|
||||
{
|
||||
*mib = {};
|
||||
mib->scs_common = cfg.scs;
|
||||
mib->scs_common = (srsran_subcarrier_spacing_t)cfg.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value;
|
||||
mib->ssb_offset = 6; // TODO
|
||||
mib->dmrs_typeA_pos = (srsran_dmrs_sch_typeA_pos_t)cfg.dmrs_type_a_position.value;
|
||||
mib->coreset0_idx = cfg.pdcch_cfg_sib1.ctrl_res_set_zero;
|
||||
|
@ -62,14 +62,12 @@ void make_ssb_cfg(const sched_nr_cell_cfg_t& cfg, srsran::phy_cfg_nr_t::ssb_cfg_
|
|||
}
|
||||
ssb->scs = (srsran_subcarrier_spacing_t)cfg.ssb_scs.value;
|
||||
ssb->pattern = SRSRAN_SSB_PATTERN_A;
|
||||
if (cfg.dl_cfg_common.is_present()) {
|
||||
if (cfg.dl_cfg_common->freq_info_dl.freq_band_list.size() > 0 and
|
||||
cfg.dl_cfg_common->freq_info_dl.freq_band_list[0].freq_band_ind_nr_present) {
|
||||
uint32_t band = cfg.dl_cfg_common->freq_info_dl.freq_band_list[0].freq_band_ind_nr;
|
||||
if (cfg.dl_cfg_common.freq_info_dl.freq_band_list.size() > 0 and
|
||||
cfg.dl_cfg_common.freq_info_dl.freq_band_list[0].freq_band_ind_nr_present) {
|
||||
uint32_t band = cfg.dl_cfg_common.freq_info_dl.freq_band_list[0].freq_band_ind_nr;
|
||||
ssb->pattern = srsran::srsran_band_helper::get_ssb_pattern(band, ssb->scs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srsran::phy_cfg_nr_t get_common_ue_phy_cfg(const sched_nr_cell_cfg_t& cfg)
|
||||
{
|
||||
|
@ -93,8 +91,9 @@ srsran::phy_cfg_nr_t get_common_ue_phy_cfg(const sched_nr_cell_cfg_t& cfg)
|
|||
ue_phy_cfg.carrier.dl_center_frequency_hz = cfg.dl_center_frequency_hz;
|
||||
ue_phy_cfg.carrier.ul_center_frequency_hz = cfg.ul_center_frequency_hz;
|
||||
ue_phy_cfg.carrier.ssb_center_freq_hz = cfg.ssb_center_freq_hz;
|
||||
ue_phy_cfg.carrier.offset_to_carrier = cfg.offset_to_carrier;
|
||||
ue_phy_cfg.carrier.scs = cfg.scs;
|
||||
ue_phy_cfg.carrier.offset_to_carrier = cfg.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier;
|
||||
ue_phy_cfg.carrier.scs =
|
||||
(srsran_subcarrier_spacing_t)cfg.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value;
|
||||
ue_phy_cfg.carrier.nof_prb = cfg.dl_cell_nof_prb;
|
||||
ue_phy_cfg.carrier.max_mimo_layers = cfg.nof_layers;
|
||||
make_ssb_cfg(cfg, &ue_phy_cfg.ssb);
|
||||
|
|
|
@ -235,7 +235,7 @@ void ue::new_slot(slot_point pdcch_slot)
|
|||
|
||||
slot_ue ue::make_slot_ue(slot_point pdcch_slot, uint32_t cc)
|
||||
{
|
||||
srsran_assert(carriers[cc] != nullptr, "make_slot_ue() called for inexistent rnti=0x%x,cc=%d", rnti, cc);
|
||||
srsran_assert(carriers[cc] != nullptr, "make_slot_ue() called for unknown rnti=0x%x,cc=%d", rnti, cc);
|
||||
return slot_ue(*carriers[cc], pdcch_slot);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,8 +62,13 @@ inline sched_nr_cell_cfg_t get_default_cell_cfg(const srsran::phy_cfg_nr_t& phy_
|
|||
cell_cfg.dl_center_frequency_hz = phy_cfg.carrier.dl_center_frequency_hz;
|
||||
cell_cfg.ul_center_frequency_hz = phy_cfg.carrier.ul_center_frequency_hz;
|
||||
cell_cfg.ssb_center_freq_hz = phy_cfg.carrier.ssb_center_freq_hz;
|
||||
cell_cfg.offset_to_carrier = phy_cfg.carrier.offset_to_carrier;
|
||||
cell_cfg.scs = phy_cfg.carrier.scs;
|
||||
cell_cfg.dl_cfg_common.freq_info_dl.scs_specific_carrier_list.resize(1);
|
||||
cell_cfg.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing =
|
||||
(asn1::rrc_nr::subcarrier_spacing_opts::options)phy_cfg.carrier.scs;
|
||||
cell_cfg.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier =
|
||||
phy_cfg.carrier.offset_to_carrier;
|
||||
cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing =
|
||||
(asn1::rrc_nr::subcarrier_spacing_opts::options)phy_cfg.carrier.scs;
|
||||
cell_cfg.dl_cell_nof_prb = phy_cfg.carrier.nof_prb;
|
||||
cell_cfg.nof_layers = phy_cfg.carrier.max_mimo_layers;
|
||||
cell_cfg.ssb_periodicity_ms = phy_cfg.ssb.periodicity_ms;
|
||||
|
|
|
@ -22,7 +22,7 @@ set(SOURCES rrc_nr_config_utils.cc)
|
|||
add_library(srsgnb_rrc_config_utils STATIC ${SOURCES})
|
||||
target_link_libraries(srsgnb_rrc_config_utils srsran_phy)
|
||||
|
||||
set(SOURCES rrc_nr.cc rrc_nr_ue.cc rrc_nr_security_context.cc cell_asn1_config.cc)
|
||||
set(SOURCES rrc_nr.cc rrc_nr_ue.cc rrc_nr_security_context.cc cell_asn1_config.cc rrc_nr_du_manager.cc)
|
||||
add_library(srsgnb_rrc STATIC ${SOURCES})
|
||||
target_link_libraries(srsgnb_rrc srsgnb_rrc_config_utils)
|
||||
|
||||
|
|
|
@ -131,6 +131,18 @@ void set_rach_cfg_common(const srsran_prach_cfg_t& prach_cfg, asn1::rrc_nr::rach
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void fill_tdd_ul_dl_config_common(const rrc_cell_cfg_nr_t& cfg, asn1::rrc_nr::tdd_ul_dl_cfg_common_s& tdd)
|
||||
{
|
||||
srsran_assert(cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD, "This function should only be called for TDD configs");
|
||||
// TDD UL-DL config
|
||||
tdd.ref_subcarrier_spacing.value = (asn1::rrc_nr::subcarrier_spacing_opts::options)cfg.phy_cell.carrier.scs;
|
||||
tdd.pattern1.dl_ul_tx_periodicity = asn1::rrc_nr::tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10;
|
||||
tdd.pattern1.nrof_dl_slots = 6;
|
||||
tdd.pattern1.nrof_dl_symbols = 0;
|
||||
tdd.pattern1.nrof_ul_slots = 4;
|
||||
tdd.pattern1.nrof_ul_symbols = 0;
|
||||
}
|
||||
|
||||
/// Fill list of CSI-ReportConfig with gNB config
|
||||
int fill_csi_report_from_enb_cfg(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_meas_cfg)
|
||||
{
|
||||
|
@ -174,7 +186,7 @@ int fill_csi_report_from_enb_cfg(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_me
|
|||
csi_report.subband_size = asn1::rrc_nr::csi_report_cfg_s::subband_size_opts::value1;
|
||||
|
||||
if (cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_FDD) {
|
||||
csi_report.report_cfg_type.periodic().report_slot_cfg.slots80() = 9;
|
||||
csi_report.report_cfg_type.periodic().report_slot_cfg.slots80() = 1;
|
||||
} else {
|
||||
csi_report.report_cfg_type.periodic().report_slot_cfg.slots80() = 7;
|
||||
}
|
||||
|
@ -224,11 +236,11 @@ void fill_nzp_csi_rs_from_enb_cfg(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_m
|
|||
auto& nzp_csi_res = csi_meas_cfg.nzp_csi_rs_res_to_add_mod_list;
|
||||
// item 0
|
||||
nzp_csi_res[0].nzp_csi_rs_res_id = 0;
|
||||
nzp_csi_res[0].res_map.freq_domain_alloc.set_other();
|
||||
nzp_csi_res[0].res_map.freq_domain_alloc.other().from_number(0b100000);
|
||||
nzp_csi_res[0].res_map.nrof_ports.value = asn1::rrc_nr::csi_rs_res_map_s::nrof_ports_opts::p2;
|
||||
nzp_csi_res[0].res_map.freq_domain_alloc.set_row2();
|
||||
nzp_csi_res[0].res_map.freq_domain_alloc.row2().from_number(0x800);
|
||||
nzp_csi_res[0].res_map.nrof_ports.value = asn1::rrc_nr::csi_rs_res_map_s::nrof_ports_opts::p1;
|
||||
nzp_csi_res[0].res_map.first_ofdm_symbol_in_time_domain = 4;
|
||||
nzp_csi_res[0].res_map.cdm_type.value = asn1::rrc_nr::csi_rs_res_map_s::cdm_type_opts::fd_cdm2;
|
||||
nzp_csi_res[0].res_map.cdm_type.value = asn1::rrc_nr::csi_rs_res_map_s::cdm_type_opts::no_cdm;
|
||||
nzp_csi_res[0].res_map.density.set_one();
|
||||
nzp_csi_res[0].res_map.freq_band.start_rb = 0;
|
||||
nzp_csi_res[0].res_map.freq_band.nrof_rbs = 52;
|
||||
|
@ -246,7 +258,7 @@ void fill_nzp_csi_rs_from_enb_cfg(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_m
|
|||
nzp_csi_res[1] = nzp_csi_res[0];
|
||||
nzp_csi_res[1].nzp_csi_rs_res_id = 1;
|
||||
nzp_csi_res[1].res_map.freq_domain_alloc.set_row1();
|
||||
nzp_csi_res[1].res_map.freq_domain_alloc.row1().from_number(0b0001);
|
||||
nzp_csi_res[1].res_map.freq_domain_alloc.row1().from_number(0x1);
|
||||
nzp_csi_res[1].res_map.nrof_ports.value = asn1::rrc_nr::csi_rs_res_map_s::nrof_ports_opts::p1;
|
||||
nzp_csi_res[1].res_map.cdm_type.value = asn1::rrc_nr::csi_rs_res_map_s::cdm_type_opts::no_cdm;
|
||||
nzp_csi_res[1].res_map.density.set_three();
|
||||
|
@ -425,8 +437,8 @@ void fill_csi_resource_cfg_to_add(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_m
|
|||
csi_meas_cfg.csi_res_cfg_to_add_mod_list[0].res_type.value = csi_res_cfg_s::res_type_opts::periodic;
|
||||
|
||||
csi_meas_cfg.csi_res_cfg_to_add_mod_list[1].csi_res_cfg_id = 1;
|
||||
auto& imres = csi_meas_cfg.csi_res_cfg_to_add_mod_list[1].csi_rs_res_set_list.set_csi_im_res_set_list();
|
||||
imres.push_back(0);
|
||||
auto& im_res = csi_meas_cfg.csi_res_cfg_to_add_mod_list[1].csi_rs_res_set_list.set_csi_im_res_set_list();
|
||||
im_res.push_back(0);
|
||||
csi_meas_cfg.csi_res_cfg_to_add_mod_list[1].bwp_id = 0;
|
||||
csi_meas_cfg.csi_res_cfg_to_add_mod_list[1].res_type.value = csi_res_cfg_s::res_type_opts::periodic;
|
||||
|
||||
|
@ -603,10 +615,10 @@ void fill_pucch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pucch_cfg
|
|||
uint32_t j = 0, j2 = 0;
|
||||
for (uint32_t i = 0; i < out.res_to_add_mod_list.size(); ++i) {
|
||||
out.res_to_add_mod_list[i].pucch_res_id = i;
|
||||
out.res_to_add_mod_list[i].intra_slot_freq_hop_present = true;
|
||||
out.res_to_add_mod_list[i].second_hop_prb_present = true;
|
||||
out.res_to_add_mod_list[i].intra_slot_freq_hop_present = false;
|
||||
if (i < 8 or i == 16) {
|
||||
out.res_to_add_mod_list[i].start_prb = 51;
|
||||
out.res_to_add_mod_list[i].second_hop_prb_present = true;
|
||||
out.res_to_add_mod_list[i].second_hop_prb = 0;
|
||||
out.res_to_add_mod_list[i].format.set_format1().init_cyclic_shift = (4 * (j % 3));
|
||||
out.res_to_add_mod_list[i].format.format1().nrof_symbols = 14;
|
||||
|
@ -615,6 +627,7 @@ void fill_pucch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pucch_cfg
|
|||
j++;
|
||||
} else if (i < 15) {
|
||||
out.res_to_add_mod_list[i].start_prb = 1;
|
||||
out.res_to_add_mod_list[i].second_hop_prb_present = true;
|
||||
out.res_to_add_mod_list[i].second_hop_prb = 50;
|
||||
out.res_to_add_mod_list[i].format.set_format2().nrof_prbs = 1;
|
||||
out.res_to_add_mod_list[i].format.format2().nrof_symbols = 2;
|
||||
|
@ -622,6 +635,7 @@ void fill_pucch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pucch_cfg
|
|||
j2++;
|
||||
} else {
|
||||
out.res_to_add_mod_list[i].start_prb = 50;
|
||||
out.res_to_add_mod_list[i].second_hop_prb_present = true;
|
||||
out.res_to_add_mod_list[i].second_hop_prb = 1;
|
||||
out.res_to_add_mod_list[i].format.set_format2().nrof_prbs = 1;
|
||||
out.res_to_add_mod_list[i].format.format2().nrof_symbols = 2;
|
||||
|
@ -637,6 +651,9 @@ void fill_pucch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pucch_cfg
|
|||
out.format2.set_setup();
|
||||
out.format2.setup().max_code_rate_present = true;
|
||||
out.format2.setup().max_code_rate = pucch_max_code_rate_opts::zero_dot25;
|
||||
// NOTE: IMPORTANT!! The gNB expects the CSI to be reported along with HARQ-ACK
|
||||
// If simul_harq_ack_csi_present = false, PUCCH might not be decoded properly when CSI is reported
|
||||
out.format2.setup().simul_harq_ack_csi_present = true;
|
||||
|
||||
// SR resources
|
||||
out.sched_request_res_to_add_mod_list.resize(1);
|
||||
|
@ -865,18 +882,15 @@ int fill_serv_cell_common_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, ser
|
|||
|
||||
serv_common.ss_pbch_block_pwr = cell_cfg.phy_cell.pdsch.rs_power;
|
||||
serv_common.n_timing_advance_offset_present = true;
|
||||
serv_common.n_timing_advance_offset = asn1::rrc_nr::serving_cell_cfg_common_s::n_timing_advance_offset_opts::n0;
|
||||
serv_common.n_timing_advance_offset = serving_cell_cfg_common_s::n_timing_advance_offset_opts::n0;
|
||||
serv_common.n_timing_advance_offset_present = true;
|
||||
serv_common.dmrs_type_a_position = asn1::rrc_nr::serving_cell_cfg_common_s::dmrs_type_a_position_opts::pos2;
|
||||
serv_common.dmrs_type_a_position = serving_cell_cfg_common_s::dmrs_type_a_position_opts::pos2;
|
||||
|
||||
serv_common.pci_present = true;
|
||||
serv_common.pci = cell_cfg.phy_cell.carrier.pci;
|
||||
|
||||
serv_common.ssb_periodicity_serving_cell_present = true;
|
||||
if (not asn1::number_to_enum(serv_common.ssb_periodicity_serving_cell, cell_cfg.ssb_cfg.periodicity_ms)) {
|
||||
get_logger(cfg).error("Config Error: Invalid SSB periodicity = %d\n", cell_cfg.ssb_cfg.periodicity_ms);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
serv_common.ssb_periodicity_serving_cell.value = serving_cell_cfg_common_s::ssb_periodicity_serving_cell_opts::ms10;
|
||||
|
||||
// Fill SSB config
|
||||
serv_common.ssb_positions_in_burst_present = true;
|
||||
|
@ -897,13 +911,7 @@ int fill_serv_cell_common_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, ser
|
|||
if (cfg.cell_list[cc].duplex_mode == SRSRAN_DUPLEX_MODE_TDD) {
|
||||
// TDD UL-DL config
|
||||
serv_common.tdd_ul_dl_cfg_common_present = true;
|
||||
auto& tdd_config = serv_common.tdd_ul_dl_cfg_common;
|
||||
tdd_config.ref_subcarrier_spacing = subcarrier_spacing_e::khz15;
|
||||
tdd_config.pattern1.dl_ul_tx_periodicity = asn1::rrc_nr::tdd_ul_dl_pattern_s::dl_ul_tx_periodicity_opts::ms10;
|
||||
tdd_config.pattern1.nrof_dl_slots = 6;
|
||||
tdd_config.pattern1.nrof_dl_symbols = 0;
|
||||
tdd_config.pattern1.nrof_ul_slots = 4;
|
||||
tdd_config.pattern1.nrof_ul_symbols = 0;
|
||||
fill_tdd_ul_dl_config_common(cfg.cell_list[cc], serv_common.tdd_ul_dl_cfg_common);
|
||||
}
|
||||
|
||||
serv_common.ul_cfg_common_present = true;
|
||||
|
@ -1057,9 +1065,6 @@ int fill_master_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1
|
|||
fill_sp_cell_cfg_from_enb_cfg(cfg, cc, out.sp_cell_cfg);
|
||||
out.sp_cell_cfg.recfg_with_sync_present = false;
|
||||
|
||||
// The current CSI config make the PUCCH decoding fail. We temporarily disable it until further investigation
|
||||
out.sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present = false;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1139,12 +1144,12 @@ void fill_dl_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, dl_cfg_common_sib
|
|||
cfg.freq_info_dl.freq_band_list.resize(1);
|
||||
cfg.freq_info_dl.freq_band_list[0].freq_band_ind_nr_present = true;
|
||||
cfg.freq_info_dl.freq_band_list[0].freq_band_ind_nr = cell_cfg.band;
|
||||
double ssb_freq_start = cell_cfg.ssb_cfg.ssb_freq_hz - SRSRAN_SSB_BW_SUBC * scs_hz / 2;
|
||||
double ssb_freq_start = cell_cfg.ssb_freq_hz - SRSRAN_SSB_BW_SUBC * scs_hz / 2;
|
||||
double offset_point_a_hz = ssb_freq_start - band_helper.nr_arfcn_to_freq(cell_cfg.dl_absolute_freq_point_a);
|
||||
uint32_t offset_point_a_prbs = offset_point_a_hz / prb_bw;
|
||||
cfg.freq_info_dl.offset_to_point_a = offset_point_a_prbs;
|
||||
cfg.freq_info_dl.scs_specific_carrier_list.resize(1);
|
||||
cfg.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier = 0;
|
||||
cfg.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier = cell_cfg.phy_cell.carrier.offset_to_carrier;
|
||||
cfg.freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing =
|
||||
(subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs;
|
||||
cfg.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb;
|
||||
|
@ -1174,7 +1179,7 @@ void fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib
|
|||
band_helper.get_abs_freq_point_a_arfcn(cell_cfg.phy_cell.carrier.nof_prb, cell_cfg.ul_arfcn);
|
||||
|
||||
cfg.freq_info_ul.scs_specific_carrier_list.resize(1);
|
||||
cfg.freq_info_ul.scs_specific_carrier_list[0].offset_to_carrier = 0;
|
||||
cfg.freq_info_ul.scs_specific_carrier_list[0].offset_to_carrier = cell_cfg.phy_cell.carrier.offset_to_carrier;
|
||||
cfg.freq_info_ul.scs_specific_carrier_list[0].subcarrier_spacing =
|
||||
(subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs;
|
||||
cfg.freq_info_ul.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb;
|
||||
|
@ -1210,7 +1215,7 @@ void fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib
|
|||
cfg.time_align_timer_common.value = time_align_timer_opts::infinity;
|
||||
}
|
||||
|
||||
void fill_serv_cell_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, serving_cell_cfg_common_sib_s& cfg)
|
||||
int fill_serv_cell_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, serving_cell_cfg_common_sib_s& cfg)
|
||||
{
|
||||
fill_dl_cfg_common_sib(cell_cfg, cfg.dl_cfg_common);
|
||||
|
||||
|
@ -1219,9 +1224,21 @@ void fill_serv_cell_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, serving_ce
|
|||
|
||||
cfg.ssb_positions_in_burst.in_one_group.from_number(0x80);
|
||||
|
||||
cfg.ssb_periodicity_serving_cell.value = serving_cell_cfg_common_sib_s::ssb_periodicity_serving_cell_opts::ms20;
|
||||
cfg.ssb_periodicity_serving_cell.value = serving_cell_cfg_common_sib_s::ssb_periodicity_serving_cell_opts::ms10;
|
||||
|
||||
// The time advance offset is not supported by the current PHY
|
||||
cfg.n_timing_advance_offset_present = true;
|
||||
cfg.n_timing_advance_offset = serving_cell_cfg_common_sib_s::n_timing_advance_offset_opts::n0;
|
||||
|
||||
// TDD UL-DL config
|
||||
if (cell_cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD) {
|
||||
cfg.tdd_ul_dl_cfg_common_present = true;
|
||||
fill_tdd_ul_dl_config_common(cell_cfg, cfg.tdd_ul_dl_cfg_common);
|
||||
}
|
||||
|
||||
cfg.ss_pbch_block_pwr = cell_cfg.phy_cell.pdsch.rs_power;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::sib1_s& sib1)
|
||||
|
@ -1266,7 +1283,7 @@ int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::s
|
|||
// sib1.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag = 0;
|
||||
|
||||
sib1.serving_cell_cfg_common_present = true;
|
||||
fill_serv_cell_cfg_common_sib(cell_cfg, sib1.serving_cell_cfg_common);
|
||||
HANDLE_ERROR(fill_serv_cell_cfg_common_sib(cell_cfg, sib1.serving_cell_cfg_common));
|
||||
|
||||
sib1.ue_timers_and_consts_present = true;
|
||||
sib1.ue_timers_and_consts.t300.value = ue_timers_and_consts_s::t300_opts::ms1000;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "srsenb/hdr/common/common_enb.h"
|
||||
#include "srsgnb/hdr/stack/rrc/cell_asn1_config.h"
|
||||
#include "srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h"
|
||||
#include "srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h"
|
||||
#include "srsgnb/hdr/stack/rrc/rrc_nr_ue.h"
|
||||
#include "srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h"
|
||||
#include "srsran/asn1/rrc_nr_utils.h"
|
||||
|
@ -77,6 +78,11 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
|
|||
cell.ssb_absolute_freq_point);
|
||||
}
|
||||
|
||||
du_cfg = std::make_unique<du_config_manager>(cfg);
|
||||
for (uint32_t i = 0; i < cfg.cell_list.size(); ++i) {
|
||||
du_cfg->add_cell();
|
||||
}
|
||||
|
||||
// Generate cell config structs
|
||||
cell_ctxt.reset(new cell_ctxt_t{});
|
||||
if (cfg.is_standalone) {
|
||||
|
@ -98,13 +104,13 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_,
|
|||
int ret = fill_sp_cell_cfg_from_enb_cfg(cfg, UE_PSCELL_CC_IDX, base_sp_cell_cfg);
|
||||
srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure cell");
|
||||
|
||||
pdcch_cfg_common_s* asn1_pdcch;
|
||||
const pdcch_cfg_common_s* asn1_pdcch;
|
||||
if (not cfg.is_standalone) {
|
||||
// Fill rrc_nr_cfg with UE-specific search spaces and coresets
|
||||
asn1_pdcch =
|
||||
&base_sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup();
|
||||
} else {
|
||||
asn1_pdcch = &cell_ctxt->sib1.serving_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup();
|
||||
asn1_pdcch = &du_cfg->cell(0).serv_cell_cfg_common().dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup();
|
||||
}
|
||||
srsran_assert(check_nr_phy_cell_cfg_valid(cfg.cell_list[0].phy_cell) == SRSRAN_SUCCESS, "Invalid PhyCell Config");
|
||||
|
||||
|
@ -293,7 +299,13 @@ void rrc_nr::config_phy()
|
|||
common_cfg.pdcch = cfg.cell_list[0].phy_cell.pdcch;
|
||||
common_cfg.prach = cfg.cell_list[0].phy_cell.prach;
|
||||
common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode;
|
||||
common_cfg.ssb = cfg.cell_list[0].ssb_cfg;
|
||||
common_cfg.ssb = {};
|
||||
common_cfg.ssb.center_freq_hz = cfg.cell_list[0].phy_cell.dl_freq_hz;
|
||||
common_cfg.ssb.ssb_freq_hz = cfg.cell_list[0].ssb_freq_hz;
|
||||
common_cfg.ssb.scs = cfg.cell_list[0].ssb_scs;
|
||||
common_cfg.ssb.pattern = cfg.cell_list[0].ssb_pattern;
|
||||
common_cfg.ssb.duplex_mode = cfg.cell_list[0].duplex_mode;
|
||||
common_cfg.ssb.periodicity_ms = du_cfg->cell(0).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number();
|
||||
if (phy->set_common_cfg(common_cfg) < SRSRAN_SUCCESS) {
|
||||
logger.error("Couldn't set common PHY config");
|
||||
return;
|
||||
|
@ -302,54 +314,48 @@ void rrc_nr::config_phy()
|
|||
|
||||
void rrc_nr::config_mac()
|
||||
{
|
||||
uint32_t cc = 0;
|
||||
// Fill MAC scheduler configuration for SIBs
|
||||
// TODO: use parsed cell NR cfg configuration
|
||||
srsran::phy_cfg_nr_default_t::reference_cfg_t ref_args{};
|
||||
ref_args.duplex = cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_TDD
|
||||
ref_args.duplex = cfg.cell_list[cc].duplex_mode == SRSRAN_DUPLEX_MODE_TDD
|
||||
? srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_TDD_CUSTOM_6_4
|
||||
: srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_FDD;
|
||||
std::vector<sched_nr_cell_cfg_t> sched_cells_cfg(1, get_default_cell_cfg(srsran::phy_cfg_nr_default_t{ref_args}));
|
||||
sched_nr_cell_cfg_t& cell = sched_cells_cfg[0];
|
||||
sched_nr_cell_cfg_t& cell = sched_cells_cfg[cc];
|
||||
|
||||
// Derive cell config from rrc_nr_cfg_t
|
||||
cell.bwps[0].pdcch = cfg.cell_list[0].phy_cell.pdcch;
|
||||
cell.pci = cfg.cell_list[0].phy_cell.carrier.pci;
|
||||
cell.nof_layers = cfg.cell_list[0].phy_cell.carrier.max_mimo_layers;
|
||||
cell.dl_cell_nof_prb = cfg.cell_list[0].phy_cell.carrier.nof_prb;
|
||||
cell.ul_cell_nof_prb = cfg.cell_list[0].phy_cell.carrier.nof_prb;
|
||||
cell.dl_center_frequency_hz = cfg.cell_list[0].phy_cell.carrier.dl_center_frequency_hz;
|
||||
cell.ul_center_frequency_hz = cfg.cell_list[0].phy_cell.carrier.ul_center_frequency_hz;
|
||||
cell.ssb_center_freq_hz = cfg.cell_list[0].phy_cell.carrier.ssb_center_freq_hz;
|
||||
cell.offset_to_carrier = cfg.cell_list[0].phy_cell.carrier.offset_to_carrier;
|
||||
cell.scs = cfg.cell_list[0].phy_cell.carrier.scs;
|
||||
cell.bwps[0].pdcch = cfg.cell_list[cc].phy_cell.pdcch;
|
||||
cell.pci = cfg.cell_list[cc].phy_cell.carrier.pci;
|
||||
cell.nof_layers = cfg.cell_list[cc].phy_cell.carrier.max_mimo_layers;
|
||||
cell.dl_cell_nof_prb = cfg.cell_list[cc].phy_cell.carrier.nof_prb;
|
||||
cell.ul_cell_nof_prb = cfg.cell_list[cc].phy_cell.carrier.nof_prb;
|
||||
cell.dl_center_frequency_hz = cfg.cell_list[cc].phy_cell.carrier.dl_center_frequency_hz;
|
||||
cell.ul_center_frequency_hz = cfg.cell_list[cc].phy_cell.carrier.ul_center_frequency_hz;
|
||||
cell.ssb_center_freq_hz = cfg.cell_list[cc].phy_cell.carrier.ssb_center_freq_hz;
|
||||
cell.dmrs_type_a_position = du_cfg->cell(cc).mib.dmrs_type_a_position;
|
||||
cell.pdcch_cfg_sib1 = du_cfg->cell(cc).mib.pdcch_cfg_sib1;
|
||||
if (du_cfg->cell(cc).serv_cell_cfg_common().tdd_ul_dl_cfg_common_present) {
|
||||
cell.tdd_ul_dl_cfg_common.emplace(du_cfg->cell(cc).serv_cell_cfg_common().tdd_ul_dl_cfg_common);
|
||||
}
|
||||
cell.dl_cfg_common = du_cfg->cell(cc).serv_cell_cfg_common().dl_cfg_common;
|
||||
cell.ul_cfg_common = du_cfg->cell(cc).serv_cell_cfg_common().ul_cfg_common;
|
||||
cell.ss_pbch_block_power = du_cfg->cell(cc).serv_cell_cfg_common().ss_pbch_block_pwr;
|
||||
if (not cfg.is_standalone) {
|
||||
const serving_cell_cfg_common_s& serv_cell = base_sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common;
|
||||
// Derive cell config from ASN1
|
||||
bool valid_cfg = srsran::make_pdsch_cfg_from_serv_cell(base_sp_cell_cfg.sp_cell_cfg_ded, &cell.bwps[0].pdsch);
|
||||
srsran_assert(valid_cfg, "Invalid NR cell configuration.");
|
||||
if (serv_cell.tdd_ul_dl_cfg_common_present) {
|
||||
cell.tdd_ul_dl_cfg_common.emplace(serv_cell.tdd_ul_dl_cfg_common);
|
||||
}
|
||||
cell.ssb_positions_in_burst.in_one_group.set(0, true);
|
||||
cell.ssb_periodicity_ms = serv_cell.ssb_periodicity_serving_cell.to_number();
|
||||
cell.ssb_scs = serv_cell.ssb_subcarrier_spacing;
|
||||
cell.ss_pbch_block_power = serv_cell.ss_pbch_block_pwr;
|
||||
} else {
|
||||
const serving_cell_cfg_common_sib_s& serv_cell = cell_ctxt->sib1.serving_cell_cfg_common;
|
||||
cell.bwps[0].pdsch.p_zp_csi_rs_set = {};
|
||||
bzero(cell.bwps[0].pdsch.nzp_csi_rs_sets, sizeof(cell.bwps[0].pdsch.nzp_csi_rs_sets));
|
||||
cell.dl_cfg_common.reset(new dl_cfg_common_sib_s{serv_cell.dl_cfg_common});
|
||||
cell.ul_cfg_common.reset(new ul_cfg_common_sib_s{serv_cell.ul_cfg_common});
|
||||
if (serv_cell.tdd_ul_dl_cfg_common_present) {
|
||||
cell.tdd_ul_dl_cfg_common.emplace(serv_cell.tdd_ul_dl_cfg_common);
|
||||
}
|
||||
cell.ssb_positions_in_burst = serv_cell.ssb_positions_in_burst;
|
||||
cell.ssb_periodicity_ms = serv_cell.ssb_periodicity_serving_cell.to_number();
|
||||
cell.ssb_positions_in_burst = du_cfg->cell(cc).serv_cell_cfg_common().ssb_positions_in_burst;
|
||||
cell.ssb_periodicity_ms = du_cfg->cell(cc).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number();
|
||||
cell.ssb_scs.value = (subcarrier_spacing_e::options)cfg.cell_list[0].phy_cell.carrier.scs;
|
||||
cell.ss_pbch_block_power = serv_cell.ss_pbch_block_pwr;
|
||||
}
|
||||
cell.dmrs_type_a_position = cell_ctxt->mib.dmrs_type_a_position;
|
||||
cell.pdcch_cfg_sib1 = cell_ctxt->mib.pdcch_cfg_sib1;
|
||||
|
||||
// Set SIB1 and SI messages
|
||||
cell.sibs.resize(cell_ctxt->sib_buffer.size());
|
||||
|
@ -373,26 +379,6 @@ void rrc_nr::config_mac()
|
|||
|
||||
int32_t rrc_nr::generate_sibs()
|
||||
{
|
||||
// MIB packing
|
||||
fill_mib_from_enb_cfg(cfg.cell_list[0], cell_ctxt->mib);
|
||||
bcch_bch_msg_s mib_msg;
|
||||
mib_msg.msg.set_mib() = cell_ctxt->mib;
|
||||
{
|
||||
srsran::unique_byte_buffer_t mib_buf = srsran::make_byte_buffer();
|
||||
if (mib_buf == nullptr) {
|
||||
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
asn1::bit_ref bref(mib_buf->msg, mib_buf->get_tailroom());
|
||||
if (mib_msg.pack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
logger.error("Couldn't pack mib msg");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
mib_buf->N_bytes = bref.distance_bytes();
|
||||
logger.debug(mib_buf->msg, mib_buf->N_bytes, "MIB payload (%d B)", mib_buf->N_bytes);
|
||||
cell_ctxt->mib_buffer = std::move(mib_buf);
|
||||
}
|
||||
|
||||
if (not cfg.is_standalone) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ int derive_coreset0_params(rrc_cell_cfg_nr_t& cell)
|
|||
(ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0;
|
||||
int ret = srsran_coreset_zero(cell.phy_cell.carrier.pci,
|
||||
ssb_pointA_freq_offset_Hz,
|
||||
cell.ssb_cfg.scs,
|
||||
cell.ssb_scs,
|
||||
cell.phy_cell.carrier.scs,
|
||||
cell.coreset0_idx,
|
||||
&cell.phy_cell.pdcch.coreset[0]);
|
||||
|
@ -131,7 +131,7 @@ int derive_ssb_params(bool is_sa,
|
|||
srsran_subcarrier_spacing_t pdcch_scs,
|
||||
uint32_t coreset0_idx,
|
||||
uint32_t nof_prb,
|
||||
srsran_ssb_cfg_t& ssb)
|
||||
rrc_cell_cfg_nr_t& cell)
|
||||
{
|
||||
// Verify essential parameters are specified and valid
|
||||
ERROR_IF_NOT(dl_arfcn > 0, "Invalid DL ARFCN=%d", dl_arfcn);
|
||||
|
@ -145,20 +145,17 @@ int derive_ssb_params(bool is_sa,
|
|||
double dl_freq_hz = band_helper.nr_arfcn_to_freq(dl_arfcn);
|
||||
uint32_t dl_absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(nof_prb, dl_arfcn);
|
||||
|
||||
ssb.center_freq_hz = dl_freq_hz;
|
||||
ssb.duplex_mode = band_helper.get_duplex_mode(band);
|
||||
|
||||
// derive SSB pattern and scs
|
||||
ssb.pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_15kHz);
|
||||
if (ssb.pattern == SRSRAN_SSB_PATTERN_A) {
|
||||
cell.ssb_pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_15kHz);
|
||||
if (cell.ssb_pattern == SRSRAN_SSB_PATTERN_A) {
|
||||
// 15kHz SSB SCS
|
||||
ssb.scs = srsran_subcarrier_spacing_15kHz;
|
||||
cell.ssb_scs = srsran_subcarrier_spacing_15kHz;
|
||||
} else {
|
||||
// try to optain SSB pattern for same band with 30kHz SCS
|
||||
ssb.pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_30kHz);
|
||||
if (ssb.pattern == SRSRAN_SSB_PATTERN_B || ssb.pattern == SRSRAN_SSB_PATTERN_C) {
|
||||
cell.ssb_pattern = band_helper.get_ssb_pattern(band, srsran_subcarrier_spacing_30kHz);
|
||||
if (cell.ssb_pattern == SRSRAN_SSB_PATTERN_B || cell.ssb_pattern == SRSRAN_SSB_PATTERN_C) {
|
||||
// SSB SCS is 30 kHz
|
||||
ssb.scs = srsran_subcarrier_spacing_30kHz;
|
||||
cell.ssb_scs = srsran_subcarrier_spacing_30kHz;
|
||||
} else {
|
||||
srsran_terminate("Can't derive SSB pattern from band %d", band);
|
||||
}
|
||||
|
@ -168,29 +165,20 @@ int derive_ssb_params(bool is_sa,
|
|||
int coreset0_rb_offset = 0;
|
||||
if (is_sa) {
|
||||
// Get offset in RBs between CORESET#0 and SSB
|
||||
coreset0_rb_offset = srsran_coreset0_ssb_offset(coreset0_idx, ssb.scs, pdcch_scs);
|
||||
coreset0_rb_offset = srsran_coreset0_ssb_offset(coreset0_idx, cell.ssb_scs, pdcch_scs);
|
||||
ERROR_IF_NOT(coreset0_rb_offset >= 0, "Failed to compute RB offset between CORESET#0 and SSB");
|
||||
} else {
|
||||
// TODO: Verify if specified SSB frequency is valid
|
||||
}
|
||||
uint32_t ssb_abs_freq_point =
|
||||
band_helper.get_abs_freq_ssb_arfcn(band, ssb.scs, dl_absolute_freq_point_a, coreset0_rb_offset);
|
||||
band_helper.get_abs_freq_ssb_arfcn(band, cell.ssb_scs, dl_absolute_freq_point_a, coreset0_rb_offset);
|
||||
ERROR_IF_NOT(ssb_abs_freq_point > 0,
|
||||
"Can't derive SSB freq point for dl_arfcn=%d and band %d",
|
||||
band_helper.freq_to_nr_arfcn(dl_freq_hz),
|
||||
band);
|
||||
|
||||
// Convert to frequency for PHY
|
||||
ssb.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point);
|
||||
|
||||
ssb.periodicity_ms = 10; // TODO: make a param
|
||||
ssb.beta_pss = 0.0;
|
||||
ssb.beta_sss = 0.0;
|
||||
ssb.beta_pbch = 0.0;
|
||||
ssb.beta_pbch_dmrs = 0.0;
|
||||
// set by PHY layer in worker_pool::set_common_cfg
|
||||
ssb.srate_hz = 0.0;
|
||||
ssb.scaling = 0.0;
|
||||
cell.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
@ -259,9 +247,9 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell)
|
|||
cell.phy_cell.carrier.scs,
|
||||
cell.coreset0_idx,
|
||||
cell.phy_cell.carrier.nof_prb,
|
||||
cell.ssb_cfg);
|
||||
cell.phy_cell.carrier.ssb_center_freq_hz = cell.ssb_cfg.ssb_freq_hz;
|
||||
cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_cfg.ssb_freq_hz);
|
||||
cell);
|
||||
cell.phy_cell.carrier.ssb_center_freq_hz = cell.ssb_freq_hz;
|
||||
cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_freq_hz);
|
||||
|
||||
// Derive remaining config params
|
||||
if (is_sa) {
|
||||
|
@ -346,7 +334,6 @@ int set_derived_nr_rrc_params(rrc_nr_cfg_t& rrc_cfg)
|
|||
int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa)
|
||||
{
|
||||
// verify SSB params are consistent
|
||||
ERROR_IF_NOT(cell.ssb_cfg.center_freq_hz == cell.phy_cell.dl_freq_hz, "Invalid SSB param generation");
|
||||
HANDLE_ERROR(check_nr_phy_cell_cfg_valid(cell.phy_cell));
|
||||
|
||||
if (is_sa) {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 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 "srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h"
|
||||
#include "srsgnb/hdr/stack/rrc/cell_asn1_config.h"
|
||||
#include "srsran/common/string_helpers.h"
|
||||
|
||||
using namespace asn1::rrc_nr;
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
du_config_manager::du_config_manager(const rrc_nr_cfg_t& cfg_) : cfg(cfg_), logger(srslog::fetch_basic_logger("RRC-NR"))
|
||||
{}
|
||||
|
||||
du_config_manager::~du_config_manager() {}
|
||||
|
||||
int du_config_manager::add_cell()
|
||||
{
|
||||
// add cell
|
||||
std::unique_ptr<du_cell_config> obj = std::make_unique<du_cell_config>();
|
||||
du_cell_config& cell = *obj;
|
||||
cell.cc = cells.size();
|
||||
|
||||
// Fill general cell params
|
||||
cell.pci = cfg.cell_list[cell.cc].phy_cell.carrier.pci;
|
||||
|
||||
// fill MIB ASN.1
|
||||
if (fill_mib_from_enb_cfg(cfg.cell_list[cell.cc], cell.mib) != SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Pack MIB
|
||||
cell.packed_mib = srsran::make_byte_buffer();
|
||||
if (cell.packed_mib == nullptr) {
|
||||
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
{
|
||||
asn1::bit_ref bref(cell.packed_mib->msg, cell.packed_mib->get_tailroom());
|
||||
bcch_bch_msg_s bch_msg;
|
||||
bch_msg.msg.set_mib() = cell.mib;
|
||||
if (bch_msg.pack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
logger.error("Couldn't pack mib msg");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
cell.packed_mib->N_bytes = bref.distance_bytes();
|
||||
}
|
||||
logger.info(
|
||||
cell.packed_mib->data(), cell.packed_mib->size(), "BCCH-BCH Message (with MIB) (%d B)", cell.packed_mib->size());
|
||||
asn1::json_writer js;
|
||||
cell.mib.to_json(js);
|
||||
logger.info("MIB content: %s", js.to_string().c_str());
|
||||
|
||||
// fill SIB1 ASN.1
|
||||
if (fill_sib1_from_enb_cfg(cfg, cell.cc, cell.sib1) != SRSRAN_SUCCESS) {
|
||||
logger.error("Couldn't generate SIB1");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Pack SIB1
|
||||
cell.packed_sib1 = srsran::make_byte_buffer();
|
||||
if (cell.packed_sib1 == nullptr) {
|
||||
logger.error("Couldn't allocate PDU in %s().", __FUNCTION__);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
{
|
||||
asn1::bit_ref bref(cell.packed_sib1->msg, cell.packed_sib1->get_tailroom());
|
||||
bcch_dl_sch_msg_s bcch_msg;
|
||||
bcch_msg.msg.set_c1().set_sib_type1() = cell.sib1;
|
||||
if (bcch_msg.pack(bref) != asn1::SRSASN_SUCCESS) {
|
||||
logger.error("Couldn't pack SIB1 msg");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
cell.packed_sib1->N_bytes = bref.distance_bytes();
|
||||
}
|
||||
logger.info(cell.packed_sib1->data(),
|
||||
cell.packed_sib1->size(),
|
||||
"BCCH-DL-SCH-Message (with SIB1) (%d B)",
|
||||
cell.packed_sib1->size());
|
||||
cell.sib1.to_json(js);
|
||||
logger.info("SIB1 content: %s", js.to_string().c_str());
|
||||
|
||||
cells.push_back(std::move(obj));
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
|
@ -192,7 +192,7 @@ void nr_security_context::generate_as_keys()
|
|||
logger.info(sec_cfg.k_nr_rrc_enc.data(), 32, "NR RRC Encryption Key (k_nr_rrc_enc)");
|
||||
logger.info(sec_cfg.k_nr_rrc_int.data(), 32, "NR RRC Integrity Key (k_nr_rrc_int)");
|
||||
logger.info(sec_cfg.k_nr_up_enc.data(), 32, "NR UP Encryption Key (k_nr_up_enc)");
|
||||
logger.info(sec_cfg.k_nr_up_int.data(), 32, "NR UP Encryption Key (k_nr_up_enc)");
|
||||
logger.info(sec_cfg.k_nr_up_int.data(), 32, "NR UP Integrity Key (k_nr_up_int)");
|
||||
}
|
||||
|
||||
void nr_security_context::regenerate_keys_handover(uint32_t new_pci, uint32_t new_dl_arfcn)
|
||||
|
|
|
@ -1117,20 +1117,8 @@ void rrc_nr::ue::handle_rrc_setup_complete(const asn1::rrc_nr::rrc_setup_complet
|
|||
/// TS 38.331, SecurityModeCommand
|
||||
void rrc_nr::ue::send_security_mode_command(srsran::unique_byte_buffer_t nas_pdu)
|
||||
{
|
||||
// FIXME: Currently we are using the PDCP-LTE, so we need to convert from nr_as_security_cfg to as_security_config.
|
||||
// When we start using PDCP-NR we can avoid this step.
|
||||
srsran::nr_as_security_config_t tmp_cnfg = sec_ctx.get_as_sec_cfg();
|
||||
srsran::as_security_config_t pdcp_cnfg = {};
|
||||
pdcp_cnfg.k_rrc_int = tmp_cnfg.k_nr_rrc_int;
|
||||
pdcp_cnfg.k_rrc_enc = tmp_cnfg.k_nr_rrc_enc;
|
||||
pdcp_cnfg.k_up_int = tmp_cnfg.k_nr_up_int;
|
||||
pdcp_cnfg.k_up_enc = tmp_cnfg.k_nr_up_enc;
|
||||
pdcp_cnfg.integ_algo = (srsran::INTEGRITY_ALGORITHM_ID_ENUM)tmp_cnfg.integ_algo;
|
||||
pdcp_cnfg.cipher_algo = (srsran::CIPHERING_ALGORITHM_ID_ENUM)tmp_cnfg.cipher_algo;
|
||||
|
||||
// Setup SRB1 security/integrity. Encryption is set on completion
|
||||
parent->pdcp->config_security(rnti, srb_to_lcid(srsran::nr_srb::srb1), pdcp_cnfg);
|
||||
parent->pdcp->enable_integrity(rnti, srb_to_lcid(srsran::nr_srb::srb1));
|
||||
// apply selected security config and enable integrity on SRB1 before generating security mode command
|
||||
update_as_security(srb_to_lcid(srsran::nr_srb::srb1), true, false);
|
||||
|
||||
if (nas_pdu != nullptr) {
|
||||
nas_pdu_queue.push_back(std::move(nas_pdu));
|
||||
|
@ -1148,11 +1136,58 @@ void rrc_nr::ue::send_security_mode_command(srsran::unique_byte_buffer_t nas_pdu
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Internal helper to update the security configuration of a PDCP bearer
|
||||
*
|
||||
* If no valid AS security config is present (yet) the method doesn't modify the
|
||||
* PDCP config and returns SRSRAN_ERROR. In some cases, however,
|
||||
* for example during RRC Setup, this is in fact the expected behaviour as
|
||||
* AS security isn't established yet.
|
||||
*
|
||||
* @param lcid Logical channel ID of the bearer
|
||||
* @param enable_integrity Whether to enable integrity protection for the bearer
|
||||
* @param enable_ciphering Whether to enable ciphering for the bearer
|
||||
* @return int SRSRAN_SUCCESS if a valid AS security config was found and the security was configured
|
||||
*/
|
||||
int rrc_nr::ue::update_as_security(uint32_t lcid, bool enable_integrity = true, bool enable_ciphering = true)
|
||||
{
|
||||
if (not sec_ctx.is_as_sec_cfg_valid()) {
|
||||
parent->logger.error("Invalid AS security configuration. Skipping configuration for lcid=%d", lcid);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// FIXME: Currently we are using the PDCP-LTE, so we need to convert from nr_as_security_cfg to as_security_config.
|
||||
// When we start using PDCP-NR we can avoid this step.
|
||||
srsran::nr_as_security_config_t tmp_cnfg = sec_ctx.get_as_sec_cfg();
|
||||
srsran::as_security_config_t pdcp_cnfg = {};
|
||||
pdcp_cnfg.k_rrc_int = tmp_cnfg.k_nr_rrc_int;
|
||||
pdcp_cnfg.k_rrc_enc = tmp_cnfg.k_nr_rrc_enc;
|
||||
pdcp_cnfg.k_up_int = tmp_cnfg.k_nr_up_int;
|
||||
pdcp_cnfg.k_up_enc = tmp_cnfg.k_nr_up_enc;
|
||||
pdcp_cnfg.integ_algo = (srsran::INTEGRITY_ALGORITHM_ID_ENUM)tmp_cnfg.integ_algo;
|
||||
pdcp_cnfg.cipher_algo = (srsran::CIPHERING_ALGORITHM_ID_ENUM)tmp_cnfg.cipher_algo;
|
||||
|
||||
// configure algorithm and keys
|
||||
parent->pdcp->config_security(rnti, lcid, pdcp_cnfg);
|
||||
|
||||
if (enable_integrity) {
|
||||
parent->pdcp->enable_integrity(rnti, lcid);
|
||||
}
|
||||
|
||||
if (enable_ciphering) {
|
||||
parent->pdcp->enable_encryption(rnti, lcid);
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
/// TS 38.331, SecurityModeComplete
|
||||
void rrc_nr::ue::handle_security_mode_complete(const asn1::rrc_nr::security_mode_complete_s& msg)
|
||||
{
|
||||
parent->logger.info("SecurityModeComplete transaction ID: %d", msg.rrc_transaction_id);
|
||||
parent->pdcp->enable_encryption(rnti, srb_to_lcid(srsran::nr_srb::srb1));
|
||||
|
||||
// finally, also enable ciphering on SRB1
|
||||
update_as_security(srb_to_lcid(srsran::nr_srb::srb1), false, true);
|
||||
|
||||
send_rrc_reconfiguration();
|
||||
// Note: Skip UE capabilities
|
||||
|
@ -1366,20 +1401,8 @@ int rrc_nr::ue::update_pdcp_bearers(const asn1::rrc_nr::radio_bearer_cfg_s& radi
|
|||
}
|
||||
parent->pdcp->add_bearer(rnti, rlc_bearer->lc_ch_id, pdcp_cnfg);
|
||||
|
||||
// enable security config
|
||||
if (sec_ctx.is_as_sec_cfg_valid()) {
|
||||
srsran::nr_as_security_config_t tmp_cnfg = sec_ctx.get_as_sec_cfg();
|
||||
srsran::as_security_config_t pdcp_cnfg = {};
|
||||
pdcp_cnfg.k_rrc_int = tmp_cnfg.k_nr_rrc_int;
|
||||
pdcp_cnfg.k_rrc_enc = tmp_cnfg.k_nr_rrc_enc;
|
||||
pdcp_cnfg.k_up_int = tmp_cnfg.k_nr_up_int;
|
||||
pdcp_cnfg.k_up_enc = tmp_cnfg.k_nr_up_enc;
|
||||
pdcp_cnfg.integ_algo = (srsran::INTEGRITY_ALGORITHM_ID_ENUM)tmp_cnfg.integ_algo;
|
||||
pdcp_cnfg.cipher_algo = (srsran::CIPHERING_ALGORITHM_ID_ENUM)tmp_cnfg.cipher_algo;
|
||||
|
||||
// Setup SRB1 security/integrity. Encryption is set on completion
|
||||
parent->pdcp->config_security(rnti, srb_to_lcid(srsran::nr_srb::srb1), pdcp_cnfg);
|
||||
parent->pdcp->enable_integrity(rnti, srb_to_lcid(srsran::nr_srb::srb1));
|
||||
update_as_security(rlc_bearer->lc_ch_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1399,6 +1422,10 @@ int rrc_nr::ue::update_pdcp_bearers(const asn1::rrc_nr::radio_bearer_cfg_s& radi
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
parent->pdcp->add_bearer(rnti, rlc_bearer->lc_ch_id, pdcp_cnfg);
|
||||
|
||||
if (sec_ctx.is_as_sec_cfg_valid()) {
|
||||
update_as_security(rlc_bearer->lc_ch_id);
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
@ -1449,6 +1476,14 @@ int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_config, bool is_co
|
|||
// TODO: remaining fields
|
||||
}
|
||||
}
|
||||
|
||||
if (cell_group_config.sp_cell_cfg_present and cell_group_config.sp_cell_cfg.sp_cell_cfg_ded_present and
|
||||
cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.ul_cfg_present and
|
||||
cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.ul_cfg.init_ul_bwp_present and
|
||||
cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.ul_cfg.init_ul_bwp.pucch_cfg_present) {
|
||||
auto& pucch_cfg = cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.ul_cfg.init_ul_bwp.pucch_cfg.setup();
|
||||
srsran::fill_phy_pucch_cfg(pucch_cfg, &uecfg.phy_cfg.pucch);
|
||||
}
|
||||
} else {
|
||||
auto& pdcch = cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup();
|
||||
for (auto& ss : pdcch.search_spaces_to_add_mod_list) {
|
||||
|
@ -1466,6 +1501,7 @@ int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_config, bool is_co
|
|||
uecfg.sp_cell_cfg.reset(new sp_cell_cfg_s{cell_group_cfg.sp_cell_cfg});
|
||||
uecfg.mac_cell_group_cfg.reset(new mac_cell_group_cfg_s{cell_group_cfg.mac_cell_group_cfg});
|
||||
uecfg.phy_cell_group_cfg.reset(new phys_cell_group_cfg_s{cell_group_cfg.phys_cell_group_cfg});
|
||||
srsran::make_csi_cfg_from_serv_cell(cell_group_config.sp_cell_cfg.sp_cell_cfg_ded, &uecfg.phy_cfg.csi);
|
||||
parent->mac->ue_cfg(rnti, uecfg);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
|
|
@ -179,6 +179,7 @@ void test_rrc_sa_connection()
|
|||
SRSRAN_SUCCESS);
|
||||
|
||||
TESTASSERT_SUCCESS(rrc_obj.add_user(0x4601, 0));
|
||||
TESTASSERT_SUCCESS(rrc_obj.ue_set_security_cfg_key(0x4601, {}));
|
||||
|
||||
test_rrc_nr_connection_establishment(task_sched, rrc_obj, rlc_obj, mac_obj, ngap_obj, 0x4601);
|
||||
test_rrc_nr_info_transfer(task_sched, rrc_obj, pdcp_obj, ngap_obj, 0x4601);
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
void meas_stop() final {}
|
||||
|
||||
/* Cell search and selection procedures */
|
||||
bool cell_search() final { return false; }
|
||||
bool cell_search(int earfcn) final { return false; }
|
||||
bool cell_select(phy_cell_t cell) final { return false; }
|
||||
bool cell_is_camping() final { return false; }
|
||||
|
||||
|
|
|
@ -58,8 +58,6 @@ public:
|
|||
bool start(const cfg_t& cfg);
|
||||
ret_t run_slot(const cf_t* buffer, uint32_t slot_sz);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
srslog::basic_logger& logger;
|
||||
srsran_ssb_t ssb = {};
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
|
||||
/********** RRC INTERFACE ********************/
|
||||
|
||||
bool cell_search() final;
|
||||
bool cell_search(int earfcn) final;
|
||||
bool cell_select(phy_cell_t cell) final;
|
||||
|
||||
// Sets the new PHY configuration for the given CC. The configuration is applied in the background. The notify()
|
||||
|
|
|
@ -77,7 +77,7 @@ public:
|
|||
|
||||
// RRC interface for controling the SYNC state
|
||||
bool cell_search_init();
|
||||
rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell);
|
||||
rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell, int earfcn);
|
||||
bool cell_select_init(phy_cell_t cell);
|
||||
bool cell_select_start(phy_cell_t cell);
|
||||
bool cell_is_camping();
|
||||
|
|
|
@ -49,7 +49,9 @@ public:
|
|||
struct cell_sel_cmd {
|
||||
phy_cell_t phy_cell;
|
||||
};
|
||||
struct cell_search_cmd {};
|
||||
struct cell_search_cmd {
|
||||
int earfcn;
|
||||
};
|
||||
struct in_sync_ev {
|
||||
static const bool log_verbose = false;
|
||||
};
|
||||
|
@ -61,7 +63,7 @@ public:
|
|||
|
||||
// PHY procedures interfaces
|
||||
bool start_cell_select(const phy_cell_t& phy_cell, srsran::event_observer<bool> observer = {});
|
||||
bool start_cell_search(srsran::event_observer<cell_srch_res> observer);
|
||||
bool start_cell_search(srsran::event_observer<cell_srch_res> observer, int earfcn);
|
||||
void cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell);
|
||||
void cell_selection_completed(bool outcome);
|
||||
void in_sync();
|
||||
|
@ -126,7 +128,7 @@ public:
|
|||
// clang-format on
|
||||
};
|
||||
struct searching_cell {
|
||||
void enter(phy_controller* f);
|
||||
void enter(phy_controller* f, const cell_search_cmd& ev);
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -220,6 +220,9 @@ private:
|
|||
|
||||
meas_cell_list<meas_cell_nr> meas_cells_nr;
|
||||
|
||||
// if this is set to a valid earfcn, this earfcn will be used for cell search
|
||||
int cell_search_earfcn = -1;
|
||||
|
||||
bool initiated = false;
|
||||
asn1::rrc::reest_cause_e m_reest_cause = asn1::rrc::reest_cause_e::nulltype;
|
||||
uint16_t m_reest_rnti = 0;
|
||||
|
@ -337,7 +340,8 @@ private:
|
|||
bool con_reconfig_ho(const asn1::rrc::rrc_conn_recfg_s& reconfig);
|
||||
void ho_failed();
|
||||
void start_go_idle();
|
||||
void rrc_connection_release(const std::string& cause);
|
||||
void handle_rrc_connection_release(const asn1::rrc::rrc_conn_release_s& release);
|
||||
void start_rrc_redirect(uint32_t new_dl_earfcn);
|
||||
void radio_link_failure_push_cmd();
|
||||
void radio_link_failure_process();
|
||||
void leave_connected();
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "../rrc/rrc_cell.h"
|
||||
#include "rrc_nr_config.h"
|
||||
#include "rrc_nr_metrics.h"
|
||||
#include "srsran/adt/circular_map.h"
|
||||
#include "srsran/asn1/rrc_nr.h"
|
||||
#include "srsran/asn1/rrc_nr_utils.h"
|
||||
|
@ -44,8 +45,6 @@ class usim_interface_rrc_nr;
|
|||
class pdcp_interface_rrc;
|
||||
class rlc_interface_rrc;
|
||||
|
||||
struct rrc_nr_metrics_t {};
|
||||
|
||||
class rrc_nr final : public rrc_interface_phy_nr,
|
||||
public rrc_interface_pdcp,
|
||||
public rrc_interface_rlc,
|
||||
|
@ -146,6 +145,7 @@ private:
|
|||
// senders
|
||||
void send_setup_request(srsran::nr_establishment_cause_t cause);
|
||||
void send_con_setup_complete(srsran::unique_byte_buffer_t nas_msg);
|
||||
void send_rrc_reconfig_complete();
|
||||
void send_ul_info_transfer(srsran::unique_byte_buffer_t nas_msg);
|
||||
void send_ul_ccch_msg(const asn1::rrc_nr::ul_ccch_msg_s& msg);
|
||||
void send_ul_dcch_msg(uint32_t lcid, const asn1::rrc_nr::ul_dcch_msg_s& msg);
|
||||
|
@ -193,14 +193,6 @@ private:
|
|||
uint32_t sim_measurement_carrier_freq_r15;
|
||||
srsran::timer_handler::unique_timer sim_measurement_timer;
|
||||
|
||||
/// RRC states (3GPP 38.331 v15.5.1 Sec 4.2.1)
|
||||
enum rrc_nr_state_t {
|
||||
RRC_NR_STATE_IDLE = 0,
|
||||
RRC_NR_STATE_CONNECTED,
|
||||
RRC_NR_STATE_CONNECTED_INACTIVE,
|
||||
RRC_NR_STATE_N_ITEMS,
|
||||
};
|
||||
const static char* rrc_nr_state_text[RRC_NR_STATE_N_ITEMS];
|
||||
rrc_nr_state_t state = RRC_NR_STATE_IDLE;
|
||||
|
||||
uint8_t transaction_id = 0;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 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 SRSUE_RRC_NR_METRICS_H
|
||||
#define SRSUE_RRC_NR_METRICS_H
|
||||
|
||||
namespace srsue {
|
||||
|
||||
/// RRC states (3GPP 38.331 v15.5.1 Sec 4.2.1)
|
||||
enum rrc_nr_state_t {
|
||||
RRC_NR_STATE_IDLE = 0,
|
||||
RRC_NR_STATE_CONNECTED,
|
||||
RRC_NR_STATE_CONNECTED_INACTIVE,
|
||||
RRC_NR_STATE_N_ITEMS,
|
||||
};
|
||||
|
||||
struct rrc_nr_metrics_t {
|
||||
rrc_nr_state_t state;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_RRC_NR_METRICS_H
|
|
@ -67,6 +67,8 @@ public:
|
|||
|
||||
// Stack+RRC interface
|
||||
bool is_registered();
|
||||
int get_k_amf(srsran::as_key_t& k_amf);
|
||||
uint32_t get_ul_nas_count();
|
||||
|
||||
int write_pdu(srsran::unique_byte_buffer_t pdu);
|
||||
|
||||
|
@ -89,7 +91,7 @@ private:
|
|||
gw_interface_nas* gw = nullptr;
|
||||
|
||||
bool running = false;
|
||||
|
||||
bool has_sec_ctxt = false;
|
||||
bool initial_sec_command = false;
|
||||
srsran::nas_5g::mobile_identity_5gs_t::guti_5g_s guti_5g;
|
||||
|
||||
|
@ -102,6 +104,8 @@ private:
|
|||
bool ia5g_caps[8] = {};
|
||||
bool ea5g_caps[8] = {};
|
||||
|
||||
void set_k_gnb_count(uint32_t count);
|
||||
|
||||
// TS 23.003 Sec. 6.2.2 IMEISV's last two octets are Software Version Number (SVN)
|
||||
// which identifies the software version number of the mobile equipment
|
||||
const uint8_t ue_svn_oct1 = 0x5;
|
||||
|
|
|
@ -69,6 +69,7 @@ protected:
|
|||
struct nas_5g_sec_ctxt {
|
||||
uint8_t ksi;
|
||||
uint8_t k_amf[32];
|
||||
uint32_t k_gnb_count;
|
||||
};
|
||||
|
||||
nas_sec_base_ctxt ctxt_base = {};
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
void restore_keys_from_failed_ho(srsran::as_security_config_t* as_ctx) final;
|
||||
|
||||
// NR RRC interface
|
||||
void generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg) final;
|
||||
bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) final;
|
||||
bool update_nr_context(srsran::as_security_config_t* sec_cfg) final;
|
||||
|
||||
|
@ -149,6 +150,8 @@ protected:
|
|||
uint8_t k_enb_initial[KEY_LEN] = {};
|
||||
uint8_t auts[AKA_AUTS_LEN] = {};
|
||||
|
||||
srsran::as_key_t k_gnb_initial = {};
|
||||
|
||||
// Current K_eNB context (K_eNB, NH and NCC)
|
||||
srsran::k_enb_context_t k_enb_ctx = {};
|
||||
srsran::k_gnb_context_t k_gnb_ctx = {};
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "srsran/system/sys_metrics.h"
|
||||
#include "stack/mac/mac_metrics.h"
|
||||
#include "stack/rrc/rrc_metrics.h"
|
||||
#include "stack/rrc_nr/rrc_nr_metrics.h"
|
||||
#include "stack/upper/gw_metrics.h"
|
||||
#include "stack/upper/nas_metrics.h"
|
||||
|
||||
|
@ -43,7 +44,7 @@ typedef struct {
|
|||
srsran::rlc_metrics_t rlc;
|
||||
nas_metrics_t nas;
|
||||
rrc_metrics_t rrc;
|
||||
rrc_metrics_t rrc_nr;
|
||||
rrc_nr_metrics_t rrc_nr;
|
||||
} stack_metrics_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -190,7 +190,7 @@ void metrics_stdout::set_metrics(const ue_metrics_t& metrics, const uint32_t per
|
|||
return;
|
||||
}
|
||||
|
||||
if (metrics.stack.rrc.state != RRC_STATE_CONNECTED) {
|
||||
if (metrics.stack.rrc.state != RRC_STATE_CONNECTED && metrics.stack.rrc_nr.state != RRC_NR_STATE_CONNECTED) {
|
||||
fmt::print("--- disconnected ---\n");
|
||||
return;
|
||||
}
|
||||
|
@ -202,25 +202,30 @@ void metrics_stdout::set_metrics(const ue_metrics_t& metrics, const uint32_t per
|
|||
display_neighbours |= metrics.stack.rrc.neighbour_cells.size() > 0;
|
||||
}
|
||||
|
||||
bool is_nr = metrics.phy_nr.nof_active_cc > 0;
|
||||
bool has_lte = metrics.phy.nof_active_cc > 0;
|
||||
bool has_nr = metrics.phy_nr.nof_active_cc > 0;
|
||||
|
||||
// print table header every 10 reports
|
||||
if (++n_reports > 10) {
|
||||
print_table(display_neighbours, is_nr);
|
||||
print_table(display_neighbours, has_nr);
|
||||
}
|
||||
|
||||
// also print table header if neighbours are added/removed in between
|
||||
if (display_neighbours != table_has_neighbours) {
|
||||
print_table(display_neighbours, is_nr);
|
||||
print_table(display_neighbours, has_nr);
|
||||
}
|
||||
|
||||
if (has_lte) {
|
||||
for (uint32_t r = 0; r < metrics.phy.nof_active_cc; r++) {
|
||||
set_metrics_helper(metrics.phy, metrics.stack.mac, metrics.stack.rrc, display_neighbours, r, false, !is_nr);
|
||||
set_metrics_helper(metrics.phy, metrics.stack.mac, metrics.stack.rrc, display_neighbours, r, false, !has_nr);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_nr) {
|
||||
for (uint32_t r = 0; r < metrics.phy_nr.nof_active_cc; r++) {
|
||||
// Assumption LTE is followed by the NR carriers.
|
||||
set_metrics_helper(metrics.phy_nr, metrics.stack.mac_nr, metrics.stack.rrc, display_neighbours, r, true, !is_nr);
|
||||
set_metrics_helper(metrics.phy_nr, metrics.stack.mac_nr, metrics.stack.rrc, display_neighbours, r, true, !has_nr);
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics.rf.rf_error) {
|
||||
|
|
|
@ -351,12 +351,12 @@ bool phy::cell_select(phy_cell_t cell)
|
|||
|
||||
// This function executes one part of the procedure immediatly and returns to continue in the background.
|
||||
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
|
||||
// processing.
|
||||
bool phy::cell_search()
|
||||
// processing. If a valid EARFCN (>0) is given, this is used for cell search.
|
||||
bool phy::cell_search(int earfcn)
|
||||
{
|
||||
sfsync.scell_sync_stop();
|
||||
if (sfsync.cell_search_init()) {
|
||||
cmd_worker_cell.add_cmd([this]() {
|
||||
cmd_worker_cell.add_cmd([this, earfcn]() {
|
||||
// Wait SYNC transitions to IDLE
|
||||
sfsync.wait_idle();
|
||||
|
||||
|
@ -364,7 +364,7 @@ bool phy::cell_search()
|
|||
reset();
|
||||
|
||||
phy_cell_t found_cell = {};
|
||||
rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell);
|
||||
rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell, earfcn);
|
||||
stack->cell_search_complete(ret, found_cell);
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -188,10 +188,10 @@ void sync::reset()
|
|||
*
|
||||
*/
|
||||
|
||||
/* A call to cell_search() finds the strongest cell in the set of supported EARFCNs. When the first cell is found,
|
||||
* returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not found in the
|
||||
* current frequency it moves to the next one and the next call to cell_search() will look in the next EARFCN in the
|
||||
* set. If no cells are found in any frequency it returns 0. If error returns -1.
|
||||
/* A call to cell_search() finds the strongest cell at a given EARFCN or in the set of supported EARFCNs. When the first
|
||||
* cell is found, returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not
|
||||
* found in the current frequency it moves to the next one and the next call to cell_search() will look in the next
|
||||
* EARFCN in the set. If no cells are found in any frequency it returns 0. If error returns -1.
|
||||
*
|
||||
* The first part of the procedure (call to _init()) moves the PHY To IDLE, ensuring that no UL/DL/PRACH will happen
|
||||
*
|
||||
|
@ -206,7 +206,6 @@ bool sync::cell_search_init()
|
|||
}
|
||||
|
||||
// Move state to IDLE
|
||||
Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
|
||||
phy_state.go_idle();
|
||||
|
||||
// Stop all intra-frequency measurement before changing frequency
|
||||
|
@ -217,10 +216,16 @@ bool sync::cell_search_init()
|
|||
return true;
|
||||
}
|
||||
|
||||
rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell)
|
||||
rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell, int earfcn)
|
||||
{
|
||||
std::unique_lock<std::mutex> ul(rrc_mutex);
|
||||
|
||||
if (earfcn < 0) {
|
||||
Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
|
||||
} else {
|
||||
Info("Cell Search: Start EARFCN=%d", earfcn);
|
||||
}
|
||||
|
||||
rrc_interface_phy_lte::cell_search_ret_t ret = {};
|
||||
ret.found = rrc_interface_phy_lte::cell_search_ret_t::ERROR;
|
||||
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
|
||||
|
@ -238,16 +243,20 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou
|
|||
Info("SYNC: Setting Cell Search sampling rate");
|
||||
}
|
||||
|
||||
if (earfcn < 0) {
|
||||
try {
|
||||
if (current_earfcn != (int)worker_com->args->dl_earfcn_list.at(cellsearch_earfcn_index)) {
|
||||
current_earfcn = (int)worker_com->args->dl_earfcn_list[cellsearch_earfcn_index];
|
||||
Info("Cell Search: changing frequency to EARFCN=%d", current_earfcn);
|
||||
set_frequency();
|
||||
}
|
||||
} catch (const std::out_of_range& oor) {
|
||||
Error("Index %d is not a valid EARFCN element.", cellsearch_earfcn_index);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
current_earfcn = earfcn;
|
||||
}
|
||||
Info("Cell Search: changing frequency to EARFCN=%d", current_earfcn);
|
||||
set_frequency();
|
||||
|
||||
// Move to CELL SEARCH and wait to finish
|
||||
Info("Cell Search: Setting Cell search state");
|
||||
|
@ -275,7 +284,7 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou
|
|||
}
|
||||
|
||||
cellsearch_earfcn_index++;
|
||||
if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size()) {
|
||||
if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size() or earfcn < 0) {
|
||||
Info("Cell Search: No more frequencies in the current EARFCN set");
|
||||
cellsearch_earfcn_index = 0;
|
||||
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
|
||||
|
|
|
@ -224,6 +224,11 @@ void sync_sa::run_state_idle()
|
|||
|
||||
void sync_sa::run_state_cell_search()
|
||||
{
|
||||
// Initialise buffer
|
||||
if (cell_search_nof_trials == 0) {
|
||||
srsran_vec_cf_zero(rx_buffer, slot_sz);
|
||||
}
|
||||
|
||||
// Receive samples
|
||||
srsran::rf_buffer_t rf_buffer = {};
|
||||
rf_buffer.set_nof_samples(slot_sz);
|
||||
|
|
|
@ -517,7 +517,7 @@ int main(int argc, char** argv)
|
|||
phy_test->start();
|
||||
|
||||
// 1. Cell search
|
||||
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search());
|
||||
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search(-1));
|
||||
TESTASSERT(phy_test->get_stack()->wait_cell_search(default_timeout));
|
||||
TESTASSERT(phy_test->get_stack()->cell_search_ret.found ==
|
||||
srsue::rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND);
|
||||
|
|
|
@ -175,13 +175,13 @@ void phy_controller::selecting_cell::wait_in_sync::enter(selecting_cell* f)
|
|||
*************************************/
|
||||
|
||||
//! Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet
|
||||
bool phy_controller::start_cell_search(srsran::event_observer<cell_srch_res> observer)
|
||||
bool phy_controller::start_cell_search(srsran::event_observer<cell_srch_res> observer, int earfcn)
|
||||
{
|
||||
if (is_in_state<searching_cell>()) {
|
||||
fsmInfo("Cell search already launched.");
|
||||
return true;
|
||||
}
|
||||
trigger(cell_search_cmd{});
|
||||
trigger(cell_search_cmd{earfcn});
|
||||
if (not is_in_state<searching_cell>()) {
|
||||
fsmWarning("Failed to launch cell search");
|
||||
return false;
|
||||
|
@ -195,10 +195,10 @@ void phy_controller::cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t
|
|||
trigger(cell_srch_res{cs_ret, found_cell});
|
||||
}
|
||||
|
||||
void phy_controller::searching_cell::enter(phy_controller* f)
|
||||
void phy_controller::searching_cell::enter(phy_controller* f, const cell_search_cmd& ev)
|
||||
{
|
||||
otherfsmInfo(f, "Initiating Cell search");
|
||||
f->phy->cell_search();
|
||||
f->phy->cell_search(ev.earfcn);
|
||||
}
|
||||
|
||||
void phy_controller::handle_cell_search_res(searching_cell& s, const cell_srch_res& result)
|
||||
|
|
|
@ -1162,8 +1162,9 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, const rrc_conn_recfg_s& reconfi
|
|||
}
|
||||
|
||||
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
|
||||
void rrc::rrc_connection_release(const std::string& cause)
|
||||
void rrc::handle_rrc_connection_release(const asn1::rrc::rrc_conn_release_s& release)
|
||||
{
|
||||
std::string cause = release.crit_exts.c1().rrc_conn_release_r8().release_cause.to_string();
|
||||
// Save idleModeMobilityControlInfo, etc.
|
||||
srsran::console("Received RRC Connection Release (releaseCause: %s)\n", cause.c_str());
|
||||
|
||||
|
@ -1173,6 +1174,36 @@ void rrc::rrc_connection_release(const std::string& cause)
|
|||
|
||||
// delay actions by 60ms as per 5.3.8.3
|
||||
task_sched.defer_callback(60, [this]() { start_go_idle(); });
|
||||
|
||||
uint32_t earfcn = 0;
|
||||
if (release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info_present) {
|
||||
switch (release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type()) {
|
||||
case asn1::rrc::redirected_carrier_info_c::types_opts::options::eutra:
|
||||
earfcn = release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.eutra();
|
||||
break;
|
||||
default:
|
||||
srsran::console("Ignoring RedirectedCarrierInfo with unsupported type (%s)\n",
|
||||
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string());
|
||||
break;
|
||||
}
|
||||
if (earfcn != 0) {
|
||||
srsran::console("RedirectedCarrierInfo present (type %s, earfcn: %d) - Redirecting\n",
|
||||
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string(),
|
||||
earfcn);
|
||||
logger.info("RedirectedCarrierInfo present (type %s, earfcn: %d) - Redirecting",
|
||||
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string(),
|
||||
earfcn);
|
||||
|
||||
// delay actions by 60ms as per 5.3.8.3
|
||||
task_sched.defer_callback(60, [this, earfcn]() { start_rrc_redirect(earfcn); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rrc::start_rrc_redirect(uint32_t new_dl_earfcn)
|
||||
{
|
||||
cell_search_earfcn = (int)new_dl_earfcn;
|
||||
plmn_search();
|
||||
}
|
||||
|
||||
/// TS 36.331, 5.3.12 - UE actions upon leaving RRC_CONNECTED
|
||||
|
@ -1827,7 +1858,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
|
|||
handle_ue_capability_enquiry(c1->ue_cap_enquiry());
|
||||
break;
|
||||
case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release:
|
||||
rrc_connection_release(c1->rrc_conn_release().crit_exts.c1().rrc_conn_release_r8().release_cause.to_string());
|
||||
handle_rrc_connection_release(c1->rrc_conn_release());
|
||||
break;
|
||||
case dl_dcch_msg_type_c::c1_c_::types::ue_info_request_r9:
|
||||
transaction_id = c1->ue_info_request_r9().rrc_transaction_id;
|
||||
|
|
|
@ -80,6 +80,12 @@ void meas_cell_eutra::set_sib13(const asn1::rrc::sib_type13_r9_s& sib13_)
|
|||
has_valid_sib13 = true;
|
||||
}
|
||||
|
||||
void meas_cell_nr::set_sib1(const asn1::rrc_nr::sib1_s& sib1_)
|
||||
{
|
||||
sib1 = sib1_;
|
||||
has_valid_sib1 = true;
|
||||
}
|
||||
|
||||
bool meas_cell::is_sib_scheduled(uint32_t sib_index) const
|
||||
{
|
||||
return sib_info_map.find(sib_index) != sib_info_map.end();
|
||||
|
|
|
@ -50,7 +50,7 @@ proc_outcome_t rrc::cell_search_proc::init()
|
|||
{
|
||||
Info("Starting...");
|
||||
state = state_t::phy_cell_search;
|
||||
if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher)) {
|
||||
if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher, rrc_ptr->cell_search_earfcn)) {
|
||||
Warning("Failed to initiate Cell Search.");
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
|
@ -1265,12 +1265,15 @@ proc_outcome_t rrc::go_idle_proc::step()
|
|||
|
||||
void rrc::go_idle_proc::then(const srsran::proc_state_t& result)
|
||||
{
|
||||
// only start cell reselection if no RRC redirect is present (redirect will trigger a cell search)
|
||||
if (rrc_ptr->cell_search_earfcn < 0) {
|
||||
if (rrc_ptr->nas->is_registered() and not rrc_ptr->cell_reselector.launch()) {
|
||||
rrc_ptr->logger.error("Failed to initiate a Cell Reselection procedure...");
|
||||
return;
|
||||
}
|
||||
rrc_ptr->callback_list.add_proc(rrc_ptr->cell_reselector);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Cell Reselection procedure
|
||||
|
@ -1393,9 +1396,9 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
|
|||
reest_cellid = rrc_ptr->meas_cells.find_cell(reest_source_freq, reest_source_pci)->get_cell_id();
|
||||
|
||||
Info("Starting... cause: \"%s\", UE context: {C-RNTI=0x%x, PCI=%d, CELL ID=%d}",
|
||||
reest_cause == asn1::rrc::reest_cause_opts::recfg_fail
|
||||
? "Reconfiguration failure"
|
||||
: cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure",
|
||||
reest_cause == asn1::rrc::reest_cause_opts::recfg_fail ? "Reconfiguration failure"
|
||||
: cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure"
|
||||
: "Other failure",
|
||||
reest_rnti,
|
||||
reest_source_pci,
|
||||
reest_cellid);
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
void set_config_mbsfn_sib2(srsran::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
|
||||
void set_config_mbsfn_sib13(const srsran::sib13_t& sib13) override {}
|
||||
void set_config_mbsfn_mcch(const srsran::mcch_msg_t& mcch) override {}
|
||||
bool cell_search() override { return true; }
|
||||
bool cell_search(int earfcn) override { return true; }
|
||||
bool cell_is_camping() override { return true; }
|
||||
void deactivate_scells() override {}
|
||||
bool cell_select(phy_cell_t cell) override
|
||||
|
|
|
@ -90,7 +90,7 @@ int test_phy_ctrl_fsm()
|
|||
TESTASSERT(phy_ctrl.is_in_sync());
|
||||
|
||||
// TEST: Correct initiation of Cell Search state
|
||||
TESTASSERT(phy_ctrl.start_cell_search(csearch_tester));
|
||||
TESTASSERT(phy_ctrl.start_cell_search(csearch_tester, -1));
|
||||
TESTASSERT(not phy_ctrl.is_in_sync());
|
||||
|
||||
// TEST: Cell Search only listens to a cell search result event
|
||||
|
|
|
@ -34,7 +34,7 @@ using namespace asn1;
|
|||
using namespace srsran;
|
||||
namespace srsue {
|
||||
|
||||
const char* rrc_nr::rrc_nr_state_text[] = {"IDLE", "CONNECTED", "CONNECTED-INACTIVE"};
|
||||
const static char* rrc_nr_state_text[] = {"IDLE", "CONNECTED", "CONNECTED-INACTIVE"};
|
||||
|
||||
rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) :
|
||||
logger(srslog::fetch_basic_logger("RRC-NR")),
|
||||
|
@ -71,9 +71,15 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_,
|
|||
stack = stack_;
|
||||
args = args_;
|
||||
|
||||
plmn_is_selected = true; // short-cut SA test
|
||||
|
||||
// allocate RRC timers
|
||||
t300 = task_sched.get_unique_timer();
|
||||
t301 = task_sched.get_unique_timer();
|
||||
t302 = task_sched.get_unique_timer();
|
||||
t304 = task_sched.get_unique_timer();
|
||||
t310 = task_sched.get_unique_timer();
|
||||
t311 = task_sched.get_unique_timer();
|
||||
|
||||
plmn_is_selected = true; // short-cut SA test
|
||||
|
||||
running = true;
|
||||
sim_measurement_timer = task_sched.get_unique_timer();
|
||||
|
@ -104,7 +110,11 @@ void rrc_nr::init_core_less()
|
|||
pdcp->add_bearer(args.coreless.drb_lcid, pdcp_cnfg);
|
||||
return;
|
||||
}
|
||||
void rrc_nr::get_metrics(rrc_nr_metrics_t& m) {}
|
||||
|
||||
void rrc_nr::get_metrics(rrc_nr_metrics_t& m)
|
||||
{
|
||||
m.state = state;
|
||||
}
|
||||
|
||||
const char* rrc_nr::get_rb_name(uint32_t lcid)
|
||||
{
|
||||
|
@ -255,7 +265,7 @@ void rrc_nr::decode_dl_ccch(unique_byte_buffer_t pdu)
|
|||
case dl_ccch_msg_type_c::c1_c_::types::rrc_reject: {
|
||||
// 5.3.15
|
||||
const auto& reject = c1->rrc_reject();
|
||||
srsran::console("Received RRC Reject");
|
||||
srsran::console("Received RRC Reject\n");
|
||||
|
||||
t300.stop();
|
||||
|
||||
|
@ -275,7 +285,6 @@ void rrc_nr::decode_dl_ccch(unique_byte_buffer_t pdu)
|
|||
task_sched.defer_task([this, rrc_setup_copy]() { handle_rrc_setup(rrc_setup_copy); });
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
logger.error("The provided DL-CCCH message type is not recognized");
|
||||
break;
|
||||
|
@ -349,6 +358,11 @@ void rrc_nr::handle_sib1(const sib1_s& sib1)
|
|||
{
|
||||
logger.info("SIB1 received, CellID=%d", meas_cells.serving_cell().get_cell_id() & 0xfff);
|
||||
|
||||
meas_cells.serving_cell().set_sib1(sib1);
|
||||
|
||||
// TODO: config basic config and remove early exit
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
// unhandled fields:
|
||||
// - cellSelectionInfo
|
||||
|
@ -611,7 +625,7 @@ void rrc_nr::send_setup_request(srsran::nr_establishment_cause_t cause)
|
|||
for (uint i = 0; i < 5; i++) { // fill random ID bytewise, 40 bits = 5 bytes
|
||||
random_id |= ((uint64_t)rand() & 0xFF) << i * 8;
|
||||
}
|
||||
rrc_setup_req->ue_id.random_value().from_number(random_id);
|
||||
rrc_setup_req->ue_id.random_value().from_number(random_id, rrc_setup_req->ue_id.random_value().length());
|
||||
rrc_setup_req->establishment_cause = (establishment_cause_opts::options)cause;
|
||||
|
||||
send_ul_ccch_msg(ul_ccch_msg);
|
||||
|
@ -692,6 +706,16 @@ void rrc_nr::send_con_setup_complete(srsran::unique_byte_buffer_t nas_msg)
|
|||
send_ul_dcch_msg(srb_to_lcid(nr_srb::srb1), ul_dcch_msg);
|
||||
}
|
||||
|
||||
void rrc_nr::send_rrc_reconfig_complete()
|
||||
{
|
||||
logger.debug("Preparing RRC Connection Reconfig Complete");
|
||||
|
||||
asn1::rrc_nr::ul_dcch_msg_s ul_dcch_msg;
|
||||
auto& rrc_reconfig_complete = ul_dcch_msg.msg.set_c1().set_rrc_recfg_complete().crit_exts.set_rrc_recfg_complete();
|
||||
|
||||
send_ul_dcch_msg(srb_to_lcid(nr_srb::srb1), ul_dcch_msg);
|
||||
}
|
||||
|
||||
// EUTRA-RRC interface
|
||||
int rrc_nr::get_eutra_nr_capabilities(srsran::byte_buffer_t* eutra_nr_caps_pdu)
|
||||
{
|
||||
|
@ -1903,12 +1927,26 @@ bool rrc_nr::apply_drb_add_mod(const drb_to_add_mod_s& drb_cfg)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!(drb_cfg.cn_assoc.type() == drb_to_add_mod_s::cn_assoc_c_::types_opts::eps_bearer_id)) {
|
||||
if (drb_cfg.cn_assoc.type() == drb_to_add_mod_s::cn_assoc_c_::types_opts::eps_bearer_id) {
|
||||
// register EPS bearer over NR PDCP
|
||||
uint32_t eps_bearer_id = drb_cfg.cn_assoc.eps_bearer_id();
|
||||
drb_eps_bearer_id[drb_cfg.drb_id] = eps_bearer_id;
|
||||
stack->add_eps_bearer(eps_bearer_id, srsran::srsran_rat_t::nr, lcid);
|
||||
} else if (drb_cfg.cn_assoc.type() == drb_to_add_mod_s::cn_assoc_c_::types_opts::sdap_cfg) {
|
||||
const auto& sdap_cfg = drb_cfg.cn_assoc.sdap_cfg();
|
||||
if (sdap_cfg.sdap_hdr_dl == asn1::rrc_nr::sdap_cfg_s::sdap_hdr_dl_opts::present ||
|
||||
sdap_cfg.sdap_hdr_ul == asn1::rrc_nr::sdap_cfg_s::sdap_hdr_ul_opts::present) {
|
||||
logger.error("SDAP currently not supported.");
|
||||
return false;
|
||||
}
|
||||
// TODO: configure SDAP accordingly
|
||||
uint32_t pdu_session_id = drb_cfg.cn_assoc.sdap_cfg().pdu_session;
|
||||
// Register PDU session as "EPS bearer" in bearer manager
|
||||
stack->add_eps_bearer(pdu_session_id, srsran::srsran_rat_t::nr, lcid);
|
||||
} else {
|
||||
logger.error("CN association type not supported %s", drb_cfg.cn_assoc.type().to_string());
|
||||
return false;
|
||||
}
|
||||
uint32_t eps_bearer_id = drb_cfg.cn_assoc.eps_bearer_id();
|
||||
drb_eps_bearer_id[drb_cfg.drb_id] = eps_bearer_id;
|
||||
|
||||
if (drb_cfg.pdcp_cfg.drb.pdcp_sn_size_dl_present && drb_cfg.pdcp_cfg.drb.pdcp_sn_size_ul_present &&
|
||||
(drb_cfg.pdcp_cfg.drb.pdcp_sn_size_ul.to_number() != drb_cfg.pdcp_cfg.drb.pdcp_sn_size_dl.to_number())) {
|
||||
|
@ -1919,9 +1957,6 @@ bool rrc_nr::apply_drb_add_mod(const drb_to_add_mod_s& drb_cfg)
|
|||
srsran::pdcp_config_t pdcp_cfg = make_drb_pdcp_config_t(drb_cfg.drb_id, true, drb_cfg.pdcp_cfg);
|
||||
pdcp->add_bearer(lcid, pdcp_cfg);
|
||||
|
||||
// register EPS bearer over NR PDCP
|
||||
stack->add_eps_bearer(eps_bearer_id, srsran::srsran_rat_t::nr, lcid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2094,12 +2129,11 @@ void rrc_nr::handle_security_mode_command(const asn1::rrc_nr::security_mode_cmd_
|
|||
// Security helper used by Security Mode Command and Mobility handling routines
|
||||
void rrc_nr::generate_as_keys()
|
||||
{
|
||||
uint8_t k_asme[32] = {};
|
||||
// FIXME: need to add
|
||||
// nas->get_k_asme(k_asme, 32);
|
||||
logger.debug(k_asme, 32, "UE K_asme");
|
||||
// logger.debug("Generating K_enb with UL NAS COUNT: %d", nas->get_k_enb_count());
|
||||
// usim->generate_as_keys(k_asme, nas->get_k_enb_count(), &sec_cfg);
|
||||
as_key_t k_amf = {};
|
||||
nas->get_k_amf(k_amf);
|
||||
logger.debug(k_amf.data(), 32, "UE K_amf");
|
||||
logger.debug("Generating K_gnb with UL NAS COUNT: %d", nas->get_ul_nas_count());
|
||||
usim->generate_nr_as_keys(k_amf, nas->get_ul_nas_count(), &sec_cfg);
|
||||
logger.info(sec_cfg.k_rrc_enc.data(), 32, "RRC encryption key - k_rrc_enc");
|
||||
logger.info(sec_cfg.k_rrc_int.data(), 32, "RRC integrity key - k_rrc_int");
|
||||
logger.info(sec_cfg.k_up_enc.data(), 32, "UP encryption key - k_up_enc");
|
||||
|
|
|
@ -100,23 +100,6 @@ proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator
|
|||
}
|
||||
}
|
||||
|
||||
if (rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size() > 0) {
|
||||
srsran::unique_byte_buffer_t nas_sdu;
|
||||
for (uint32_t i = 0; i < rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size(); ++i) {
|
||||
nas_sdu = srsran::make_byte_buffer();
|
||||
if (nas_sdu != nullptr) {
|
||||
memcpy(nas_sdu->msg,
|
||||
rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list[i].data(),
|
||||
rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list[i].size());
|
||||
nas_sdu->N_bytes = rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list[i].size();
|
||||
rrc_handle.write_sdu(std::move(nas_sdu));
|
||||
} else {
|
||||
rrc_handle.logger.error("Couldn't allocate SDU in %s.", __FUNCTION__);
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rrc_nr_reconf.crit_exts.rrc_recfg().radio_bearer_cfg_present) {
|
||||
Info("Applying Radio Bearer Cfg.");
|
||||
if (!rrc_handle.apply_radio_bearer_cfg(rrc_nr_reconf.crit_exts.rrc_recfg().radio_bearer_cfg)) {
|
||||
|
@ -124,6 +107,25 @@ proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator
|
|||
}
|
||||
}
|
||||
|
||||
rrc_handle.send_rrc_reconfig_complete();
|
||||
|
||||
// Handle NAS messages
|
||||
if (rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size() > 0) {
|
||||
for (uint32_t i = 0; i < rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size(); ++i) {
|
||||
srsran::unique_byte_buffer_t nas_pdu = srsran::make_byte_buffer();
|
||||
if (nas_pdu != nullptr) {
|
||||
memcpy(nas_pdu->msg,
|
||||
rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list[i].data(),
|
||||
rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list[i].size());
|
||||
nas_pdu->N_bytes = rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list[i].size();
|
||||
rrc_handle.nas->write_pdu(std::move(nas_pdu));
|
||||
} else {
|
||||
rrc_handle.logger.error("Couldn't allocate SDU in %s.", __FUNCTION__);
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return proc_outcome_t::success;
|
||||
}
|
||||
|
||||
|
@ -317,7 +319,7 @@ srsran::proc_outcome_t rrc_nr::connection_setup_proc::init(const asn1::rrc_nr::r
|
|||
{
|
||||
Info("Starting...");
|
||||
|
||||
if (dedicated_info_nas_) {
|
||||
if (dedicated_info_nas_ == nullptr) {
|
||||
logger.error("Connection Setup Failed, no dedicatedInfoNAS available");
|
||||
return proc_outcome_t::error;
|
||||
}
|
||||
|
@ -436,6 +438,17 @@ rrc_nr::cell_selection_proc::handle_cell_search_result(const rrc_interface_phy_n
|
|||
// until cell selection is done, update PHY config to take the last found PCI
|
||||
rrc_handle.phy_cfg.carrier.pci = result.pci;
|
||||
|
||||
// Until SI acquisition is implemented, provide hard-coded SIB for now
|
||||
uint8_t msg[] = {0x74, 0x81, 0x01, 0x70, 0x10, 0x40, 0x04, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x33, 0x60, 0x38,
|
||||
0x05, 0x01, 0x00, 0x40, 0x1a, 0x00, 0x00, 0x06, 0x6c, 0x6d, 0x92, 0x21, 0xf3, 0x70, 0x40, 0x20,
|
||||
0x00, 0x00, 0x80, 0x80, 0x00, 0x41, 0x06, 0x80, 0xa0, 0x90, 0x9c, 0x20, 0x08, 0x55, 0x19, 0x40,
|
||||
0x00, 0x00, 0x33, 0xa1, 0xc6, 0xd9, 0x22, 0x40, 0x00, 0x00, 0x20, 0xb8, 0x94, 0x63, 0xc0, 0x09,
|
||||
0x28, 0x44, 0x1b, 0x7e, 0xad, 0x8e, 0x1d, 0x00, 0x9e, 0x2d, 0xa3, 0x0a};
|
||||
srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer();
|
||||
memcpy(pdu->msg, msg, sizeof(msg));
|
||||
pdu->N_bytes = sizeof(msg);
|
||||
rrc_handle.write_pdu_bcch_dlsch(std::move(pdu));
|
||||
|
||||
if (not rrc_handle.phy->start_cell_select(cs_args)) {
|
||||
Error("Could not set start cell search.");
|
||||
return proc_outcome_t::error;
|
||||
|
|
|
@ -119,10 +119,13 @@ class dummy_eutra : public rrc_eutra_interface_rrc_nr
|
|||
class dummy_nas : public nas_5g_interface_rrc_nr
|
||||
{
|
||||
int write_pdu(srsran::unique_byte_buffer_t pdu) { return SRSRAN_SUCCESS; };
|
||||
int get_k_amf(srsran::as_key_t& k_amf) { return SRSRAN_SUCCESS; };
|
||||
uint32_t get_ul_nas_count() { return SRSRAN_SUCCESS; };
|
||||
};
|
||||
|
||||
class dummy_sim : public usim_interface_rrc_nr
|
||||
{
|
||||
void generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg){};
|
||||
bool generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg) { return true; }
|
||||
bool update_nr_context(srsran::as_security_config_t* sec_cfg) { return true; }
|
||||
};
|
||||
|
|
|
@ -237,8 +237,6 @@ int ue_stack_lte::init(const stack_args_t& args_)
|
|||
args.rrc_nr);
|
||||
rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &rrc_nr, args.rrc);
|
||||
|
||||
args.nas_5g.ia5g = "0,1,2,3";
|
||||
args.nas_5g.ea5g = "0,1,2,3";
|
||||
nas_5g.init(usim.get(), &rrc_nr, gw, args.nas_5g);
|
||||
|
||||
running = true;
|
||||
|
@ -339,7 +337,13 @@ bool ue_stack_lte::disable_data()
|
|||
bool ue_stack_lte::start_service_request()
|
||||
{
|
||||
if (running) {
|
||||
ue_task_queue.try_push([this]() { nas.start_service_request(srsran::establishment_cause_t::mo_data); });
|
||||
ue_task_queue.try_push([this]() {
|
||||
if (args.attach_on_nr) {
|
||||
nas_5g.start_service_request();
|
||||
} else {
|
||||
nas.start_service_request(srsran::establishment_cause_t::mo_data);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -355,6 +359,7 @@ bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
|
|||
rlc.get_metrics(metrics.rlc, metrics.mac[0].nof_tti);
|
||||
nas.get_metrics(&metrics.nas);
|
||||
rrc.get_metrics(metrics.rrc);
|
||||
rrc_nr.get_metrics(metrics.rrc_nr);
|
||||
pending_stack_metrics.push(metrics);
|
||||
});
|
||||
// wait for result
|
||||
|
|
|
@ -302,6 +302,11 @@ int nas_5g::send_registration_request()
|
|||
}
|
||||
}
|
||||
|
||||
if (has_sec_ctxt) {
|
||||
set_k_gnb_count(ctxt_base.tx_count);
|
||||
ctxt_base.tx_count++;
|
||||
}
|
||||
|
||||
state.set_registered_initiated();
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
@ -462,6 +467,7 @@ int nas_5g::send_security_mode_complete(const srsran::nas_5g::security_mode_comm
|
|||
pcap->write_nas(pdu.get()->msg, pdu.get()->N_bytes);
|
||||
}
|
||||
|
||||
has_sec_ctxt = true;
|
||||
logger.info("Sending Security Mode Complete");
|
||||
rrc_nr->write_sdu(std::move(pdu));
|
||||
ctxt_base.tx_count++;
|
||||
|
@ -807,6 +813,7 @@ int nas_5g::handle_registration_accept(registration_accept_t& registration_accep
|
|||
int nas_5g::handle_registration_reject(registration_reject_t& registration_reject)
|
||||
{
|
||||
logger.info("Handling Registration Reject");
|
||||
has_sec_ctxt = false;
|
||||
ctxt_base.rx_count++;
|
||||
state.set_deregistered(mm5g_state_t::deregistered_substate_t::plmn_search);
|
||||
|
||||
|
@ -854,6 +861,7 @@ int nas_5g::handle_authentication_request(authentication_request_t& authenticati
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
initial_sec_command = true;
|
||||
uint8_t res_star[16];
|
||||
|
||||
logger.info(authentication_request.authentication_parameter_rand.rand.data(),
|
||||
|
@ -897,6 +905,7 @@ int nas_5g::handle_authentication_request(authentication_request_t& authenticati
|
|||
int nas_5g::handle_authentication_reject(srsran::nas_5g::authentication_reject_t& authentication_reject)
|
||||
{
|
||||
logger.info("Handling Authentication Reject");
|
||||
has_sec_ctxt = false;
|
||||
ctxt_base.rx_count++;
|
||||
state.set_deregistered(mm5g_state_t::deregistered_substate_t::plmn_search);
|
||||
return SRSRAN_SUCCESS;
|
||||
|
@ -920,6 +929,7 @@ int nas_5g::handle_service_accept(srsran::nas_5g::service_accept_t& service_acce
|
|||
int nas_5g::handle_service_reject(srsran::nas_5g::service_reject_t& service_reject)
|
||||
{
|
||||
logger.info("Handling Service Reject");
|
||||
has_sec_ctxt = false;
|
||||
ctxt_base.rx_count++;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
@ -941,10 +951,8 @@ int nas_5g::handle_security_mode_command(security_mode_command_t& security_m
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
initial_sec_command = false; // TODO
|
||||
|
||||
if (initial_sec_command) {
|
||||
ctxt_base.rx_count = 0;
|
||||
set_k_gnb_count(0);
|
||||
ctxt_base.tx_count = 0;
|
||||
initial_sec_command = false;
|
||||
}
|
||||
|
@ -1115,6 +1123,27 @@ void nas_5g::get_metrics(nas_5g_metrics_t& metrics)
|
|||
metrics.state = state.get_state();
|
||||
}
|
||||
|
||||
int nas_5g::get_k_amf(as_key_t& k_amf)
|
||||
{
|
||||
if (not has_sec_ctxt) {
|
||||
logger.error("K_amf requested before a valid NAS security context was established");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
std::copy(std::begin(ctxt_5g.k_amf), std::end(ctxt_5g.k_amf), k_amf.begin());
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t nas_5g::get_ul_nas_count()
|
||||
{
|
||||
return ctxt_5g.k_gnb_count;
|
||||
}
|
||||
|
||||
void nas_5g::set_k_gnb_count(uint32_t count)
|
||||
{
|
||||
ctxt_5g.k_gnb_count = count;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Helpers
|
||||
******************************************************************************/
|
||||
|
|
|
@ -231,6 +231,7 @@ void usim_base::generate_nas_keys(uint8_t* k_asme,
|
|||
/*
|
||||
* RRC Interface
|
||||
*/
|
||||
|
||||
void usim_base::generate_as_keys(uint8_t* k_asme_, uint32_t count_ul, srsran::as_security_config_t* sec_cfg)
|
||||
{
|
||||
if (!initiated) {
|
||||
|
@ -376,6 +377,42 @@ bool usim_base::generate_nas_keys_5g(uint8_t* k_amf,
|
|||
* NR RRC Interface
|
||||
*/
|
||||
|
||||
void usim_base::generate_nr_as_keys(srsran::as_key_t& k_amf, uint32_t count_ul, srsran::as_security_config_t* sec_cfg)
|
||||
{
|
||||
if (!initiated) {
|
||||
logger.error("USIM not initiated!");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Generating NR AS Keys. NAS UL COUNT %d", count_ul);
|
||||
logger.debug(k_amf.data(), 32, "K_amf");
|
||||
|
||||
// Generate K_gnb
|
||||
srsran::security_generate_k_gnb(k_amf, count_ul, k_gnb_ctx.k_gnb);
|
||||
logger.info(k_gnb_ctx.k_gnb.data(), 32, "K_gnb");
|
||||
|
||||
// Save initial k_gnb
|
||||
k_gnb_initial = k_gnb_ctx.k_gnb;
|
||||
|
||||
security_generate_k_nr_rrc(k_gnb_ctx.k_gnb.data(),
|
||||
sec_cfg->cipher_algo,
|
||||
sec_cfg->integ_algo,
|
||||
sec_cfg->k_rrc_enc.data(),
|
||||
sec_cfg->k_rrc_int.data());
|
||||
|
||||
security_generate_k_nr_up(k_gnb_ctx.k_gnb.data(),
|
||||
sec_cfg->cipher_algo,
|
||||
sec_cfg->integ_algo,
|
||||
sec_cfg->k_up_enc.data(),
|
||||
sec_cfg->k_up_int.data());
|
||||
|
||||
logger.info(k_gnb_ctx.k_gnb.data(), 32, "Initial K_gnb");
|
||||
logger.info(sec_cfg->k_rrc_int.data(), sec_cfg->k_rrc_int.size(), "NR K_RRC_int");
|
||||
logger.info(sec_cfg->k_rrc_enc.data(), sec_cfg->k_rrc_enc.size(), "NR K_RRC_enc");
|
||||
logger.info(sec_cfg->k_up_int.data(), sec_cfg->k_up_int.size(), "NR K_UP_int");
|
||||
logger.info(sec_cfg->k_up_enc.data(), sec_cfg->k_up_enc.size(), "NR K_UP_enc");
|
||||
}
|
||||
|
||||
bool usim_base::generate_nr_context(uint16_t sk_counter, srsran::as_security_config_t* sec_cfg)
|
||||
{
|
||||
if (!initiated) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
|
||||
#include "srsran/common/metrics_hub.h"
|
||||
#include "srsran/srsran.h"
|
||||
#include "srsran/common/test_common.h"
|
||||
#include "srsue/hdr/metrics_csv.h"
|
||||
#include "srsue/hdr/metrics_stdout.h"
|
||||
#include "srsue/hdr/ue_metrics_interface.h"
|
||||
|
@ -34,10 +34,12 @@ using namespace srsue;
|
|||
|
||||
namespace srsue {
|
||||
|
||||
char* csv_file_name = NULL;
|
||||
static char* csv_file_name = NULL;
|
||||
static float period = 1.0;
|
||||
static int duration_s = 5;
|
||||
|
||||
// fake classes
|
||||
class ue_dummy : public ue_metrics_interface
|
||||
class eutra_ue_dummy : public ue_metrics_interface
|
||||
{
|
||||
public:
|
||||
bool get_metrics(ue_metrics_t* m)
|
||||
|
@ -72,6 +74,51 @@ public:
|
|||
m->phy.nof_active_cc = 1;
|
||||
m->phy.ch[0].rsrp = -10.0f;
|
||||
m->phy.ch[0].pathloss = 32;
|
||||
|
||||
m->stack.rrc.state = (rand() % 2 == 0) ? RRC_STATE_CONNECTED : RRC_STATE_IDLE;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class nsa_ue_dummy : public ue_metrics_interface
|
||||
{
|
||||
public:
|
||||
bool get_metrics(ue_metrics_t* m)
|
||||
{
|
||||
*m = {};
|
||||
|
||||
// fill dummy values
|
||||
m->rf.rf_o = 10;
|
||||
m->phy.nof_active_cc = 1;
|
||||
m->phy.ch[0].rsrp = -10.0f;
|
||||
m->phy.ch[0].pathloss = 74;
|
||||
m->stack.mac[0].rx_pkts = 100;
|
||||
m->stack.mac[0].rx_errors = 0;
|
||||
m->stack.mac[0].rx_brate = 200;
|
||||
m->stack.mac[0].nof_tti = 1;
|
||||
|
||||
m->phy.info[1].pci = UINT32_MAX;
|
||||
m->stack.mac[1].rx_pkts = 100;
|
||||
m->stack.mac[1].rx_errors = 100;
|
||||
m->stack.mac[1].rx_brate = 150;
|
||||
m->stack.mac[1].nof_tti = 1;
|
||||
|
||||
// random neighbour cells
|
||||
if (rand() % 2 == 0) {
|
||||
phy_meas_t neighbor = {};
|
||||
neighbor.pci = 8;
|
||||
neighbor.rsrp = -33;
|
||||
m->stack.rrc.neighbour_cells.push_back(neighbor);
|
||||
m->stack.rrc.neighbour_cells.push_back(neighbor); // need to add twice since we use CA
|
||||
}
|
||||
|
||||
m->phy.nof_active_cc = 1;
|
||||
m->phy.ch[0].rsrp = -10.0f;
|
||||
m->phy.ch[0].pathloss = 32;
|
||||
|
||||
// NR
|
||||
m->phy_nr.nof_active_cc = 1;
|
||||
m->stack.mac_nr[0].rx_pkts = 100;
|
||||
m->stack.mac_nr[0].rx_errors = 2;
|
||||
m->stack.mac_nr[0].rx_brate = 223;
|
||||
|
@ -83,6 +130,31 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class sa_ue_dummy : public ue_metrics_interface
|
||||
{
|
||||
public:
|
||||
bool get_metrics(ue_metrics_t* m)
|
||||
{
|
||||
*m = {};
|
||||
|
||||
// fill dummy values
|
||||
m->rf.rf_o = 10;
|
||||
m->phy.nof_active_cc = 0;
|
||||
|
||||
// NR
|
||||
m->phy_nr.nof_active_cc = 1;
|
||||
m->phy_nr.info[0].pci = 501;
|
||||
m->stack.mac_nr[0].rx_pkts = 100;
|
||||
m->stack.mac_nr[0].rx_errors = 2;
|
||||
m->stack.mac_nr[0].rx_brate = 223;
|
||||
m->stack.mac_nr[0].nof_tti = 1;
|
||||
|
||||
m->stack.rrc_nr.state = (rand() % 2 == 0) ? RRC_NR_STATE_CONNECTED : RRC_NR_STATE_IDLE;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
void usage(char* prog)
|
||||
|
@ -110,11 +182,35 @@ void parse_args(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
int ue_test(std::string name, ue_metrics_interface* ue)
|
||||
{
|
||||
// the default metrics type for stdout output
|
||||
metrics_stdout metrics_screen;
|
||||
metrics_screen.set_ue_handle(ue);
|
||||
|
||||
// the CSV file writer
|
||||
metrics_csv metrics_file(csv_file_name);
|
||||
metrics_file.set_ue_handle(ue);
|
||||
|
||||
// create metrics hub and register metrics for stdout
|
||||
srsran::metrics_hub<ue_metrics_t> metricshub;
|
||||
metricshub.init(ue, period);
|
||||
metricshub.add_listener(&metrics_screen);
|
||||
metricshub.add_listener(&metrics_file);
|
||||
|
||||
// enable printing
|
||||
metrics_screen.toggle_print(true);
|
||||
|
||||
std::cout << "Running " << name << " UE test for " << duration_s << " seconds .." << std::endl;
|
||||
usleep(duration_s * 1e6);
|
||||
|
||||
metricshub.stop();
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
float period = 1.0;
|
||||
ue_dummy ue;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
|
@ -122,26 +218,14 @@ int main(int argc, char** argv)
|
|||
|
||||
parse_args(argc, argv);
|
||||
|
||||
// the default metrics type for stdout output
|
||||
metrics_stdout metrics_screen;
|
||||
metrics_screen.set_ue_handle(&ue);
|
||||
eutra_ue_dummy eutra_ue;
|
||||
TESTASSERT_SUCCESS(ue_test("EUTRA", &eutra_ue));
|
||||
|
||||
// the CSV file writer
|
||||
metrics_csv metrics_file(csv_file_name);
|
||||
metrics_file.set_ue_handle(&ue);
|
||||
nsa_ue_dummy nsa_ue;
|
||||
TESTASSERT_SUCCESS(ue_test("NSA", &nsa_ue));
|
||||
|
||||
// create metrics hub and register metrics for stdout
|
||||
srsran::metrics_hub<ue_metrics_t> metricshub;
|
||||
metricshub.init(&ue, period);
|
||||
metricshub.add_listener(&metrics_screen);
|
||||
metricshub.add_listener(&metrics_file);
|
||||
sa_ue_dummy sa_ue;
|
||||
TESTASSERT_SUCCESS(ue_test("SA", &sa_ue));
|
||||
|
||||
// enable printing
|
||||
metrics_screen.toggle_print(true);
|
||||
|
||||
std::cout << "Running for 5 seconds .." << std::endl;
|
||||
usleep(5e6);
|
||||
|
||||
metricshub.stop();
|
||||
return 0;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
void set_mch_period_stop(uint32_t stop) override{};
|
||||
|
||||
// Cell search and selection procedures
|
||||
bool cell_search() override;
|
||||
bool cell_search(int earfcn) override;
|
||||
bool cell_select(phy_cell_t cell) override;
|
||||
bool cell_is_camping() override;
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ void lte_ttcn3_phy::meas_stop() {}
|
|||
// configured by the SS, including the ones that we should not even detect because
|
||||
// their power is too weak. The cell search should only report the cells that
|
||||
// are actually visible though.
|
||||
bool lte_ttcn3_phy::cell_search()
|
||||
bool lte_ttcn3_phy::cell_search(int earfcn)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(phy_mutex);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ int ue::init(const all_args_t& args_)
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
std::unique_ptr<gw> gw_ptr(new gw(srslog::fetch_basic_logger("GW")));
|
||||
std::unique_ptr<gw> gw_ptr(new gw(srslog::fetch_basic_logger("GW", false)));
|
||||
if (!gw_ptr) {
|
||||
srsran::console("Error creating a GW instance.\n");
|
||||
return SRSRAN_ERROR;
|
||||
|
@ -285,6 +285,11 @@ int ue::parse_args(const all_args_t& args_)
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Update NAS-5G args
|
||||
args.stack.nas_5g.ia5g = args.stack.nas.eia;
|
||||
args.stack.nas_5g.ea5g = args.stack.nas.eea;
|
||||
args.stack.nas_5g.pdu_session_cfgs.push_back({args.stack.nas.apn_name});
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue