Merge branch 'next' into agpl_next

This commit is contained in:
Codebot 2022-07-31 21:12:25 +00:00 committed by SRS codebot
commit 234f99de24
27 changed files with 561 additions and 96 deletions

View File

@ -1,6 +1,12 @@
Change Log for Releases
=======================
## 22.04.1
* Various bug fixes in RLC AM and PDCP for NR
* Fix crash when UE attempted to reestablish in SA
* Remove fixed coreset0 index for SSB
* Add support for SIB5 and SIB6 transmission in LTE
## 22.04
* Added baseline 5G-SA support to srsUE and srsENB
* Added dynamic loading of RF libraries

View File

@ -20,6 +20,6 @@
SET(SRSRAN_VERSION_MAJOR 22)
SET(SRSRAN_VERSION_MINOR 04)
SET(SRSRAN_VERSION_PATCH 0)
SET(SRSRAN_VERSION_PATCH 1)
SET(SRSRAN_VERSION_STRING "${SRSRAN_VERSION_MAJOR}.${SRSRAN_VERSION_MINOR}.${SRSRAN_VERSION_PATCH}")
SET(SRSRAN_SOVERSION 0)

View File

@ -2430,6 +2430,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_security_protected_nas_msg(LIBLTE_BYTE_MSG_STR
#define LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_IEI 0x64
#define LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_IEI 0xF
#define LIBLTE_MME_T3412_EXTENDED_VALUE_IEI 0x5E
#define LIBLTE_MME_ADDITIONAL_INFORMATION_IEI 0x65
// Enums
// Structs
typedef struct {

View File

@ -7600,7 +7600,11 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_downlink_generic_nas_transport_msg(
liblte_mme_pack_generic_message_container_ie(&dl_generic_nas_transport->generic_msg_cont, &msg_ptr);
// Additional Information
liblte_mme_pack_additional_information_ie(&dl_generic_nas_transport->add_info, &msg_ptr);
if (dl_generic_nas_transport->add_info_present) {
*msg_ptr = LIBLTE_MME_ADDITIONAL_INFORMATION_IEI;
msg_ptr++;
liblte_mme_pack_additional_information_ie(&dl_generic_nas_transport->add_info, &msg_ptr);
}
// Fill in the number of bytes used
msg->N_bytes = msg_ptr - msg->msg;
@ -7637,8 +7641,13 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_downlink_generic_nas_transport_msg(
liblte_mme_unpack_generic_message_container_ie(&msg_ptr, &dl_generic_nas_transport->generic_msg_cont);
// Additional Information
liblte_mme_unpack_additional_information_ie(&msg_ptr, &dl_generic_nas_transport->add_info);
if (LIBLTE_MME_ADDITIONAL_INFORMATION_IEI == *msg_ptr) {
msg_ptr++;
liblte_mme_unpack_additional_information_ie(&msg_ptr, &dl_generic_nas_transport->add_info);
dl_generic_nas_transport->add_info_present = true;
} else {
dl_generic_nas_transport->add_info_present = false;
}
err = LIBLTE_SUCCESS;
}
@ -9053,7 +9062,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_deactivate_eps_bearer_context_request_msg(
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and EPS Bearer ID
*msg_ptr = (deact_eps_bearer_context_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++;

View File

@ -20,19 +20,12 @@
*/
#include "srsran/asn1/liblte_mme.h"
#include "srsran/common/test_common.h"
#include "srsran/srslog/srslog.h"
#include <iostream>
#include <srsran/common/buffer_pool.h>
#include <srsran/common/int_helpers.h>
#define TESTASSERT(cond) \
{ \
if (!(cond)) { \
std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \
return -1; \
} \
}
int nas_dedicated_eps_bearer_context_setup_request_test()
{
auto& nas_logger = srslog::fetch_basic_logger("NAS", false);
@ -112,7 +105,95 @@ int nas_dedicated_eps_bearer_context_setup_request_test()
srslog::flush();
printf("Test NAS Activate Dedicated EPS Bearer Context Request successfull\n");
return 0;
return SRSRAN_SUCCESS;
}
int downlink_generic_nas_transport_unpacking_test()
{
uint8_t nas_message[] = {
0x27, 0xae, 0x80, 0xc8, 0xf9, 0x06, 0x07, 0x68, 0x01, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x08, 0x70};
srsran::unique_byte_buffer_t buf;
LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT dl_generic_nas_transport;
LIBLTE_ERROR_ENUM err;
copy_msg_to_buffer(buf, nas_message);
err = liblte_mme_unpack_downlink_generic_nas_transport_msg((LIBLTE_BYTE_MSG_STRUCT*)buf.get(),
&dl_generic_nas_transport);
TESTASSERT(err == LIBLTE_SUCCESS);
TESTASSERT(dl_generic_nas_transport.generic_msg_cont_type == 1);
TESTASSERT(dl_generic_nas_transport.generic_msg_cont.N_bytes == 6);
TESTASSERT(dl_generic_nas_transport.add_info_present == false);
return SRSRAN_SUCCESS;
}
int downlink_generic_nas_transport_packing_test()
{
uint8_t nas_message[] = {
0x27, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x68, 0x01, 0x00, 0x06, 0xf0, 0x00, 0x00, 0x00, 0x08, 0x70};
uint8_t generic_msg_cont[] = {0xf0, 0x00, 0x00, 0x00, 0x08, 0x70};
LIBLTE_BYTE_MSG_STRUCT buf;
LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT dl_generic_nas_transport;
LIBLTE_ERROR_ENUM err;
dl_generic_nas_transport.generic_msg_cont_type = 1;
dl_generic_nas_transport.generic_msg_cont.N_bytes = sizeof(generic_msg_cont);
memcpy(dl_generic_nas_transport.generic_msg_cont.msg, generic_msg_cont, sizeof(generic_msg_cont));
dl_generic_nas_transport.add_info_present = false;
err = liblte_mme_pack_downlink_generic_nas_transport_msg(
&dl_generic_nas_transport, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, 0xffffffff, &buf);
TESTASSERT(err == LIBLTE_SUCCESS);
TESTASSERT(buf.N_bytes == sizeof(nas_message));
TESTASSERT(memcmp(buf.msg, nas_message, buf.N_bytes) == 0);
return SRSRAN_SUCCESS;
}
int downlink_generic_nas_transport_with_add_info_unpacking_test()
{
uint8_t nas_message[] = {0x27, 0xae, 0x80, 0xc8, 0xf9, 0x06, 0x07, 0x68, 0x01, 0x00, 0x06,
0xf0, 0x00, 0x00, 0x00, 0x08, 0x70, 0x65, 0x02, 0x11, 0x11};
srsran::unique_byte_buffer_t buf;
LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT dl_generic_nas_transport;
LIBLTE_ERROR_ENUM err;
copy_msg_to_buffer(buf, nas_message);
err = liblte_mme_unpack_downlink_generic_nas_transport_msg((LIBLTE_BYTE_MSG_STRUCT*)buf.get(),
&dl_generic_nas_transport);
TESTASSERT(err == LIBLTE_SUCCESS);
TESTASSERT(dl_generic_nas_transport.generic_msg_cont_type == 1);
TESTASSERT(dl_generic_nas_transport.generic_msg_cont.N_bytes == 6);
TESTASSERT(dl_generic_nas_transport.add_info_present == true);
TESTASSERT(dl_generic_nas_transport.add_info.N_octets == 2);
return SRSRAN_SUCCESS;
}
int downlink_generic_nas_transport_with_add_info_packing_test()
{
uint8_t nas_message[] = {0x27, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x68, 0x01, 0x00, 0x06,
0xf0, 0x00, 0x00, 0x00, 0x08, 0x70, 0x65, 0x02, 0x11, 0x11};
uint8_t generic_msg_cont[] = {0xf0, 0x00, 0x00, 0x00, 0x08, 0x70};
uint8_t add_info[] = {0x11, 0x11};
LIBLTE_BYTE_MSG_STRUCT buf;
LIBLTE_MME_DOWNLINK_GENERIC_NAS_TRANSPORT_MSG_STRUCT dl_generic_nas_transport;
LIBLTE_ERROR_ENUM err;
dl_generic_nas_transport.generic_msg_cont_type = 1;
dl_generic_nas_transport.generic_msg_cont.N_bytes = sizeof(generic_msg_cont);
memcpy(dl_generic_nas_transport.generic_msg_cont.msg, generic_msg_cont, sizeof(generic_msg_cont));
dl_generic_nas_transport.add_info_present = true;
dl_generic_nas_transport.add_info.N_octets = sizeof(add_info);
memcpy(dl_generic_nas_transport.add_info.info, add_info, sizeof(add_info));
err = liblte_mme_pack_downlink_generic_nas_transport_msg(
&dl_generic_nas_transport, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, 0xffffffff, &buf);
TESTASSERT(err == LIBLTE_SUCCESS);
TESTASSERT(buf.N_bytes == sizeof(nas_message));
TESTASSERT(memcmp(buf.msg, nas_message, buf.N_bytes) == 0);
return SRSRAN_SUCCESS;
}
int main(int argc, char** argv)
@ -121,9 +202,13 @@ int main(int argc, char** argv)
asn1_logger.set_level(srslog::basic_levels::debug);
asn1_logger.set_hex_dump_max_size(-1);
srslog::init();
srsran::test_init(argc, argv);
int result = nas_dedicated_eps_bearer_context_setup_request_test();
TESTASSERT(nas_dedicated_eps_bearer_context_setup_request_test() == SRSRAN_SUCCESS);
TESTASSERT(downlink_generic_nas_transport_unpacking_test() == SRSRAN_SUCCESS);
TESTASSERT(downlink_generic_nas_transport_packing_test() == SRSRAN_SUCCESS);
TESTASSERT(downlink_generic_nas_transport_with_add_info_unpacking_test() == SRSRAN_SUCCESS);
TESTASSERT(downlink_generic_nas_transport_with_add_info_packing_test() == SRSRAN_SUCCESS);
return result;
return SRSRAN_SUCCESS;
}

View File

@ -151,6 +151,21 @@ public:
return ret;
}
double get_ssb_freq_hz(uint32_t cc_idx)
{
double ret = 0.0;
if (cc_idx < cell_list_lte.size()) {
ret = cell_list_lte[cc_idx].dl_freq_hz;
}
cc_idx -= cell_list_lte.size();
if (cc_idx < cell_list_nr.size()) {
ret = cell_list_nr[cc_idx].carrier.ssb_center_freq_hz;
}
return ret;
}
uint32_t get_rf_port(uint32_t cc_idx)
{
uint32_t ret = 0;

View File

@ -41,7 +41,7 @@ public:
T(default_paging_cycle_),
Nb(static_cast<uint32_t>((float)T * nb_)),
N(std::min(T, Nb)),
Ns(std::max(1U, Nb)),
Ns(std::max(1U, static_cast<uint32_t>(nb_))),
logger(srslog::fetch_basic_logger("RRC"))
{
for (subframe_info& sf_obj : sf_pending_pcch) {

View File

@ -137,6 +137,71 @@ sib3 =
}
};
#####################################################################
# sib5 configuration options (See TS 36.331)
# Contains information relevant for inter-frequency cell re-selection.
# Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted
#
# inter_freq_carrier_freq_list: A list of neighbouring inter-frequencies.
# dl_carrier_freq: The EARFCN for the EUTRA carrier frequency.
# q_rx_lev_min: Minimum received RSRP level in the E-UTRA cell, ([field_val] * 2) = [level in dBm].
# p_max: Optional maximum allowed transmission power for the neighbouring E-UTRA cells on this carrier frequency.
# t_resel_eutra: Cell reselection timer (seconds).
# t_resel_eutra_sf: Optional speed dependent ScalingFactor for t_resel_eutra.
# sf_medium: Scaling factor if the UE is in Medium Mobility state, one of "0.25", "0.5", "0.75" or "1.0".
# sf_high: Scaling factor if the UE is in High Mobility state, one of "0.25", "0.5", "0.75" or "1.0".
# thresh_x_high: Srclev threshold (dB) to select to a higher-priority RAT/Frequency.
# thresh_x_low: Srclev threshold (dB) to select to a lower-priority RAT/Frequency.
# allowed_meas_bw: Maximum allowed measurement bandwidth on a carrier frequency .
# presence_ant_port_1: whether all the neighbouring cells use Antenna Port 1.
# cell_resel_prio: Optional absolute priority of the carrier frequency group.
# neigh_cell_cfg: Information related to MBSFN and TDD UL/DL configuration of neighbour cells.
# q_offset_freq: Frequency specific offset for equal priority E-UTRAN frequencies.
# inter_freq_neigh_cell_list: A List of inter-frequency neighbouring cells with specific cell re-selection parameters.
# phys_cell_id: Physical layer identity of the cell.
# q_offset_cell: Cell spcific offset.
# inter_freq_black_cell_list: A List of blacklisted inter-frequency neighbouring cells.
# start: The lowest physical cell identity in the range.
# range: The number of physical cell identities in the range.
#
#####################################################################
sib5 =
{
inter_freq_carrier_freq_list =
(
{
dl_carrier_freq = 1450;
q_rx_lev_min = -70;
t_resel_eutra = 2;
t_resel_eutra_sf = {
sf_medium = "0.25";
sf_high = "1.0";
};
thresh_x_high = 3;
thresh_x_low = 2;
allowed_meas_bw = 75;
presence_ant_port_1 = True;
cell_resel_prio = 4;
neigh_cell_cfg = 2;
q_offset_freq = -6;
inter_freq_neigh_cell_list =
(
{
phys_cell_id = 500;
q_offset_cell = 2;
}
);
inter_freq_black_cell_list =
(
{
start = 123;
range = 4;
}
);
}
);
};
#####################################################################
# sib6 configuration options (See TS 36.331)
# Contains UTRA neighbor information for inter-rat handover.

View File

@ -151,6 +151,156 @@ int field_intra_black_cell_list::parse(libconfig::Setting& root)
return 0;
}
int field_inter_freq_carrier_freq_list::parse(libconfig::Setting& root)
{
data->inter_freq_carrier_freq_list.resize((uint32_t)root.getLength());
for (uint32_t i = 0; i < data->inter_freq_carrier_freq_list.size() && i < ASN1_RRC_MAX_FREQ; i++) {
unsigned int dl_carrier_freq = 0;
if (!root[i].lookupValue("dl_carrier_freq", dl_carrier_freq)) {
ERROR("Missing field `dl_carrier_freq` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
data->inter_freq_carrier_freq_list[i].dl_carrier_freq = dl_carrier_freq;
int q_rx_lev_min = 0;
if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) {
ERROR("Missing field `q_rx_lev_min` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
data->inter_freq_carrier_freq_list[i].q_rx_lev_min = q_rx_lev_min;
int p_max = 0;
if (root[i].lookupValue("p_max", p_max)) {
data->inter_freq_carrier_freq_list[i].p_max_present = true;
data->inter_freq_carrier_freq_list[i].p_max = p_max;
}
unsigned int t_resel_eutra = 0;
if (!root[i].lookupValue("t_resel_eutra", t_resel_eutra)) {
ERROR("Missing field `t_resel_eutra` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
data->inter_freq_carrier_freq_list[i].t_resel_eutra = t_resel_eutra;
if (root[i].exists("t_resel_eutra_sf")) {
data->inter_freq_carrier_freq_list[i].t_resel_eutra_sf_present = true;
field_asn1_enum_number_str<asn1::rrc::speed_state_scale_factors_s::sf_medium_e_> sf_medium(
"sf_medium", &data->inter_freq_carrier_freq_list[i].t_resel_eutra_sf.sf_medium);
if (sf_medium.parse(root[i]["t_resel_eutra_sf"])) {
ERROR("Error parsing `sf_medium` in inter_freq_carrier_freq_list=%d t_resel_eutra_sf", i);
return SRSRAN_ERROR;
}
field_asn1_enum_number_str<asn1::rrc::speed_state_scale_factors_s::sf_high_e_> sf_high(
"sf_high", &data->inter_freq_carrier_freq_list[i].t_resel_eutra_sf.sf_high);
if (sf_high.parse(root[i]["t_resel_eutra_sf"])) {
ERROR("Error parsing `sf_high` in inter_freq_carrier_freq_list=%d t_resel_eutra_sf", i);
return SRSRAN_ERROR;
}
}
unsigned int thresh_x_high = 0;
if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) {
ERROR("Missing field `thresh_x_high` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
data->inter_freq_carrier_freq_list[i].thresh_x_high = thresh_x_high;
unsigned int thresh_x_low = 0;
if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) {
ERROR("Missing field `thresh_x_low` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
data->inter_freq_carrier_freq_list[i].thresh_x_low = thresh_x_low;
field_asn1_enum_number<asn1::rrc::allowed_meas_bw_e> allowed_meas_bw(
"allowed_meas_bw", &data->inter_freq_carrier_freq_list[i].allowed_meas_bw);
if (allowed_meas_bw.parse(root[i])) {
ERROR("Error parsing `allowed_meas_bw` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
bool presence_ant_port1 = 0;
if (!root[i].lookupValue("presence_ant_port_1", presence_ant_port1)) {
ERROR("Missing field `presence_ant_port_1` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
data->inter_freq_carrier_freq_list[i].presence_ant_port1 = presence_ant_port1;
unsigned int cell_resel_prio = 0;
if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) {
data->inter_freq_carrier_freq_list[i].cell_resel_prio_present = true;
data->inter_freq_carrier_freq_list[i].cell_resel_prio = cell_resel_prio;
}
field_asn1_enum_number<asn1::rrc::q_offset_range_e> q_offset_freq(
"q_offset_freq", &data->inter_freq_carrier_freq_list[i].q_offset_freq);
if (!q_offset_freq.parse(root[i])) {
data->inter_freq_carrier_freq_list[i].q_offset_freq_present = true;
}
field_asn1_bitstring_number<asn1::fixed_bitstring<2>, uint8_t> neigh_cell_cfg(
"neigh_cell_cfg", &data->inter_freq_carrier_freq_list[i].neigh_cell_cfg);
if (neigh_cell_cfg.parse(root[i])) {
ERROR("Error parsing `neigh_cell_cfg` in inter_freq_carrier_freq_list=%d", i);
return SRSRAN_ERROR;
}
if (root[i].exists("inter_freq_neigh_cell_list")) {
auto inter_neigh_cell_list_parser = new field_inter_freq_neigh_cell_list(&data->inter_freq_carrier_freq_list[i]);
HANDLEPARSERCODE(inter_neigh_cell_list_parser->parse(root[i]["inter_freq_neigh_cell_list"]));
}
if (root[i].exists("inter_freq_black_cell_list")) {
auto inter_black_cell_list_parser = new field_inter_freq_black_cell_list(&data->inter_freq_carrier_freq_list[i]);
HANDLEPARSERCODE(inter_black_cell_list_parser->parse(root[i]["inter_freq_black_cell_list"]));
}
}
return 0;
}
int field_inter_freq_neigh_cell_list::parse(libconfig::Setting& root)
{
data->inter_freq_neigh_cell_list.resize((uint32_t)root.getLength());
data->inter_freq_neigh_cell_list_present = data->inter_freq_neigh_cell_list.size() > 0;
for (uint32_t i = 0; i < data->inter_freq_neigh_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) {
if (not parse_enum_by_number(data->inter_freq_neigh_cell_list[i].q_offset_cell, "q_offset_cell", root[i])) {
ERROR("Missing field q_offset_cell in neigh_cell=%d\n", i);
return SRSRAN_ERROR;
}
unsigned int phys_cell_id = 0;
if (!root[i].lookupValue("phys_cell_id", phys_cell_id)) {
ERROR("Missing field phys_cell_id in neigh_cell=%d\n", i);
return SRSRAN_ERROR;
}
data->inter_freq_neigh_cell_list[i].pci = (uint16)phys_cell_id;
}
return 0;
}
int field_inter_freq_black_cell_list::parse(libconfig::Setting& root)
{
data->inter_freq_black_cell_list.resize((uint32_t)root.getLength());
data->inter_freq_black_cell_list_present = data->inter_freq_black_cell_list.size() > 0;
for (uint32_t i = 0; i < data->inter_freq_black_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) {
if (not parse_enum_by_number(data->inter_freq_black_cell_list[i].range, "range", root[i])) {
ERROR("Missing field range in black_cell=%d\n", i);
return SRSRAN_ERROR;
}
data->inter_freq_black_cell_list[i].range_present = true;
unsigned int start = 0;
if (!root[i].lookupValue("start", start)) {
ERROR("Missing field start in black_cell=%d\n", i);
return SRSRAN_ERROR;
}
data->inter_freq_black_cell_list[i].start = (uint16)start;
}
return 0;
}
int field_carrier_freq_list_utra_fdd::parse(libconfig::Setting& root)
{
data->carrier_freq_list_utra_fdd.resize((uint32_t)root.getLength());
@ -1378,6 +1528,7 @@ static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cf
parse_opt_field(cell_cfg.phy_cell.rf_port, cellroot, "rf_port");
HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.carrier.pci, cellroot, "pci"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.cell_id, cellroot, "cell_id"));
HANDLEPARSERCODE(parse_opt_field(cell_cfg.coreset0_idx, cellroot, "coreset0_idx"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.prach_root_seq_idx, cellroot, "root_seq_idx"));
HANDLEPARSERCODE(parse_required_field(cell_cfg.tac, cellroot, "tac"));
@ -1999,54 +2150,11 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t*
ERROR("Only 10 MHz bandwidth supported.");
return SRSRAN_ERROR;
}
if (rrc_nr_cfg_->is_standalone) {
if (is_valid_arfcn(cfg.band, cfg.dl_arfcn) == false) {
ERROR("DL-ARFCN %d in band n%d not supported with coreset0 config.", cfg.dl_arfcn, cfg.band);
ERROR("Valid ARFCNs for band n%d are: %s", cfg.band, valid_arfcns_to_string(cfg.band).c_str());
return SRSRAN_ERROR;
}
if (cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD) {
ERROR("Only FDD duplex supported in SA mode.");
return SRSRAN_ERROR;
}
}
}
return SRSRAN_SUCCESS;
}
// List of selected ARFCNs in band n3, n7 and n20 that match the coreset0 config
using arfcn_list_t = std::list<uint32_t>;
std::map<uint32_t, arfcn_list_t> valid_arfcn = {{3, {363500, 368500, 369500, 374500, 375000}},
{7, {525000, 526200, 531000}},
{20, {159000, 160200}}};
std::string valid_arfcns_to_string(uint32_t band)
{
std::string band_string;
if (valid_arfcn.find(band) != valid_arfcn.end()) {
for (const auto& arfcn : valid_arfcn.at(band)) {
band_string += std::to_string(arfcn);
band_string += ", ";
}
}
return band_string;
}
bool is_valid_arfcn(uint32_t band, uint32_t dl_arfcn)
{
if (valid_arfcn.find(band) == valid_arfcn.end()) {
return false;
}
const auto& arfcn_list = valid_arfcn.at(band);
for (const auto& arfcn : arfcn_list) {
if (arfcn == dl_arfcn) {
return true;
}
}
return false;
}
} // namespace enb_conf_sections
namespace sib_sections {
@ -2345,6 +2453,20 @@ int parse_sib4(std::string filename, sib_type4_s* data)
return parser::parse_section(std::move(filename), &sib4);
}
int parse_sib5(std::string filename, sib_type5_s* data)
{
parser::section sib5("sib5");
// interFreqCarrierFreqList
parser::section inter_freq_carrier_freq_list("inter_freq_carrier_freq_list");
sib5.add_subsection(&inter_freq_carrier_freq_list);
bool dummy_bool = false;
inter_freq_carrier_freq_list.set_optional(&dummy_bool);
inter_freq_carrier_freq_list.add_field(new field_inter_freq_carrier_freq_list(data));
return parser::parse_section(std::move(filename), &sib5);
}
int parse_sib6(std::string filename, sib_type6_s* data)
{
parser::section sib6("sib6");
@ -2458,6 +2580,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
sib_type2_s* sib2 = &rrc_cfg_->sibs[1].set_sib2();
sib_type3_s* sib3 = &rrc_cfg_->sibs[2].set_sib3();
sib_type4_s* sib4 = &rrc_cfg_->sibs[3].set_sib4();
sib_type5_s* sib5 = &rrc_cfg_->sibs[4].set_sib5();
sib_type6_s* sib6 = &rrc_cfg_->sibs[5].set_sib6();
sib_type7_s* sib7 = &rrc_cfg_->sibs[6].set_sib7();
sib_type9_s* sib9 = &rrc_cfg_->sibs[8].set_sib9();
@ -2528,6 +2651,13 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co
}
}
// Generate SIB5 if defined in mapping info
if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type5)) {
if (sib_sections::parse_sib5(args_->enb_files.sib_config, sib5) != SRSRAN_SUCCESS) {
return SRSRAN_ERROR;
}
}
// Generate SIB6 if defined in mapping info
if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type6)) {
if (sib_sections::parse_sib6(args_->enb_files.sib_config, sib6) != SRSRAN_SUCCESS) {

View File

@ -63,6 +63,7 @@ int parse_sib1(std::string filename, asn1::rrc::sib_type1_s* data);
int parse_sib2(std::string filename, asn1::rrc::sib_type2_s* data);
int parse_sib3(std::string filename, asn1::rrc::sib_type3_s* data);
int parse_sib4(std::string filename, asn1::rrc::sib_type4_s* data);
int parse_sib5(std::string filename, asn1::rrc::sib_type5_s* data);
int parse_sib6(std::string filename, asn1::rrc::sib_type6_s* data);
int parse_sib7(std::string filename, asn1::rrc::sib_type7_s* data);
int parse_sib9(std::string filename, asn1::rrc::sib_type9_s* data);
@ -150,6 +151,39 @@ private:
asn1::rrc::sib_type4_s* data;
};
class field_inter_freq_carrier_freq_list final : public parser::field_itf
{
public:
explicit field_inter_freq_carrier_freq_list(asn1::rrc::sib_type5_s* data_) { data = data_; }
int parse(Setting& root) override;
const char* get_name() override { return "inter_freq_carrier_freq_list"; }
private:
asn1::rrc::sib_type5_s* data;
};
class field_inter_freq_neigh_cell_list final : public parser::field_itf
{
public:
explicit field_inter_freq_neigh_cell_list(asn1::rrc::inter_freq_carrier_freq_info_s* data_) { data = data_; }
int parse(Setting& root) override;
const char* get_name() override { return "inter_freq_neigh_cell_list"; }
private:
asn1::rrc::inter_freq_carrier_freq_info_s* data;
};
class field_inter_freq_black_cell_list final : public parser::field_itf
{
public:
explicit field_inter_freq_black_cell_list(asn1::rrc::inter_freq_carrier_freq_info_s* data_) { data = data_; }
int parse(Setting& root) override;
const char* get_name() override { return "inter_freq_black_cell_list"; }
private:
asn1::rrc::inter_freq_carrier_freq_info_s* data;
};
class field_carrier_freq_list_utra_fdd final : public parser::field_itf
{
public:

View File

@ -21,11 +21,11 @@
#include <unistd.h>
#include "srsenb/hdr/phy/txrx.h"
#include "srsran/common/band_helper.h"
#include "srsran/common/threads.h"
#include "srsran/srsran.h"
#include "srsenb/hdr/phy/txrx.h"
#define Error(fmt, ...) \
if (SRSRAN_DEBUG_ENABLED) \
logger.error(fmt, ##__VA_ARGS__)
@ -94,6 +94,8 @@ void txrx::run_thread()
float samp_rate = srsran_sampling_freq_hz(worker_com->get_nof_prb(0));
srsran::srsran_band_helper band_helper;
// Configure radio
radio_h->set_rx_srate(samp_rate);
radio_h->set_tx_srate(samp_rate);
@ -103,11 +105,23 @@ void txrx::run_thread()
double tx_freq_hz = worker_com->get_dl_freq_hz(cc_idx);
double rx_freq_hz = worker_com->get_ul_freq_hz(cc_idx);
uint32_t rf_port = worker_com->get_rf_port(cc_idx);
srsran::console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz for cc_idx=%d nof_prb=%d\n",
tx_freq_hz / 1e6f,
rx_freq_hz / 1e6f,
cc_idx,
worker_com->get_nof_prb(cc_idx));
if (cc_idx < worker_com->get_nof_carriers_lte()) {
srsran::console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz for cc_idx=%d nof_prb=%d\n",
tx_freq_hz / 1e6f,
rx_freq_hz / 1e6f,
cc_idx,
worker_com->get_nof_prb(cc_idx));
} else {
srsran::console(
"Setting frequency: DL=%.1f Mhz, DL_SSB=%.2f Mhz (SSB-ARFCN=%d), UL=%.1f MHz for cc_idx=%d nof_prb=%d\n",
tx_freq_hz / 1e6f,
worker_com->get_ssb_freq_hz(cc_idx) / 1e6f,
band_helper.freq_to_nr_arfcn(worker_com->get_ssb_freq_hz(cc_idx)),
rx_freq_hz / 1e6f,
cc_idx,
worker_com->get_nof_prb(cc_idx));
}
radio_h->set_tx_freq(rf_port, tx_freq_hz);
radio_h->set_rx_freq(rf_port, rx_freq_hz);
}

View File

@ -30,6 +30,10 @@ target_link_libraries(erab_setup_test test_helpers ${LIBCONFIGPP_LIBRARIES} ${AT
add_executable(rrc_mobility_test rrc_mobility_test.cc)
target_link_libraries(rrc_mobility_test srsran_asn1 test_helpers ${ATOMIC_LIBS})
add_executable(rrc_paging_test rrc_paging_test.cc)
target_link_libraries(rrc_paging_test srsran_asn1 test_helpers)
add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(rrc_meascfg_test rrc_meascfg_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(rrc_paging_test rrc_paging_test)

View File

@ -0,0 +1,48 @@
/**
*
* \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 "srsenb/hdr/stack/rrc/rrc_paging.h"
#include "srsran/common/test_common.h"
using namespace srsenb;
void test_paging()
{
unsigned paging_cycle = 32;
float nb = 1;
paging_manager pcch_manager{paging_cycle, nb};
unsigned ue_id = 4780;
unsigned mmec = 10;
uint8_t m_tmsi[] = {0x64, 0x04, 0x00, 0x02};
pcch_manager.add_tmsi_paging(ue_id, mmec, m_tmsi);
// \remark: See TS 36.304, section 7.1.
unsigned N = std::min(paging_cycle, (unsigned)std::round(nb * paging_cycle));
unsigned Ns = std::max(1, (int)nb);
unsigned i_s = (ue_id / N) % Ns;
TESTASSERT_EQ(0, i_s);
tti_point t{0};
for (unsigned count = 0; count < 1024 * 10; ++count, ++t) {
if (pcch_manager.pending_pcch_bytes(t) > 0) {
fmt::print("[{}]\n", t);
TESTASSERT_EQ((paging_cycle / N) * (ue_id % N), (t.sfn() % paging_cycle));
TESTASSERT_EQ(9, t.sf_idx()); // PO when i_s == 0.
}
}
}
int main()
{
test_paging();
}

View File

@ -66,6 +66,8 @@ struct bwp_slot_grid {
explicit bwp_slot_grid(const bwp_params_t& bwp_params, uint32_t slot_idx_);
void reset();
void reserve_pdsch(const prb_grant& grant) { pdschs.reserve_prbs(grant); }
bool is_dl() const { return cfg->slots[slot_idx].is_dl; }
bool is_ul() const { return cfg->slots[slot_idx].is_ul; }
};

View File

@ -89,6 +89,7 @@ struct sched_nr_cell_cfg_t {
uint32_t nof_layers;
uint32_t pci;
uint32_t ssb_offset;
uint32_t dl_cell_nof_prb;
uint32_t ul_cell_nof_prb;
asn1::rrc_nr::dl_cfg_common_sib_s dl_cfg_common;

View File

@ -55,6 +55,9 @@ public:
return dl_prbs.prbs();
}
/// Marks a range of PRBS as occupied, preventing further allocations
void reserve_prbs(const prb_grant& grant) { dl_prbs |= grant; }
/// Verifies if the input arguments are valid for an SI allocation and grant doesnt collide with other grants
alloc_result is_si_grant_valid(uint32_t ss_id, const prb_grant& grant) const;

View File

@ -45,6 +45,7 @@ struct rrc_cell_cfg_nr_t {
srsran_duplex_mode_t duplex_mode;
double ssb_freq_hz;
uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn)
uint32_t ssb_offset;
srsran_subcarrier_spacing_t ssb_scs;
srsran_ssb_pattern_t ssb_pattern;
asn1::rrc_nr::pdcch_cfg_common_s pdcch_cfg_common;

View File

@ -36,7 +36,7 @@ void make_mib_cfg(const sched_nr_cell_cfg_t& cfg, srsran_mib_nr_t* mib)
{
*mib = {};
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->ssb_offset = cfg.ssb_offset;
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;
mib->ss0_idx = cfg.pdcch_cfg_sib1.search_space_zero;

View File

@ -105,6 +105,17 @@ void sched_dl_signalling(bwp_slot_allocator& bwp_alloc)
// Schedule SSB
sched_ssb_basic(sl_pdcch, bwp_params.cell_cfg.ssb.periodicity_ms, bwp_params.cell_cfg.mib, sl_grid.dl.phy.ssb);
// Mark SSB region as occupied
if (!sl_grid.dl.phy.ssb.empty()) {
float ssb_offset_hz =
bwp_params.cell_cfg.carrier.ssb_center_freq_hz - bwp_params.cell_cfg.carrier.dl_center_frequency_hz;
int ssb_offset_rb = ceil(ssb_offset_hz / (15000.0f * 12));
int ssb_start_rb = bwp_params.cell_cfg.carrier.nof_prb / 2 + ssb_offset_rb - 10;
uint32_t ssb_len_rb = 20;
assert(ssb_start_rb >= 0 && ssb_start_rb + ssb_len_rb < bwp_params.cell_cfg.carrier.nof_prb);
sl_grid.reserve_pdsch(prb_grant({(uint32_t)ssb_start_rb, ssb_start_rb + ssb_len_rb}));
}
// Schedule NZP-CSI-RS
sched_nzp_csi_rs(bwp_params.cfg.pdsch.nzp_csi_rs_sets, cfg, sl_grid.dl.phy.nzp_csi_rs);
}
@ -159,12 +170,10 @@ void si_sched::run_slot(bwp_slot_allocator& bwp_alloc)
}
} else if (si.win_start + si.win_len_slots >= sl_pdcch) {
// If end of SI message window
if (si.n == 0) {
logger.error("SCHED: Could not allocate SIB1, len=%d. Cause: %s", si.len_bytes, to_string(si.result));
} else {
logger.warning(
"SCHED: Could not allocate SI message idx=%d, len=%d. Cause: %s", si.n, si.len_bytes, to_string(si.result));
}
srsran_always_assert(
si.n == 0, "SCHED: Could not allocate SIB1, len=%d. Cause: %s", si.len_bytes, to_string(si.result));
logger.warning(
"SCHED: Could not allocate SI message idx=%d, len=%d. Cause: %s", si.n, si.len_bytes, to_string(si.result));
si.win_start.clear();
}
}

View File

@ -83,9 +83,15 @@ dl_sched_res_t* cc_worker::run_slot(slot_point tx_sl, ue_map_t& ue_db)
// Log UEs state for slot
log_sched_slot_ues(logger, tx_sl, cfg.cc, slot_ues);
const uint32_t ss_id = 0;
slot_point sl_pdcch = bwp_alloc.get_pdcch_tti();
prb_bitmap prbs_before = bwp_alloc.res_grid()[sl_pdcch].pdschs.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
// Allocate cell DL signalling
sched_dl_signalling(bwp_alloc);
prb_bitmap prbs_after = bwp_alloc.res_grid()[sl_pdcch].pdschs.occupied_prbs(ss_id, srsran_dci_format_nr_1_0);
// Allocate pending SIBs
bwps[0].si.run_slot(bwp_alloc);

View File

@ -80,7 +80,7 @@ inline sched_nr_cell_cfg_t get_default_cell_cfg(const srsran::phy_cfg_nr_t& phy_
// TODO: phy_cfg.ssb_positions_in_burst.group_presence_present
cell_cfg.dmrs_type_a_position.value = asn1::rrc_nr::mib_s::dmrs_type_a_position_opts::pos2;
cell_cfg.ssb_scs.value = (asn1::rrc_nr::subcarrier_spacing_opts::options)phy_cfg.ssb.scs;
cell_cfg.pdcch_cfg_sib1.ctrl_res_set_zero = 6;
cell_cfg.pdcch_cfg_sib1.ctrl_res_set_zero = 0;
cell_cfg.pdcch_cfg_sib1.search_space_zero = 0;
cell_cfg.bwps.resize(1);

View File

@ -1098,7 +1098,7 @@ int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s
default:
srsran_terminate("Invalid carrier SCS=%d Hz", SRSRAN_SUBC_SPACING_NR(cell_cfg.phy_cell.carrier.scs));
}
mib.ssb_subcarrier_offset = 6; // TODO: currently hard-coded
mib.ssb_subcarrier_offset = cell_cfg.ssb_offset;
mib.dmrs_type_a_position.value = mib_s::dmrs_type_a_position_opts::pos2;
mib.pdcch_cfg_sib1.search_space_zero = 0;
mib.pdcch_cfg_sib1.ctrl_res_set_zero = cell_cfg.coreset0_idx;

View File

@ -347,6 +347,7 @@ void rrc_nr::config_mac()
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.ssb_offset = du_cfg->cell(cc).mib.ssb_subcarrier_offset;
if (not cfg.is_standalone) {
const serving_cell_cfg_common_s& serv_cell =
cell_ctxt->master_cell_group->sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common;

View File

@ -124,7 +124,7 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell)
void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell)
{
cell = {};
cell.coreset0_idx = 6;
cell.coreset0_idx = 7;
cell.ssb_absolute_freq_point = 0; // auto derived
cell.num_ra_preambles = 8;
generate_default_nr_phy_cell(cell.phy_cell);
@ -196,7 +196,41 @@ int derive_ssb_params(bool is_sa,
band);
// Convert to frequency for PHY
cell.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point);
cell.ssb_absolute_freq_point = ssb_abs_freq_point;
cell.ssb_freq_hz = band_helper.nr_arfcn_to_freq(ssb_abs_freq_point);
double pointA_abs_freq_Hz = dl_freq_hz - nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(pdcch_scs) / 2;
uint32_t ssb_pointA_freq_offset_Hz =
(cell.ssb_freq_hz > pointA_abs_freq_Hz) ? (uint32_t)(cell.ssb_freq_hz - pointA_abs_freq_Hz) : 0;
cell.ssb_offset = (uint32_t)(ssb_pointA_freq_offset_Hz / SRSRAN_SUBC_SPACING_NR(pdcch_scs)) % SRSRAN_NRE;
// Validate Coreset0 has space
srsran_coreset_t coreset0 = {};
ERROR_IF_NOT(
srsran_coreset_zero(
cell.phy_cell.cell_id, ssb_pointA_freq_offset_Hz, cell.ssb_scs, pdcch_scs, coreset0_idx, &coreset0) == 0,
"Deriving parameters for coreset0: index=%d, ssb_pointA_offset=%d kHz\n",
coreset0_idx,
ssb_pointA_freq_offset_Hz / 1000);
ERROR_IF_NOT(srsran_coreset_start_rb(&coreset0) + srsran_coreset_get_bw(&coreset0) <= cell.phy_cell.carrier.nof_prb,
"Coreset0 index=%d is not compatible with DL ARFCN %d in band %d\n",
coreset0_idx,
cell.dl_arfcn,
cell.band);
// Validate Coreset0 has less than 3 symbols
ERROR_IF_NOT(coreset0.duration < 3,
"Coreset0 index=%d is not supported due to overlap with SSB. Select a coreset0 index from 38.213 Table "
"13-1 such that N_symb_coreset < 3\n",
coreset0_idx);
// Validate Coreset0 has more than 24 RB
ERROR_IF_NOT(srsran_coreset_get_bw(&coreset0) > 24,
"Coreset0 configuration index=%d has only %d RB. A coreset0 index >= 6 is required such as N_rb >= 48\n",
srsran_coreset_get_bw(&coreset0),
coreset0_idx);
return SRSRAN_SUCCESS;
}
@ -255,15 +289,16 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell)
derive_phy_cell_freq_params(cell.dl_arfcn, cell.ul_arfcn, cell.phy_cell);
// Derive SSB params
derive_ssb_params(is_sa,
cell.dl_arfcn,
cell.band,
cell.phy_cell.carrier.scs,
cell.coreset0_idx,
cell.phy_cell.carrier.nof_prb,
cell);
ERROR_IF_NOT(derive_ssb_params(is_sa,
cell.dl_arfcn,
cell.band,
cell.phy_cell.carrier.scs,
cell.coreset0_idx,
cell.phy_cell.carrier.nof_prb,
cell) == 0,
"Deriving SSB parameters\n");
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 (not is_sa) {

View File

@ -120,6 +120,7 @@ int test_rrc_setup()
generate_default_nr_cell(rrc_cfg_nr.cell_list[0]);
rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500;
rrc_cfg_nr.cell_list[0].dl_arfcn = 634240;
rrc_cfg_nr.cell_list[0].coreset0_idx = 3;
rrc_cfg_nr.cell_list[0].band = 78;
rrc_cfg_nr.cell_list[0].phy_cell.carrier.nof_prb = 52;
rrc_cfg_nr.is_standalone = false;

View File

@ -440,11 +440,6 @@ rrc_nr::cell_selection_proc::handle_cell_search_result(const rrc_interface_phy_n
Error("Unsupported SCS %s", srsran_subcarrier_spacing_to_str(mib.scs_common));
return proc_outcome_t::error;
}
// TODO: calculate SSB offset
if (mib.ssb_offset != 6) {
Error("Unsupported SSB offset %d", mib.ssb_offset);
return proc_outcome_t::error;
}
// Logs the PCI, cell measurements and decoded MIB
Info("Cell search found ARFCN=%d PCI=%d %s %s",

View File

@ -175,9 +175,9 @@ imei = 353490069873319
# pass: Password for CHAP authentication
# force_imsi_attach: Whether to always perform an IMSI attach
# eia: List of integrity algorithms included in UE capabilities
# Supported: 1 - Snow3G, 2 - AES
# Supported: 1 - Snow3G, 2 - AES, 3 - ZUC
# eea: List of ciphering algorithms included in UE capabilities
# Supported: 0 - NULL, 1 - Snow3G, 2 - AES
# Supported: 0 - NULL, 1 - Snow3G, 2 - AES, 3 - ZUC
#####################################################################
[nas]
#apn = internetinternet
@ -185,8 +185,8 @@ imei = 353490069873319
#user = srsuser
#pass = srspass
#force_imsi_attach = false
#eia = 1,2
#eea = 0,1,2
#eia = 1,2,3
#eea = 0,1,2,3
#####################################################################
# GW configuration